springcloud二-Sentinel2
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 1. 熔断降级
- 1.1 介绍
- 1.2 状态机
- 1.3 慢调⽤⽐例
- 1.4 降级-捕获异常
- 1.5 降级-FallbackFactory
- 1.6 异常⽐例
- 1.7 异常数
- 2. 授权规则
- 3. 定义异常返回结果
- 4. 规则管理及推送
- 4.1 生产环境使用Sentinel
- 4.2 规则管理持久化模式介绍
- 4.3 规则管理持久化-pull模式实现
- 4.4 规则管理持久化-push模式实现
- 4.5 Sentinel集成Nacos持久化原码改造
- 4.6 集成nacos持久化验证
- 总结
前言
1. 熔断降级
1.1 介绍
除了流量控制以外, 对调⽤链路中不稳定的资源进⾏熔断降级也是保障⾼可⽤的重要措施之⼀.
⼀个服务常常会调⽤别的模块, 可能是另⼀个远程服务, 数据库, 或者第三⽅ API 等. 例如: ⽀付的时候,可能需要远程调⽤银联提供的 API. 查询某个商品的价格, 可能需要进⾏数据库查询
如上图, 当F发⽣了故障不能及时响应, C调⽤F时, 只能阻塞等待, 直到超时. 如果流量⽐较⼤, 每个请求都等到超时才进⾏响应, 那么系统C的线程资源很快就会被耗尽不能对外提供服务了(处理完成后, 才会释放资源).
现代微服务架构都是分布式的, 由⾮常多的服务组成. 不同服务之间相互调⽤, 组成复杂的调⽤链路. 复杂链路上的某⼀环不稳定, 就可能会层层级联, 最终导致整个链路都不可⽤. 因此我们需要对不稳定的弱依赖服务调⽤进⾏熔断, 暂时切断不稳定调⽤, 避免局部不稳定因素导致整体的雪崩.
熔断降级作为保护⾃⾝的⼿段,通常在客⼾端(调⽤端)进⾏配置.
Sentinel 提供了三种熔断策略: 慢调⽤, 异常⽐例, 异常数
核心依赖就是强依赖:必不可少,非核心依赖就是弱依赖:可以不要
熔断是对不稳定的弱依赖进行降级
慢调⽤⽐例 ( SLOW_REQUEST_RATIO ):需要设置允许的慢调⽤ RT(即最⼤的响应时间):100ms, 请求的
响应时间⼤于该值则统计为慢调⽤. 在指定时间内, 如果请求数量 > 设定的最⼩数量, 且慢调⽤⽐例
> 设定的阈值, 则触发熔断
• 异常⽐例 ( ERROR_RATIO ):指定时间内, 请求数量 > 设置的最⼩数量, 且异常⽐例⼤于阈值, 则触发熔断
• 异常数 ( ERROR_COUNT ): 指定时间内, 异常数⽬超过阈值后, 则触发熔断
这样设置意思就是,当1s内,有大于5个请求过来(比如十个),并且有大于10*0.5=5个请求的数量的时间都大于了100ms,那么就熔断,熔断时间为熔断时长
异常比例过大就熔断
1s中之内有多少个异常就熔断
1.2 状态机
熔断的思路是由断路器 (或者叫熔断器) 统计服务调⽤的慢请求⽐例, 异常⽐例等, 如果超过阈值, 则熔断该服务, 也就是拦截对该服务的请求, 当服务恢复时, 断路器会放⾏访问该服务的请求
断路器控制熔断和放⾏是通过状态机来完成的
状态机有三个状态:
• Closed: 关闭状态, 所有请求都会通过断路器, 并开始统计慢请求⽐例, 异常⽐例, 超过阈值则切换到
open状态.
• Open: 打开状态,服务调⽤被熔断. 这时所有访问被熔断服务的请求都会被拒绝.
• Half-open: 半开状态, 当经过⼀段时间后(熔断时长), 断路器会从Open状态切换到Half-open状态, 这时会有⼀定数量的请求被放⼊, 根据这些请求的失败率来判断后续操作.
◦ 失败率低于阈值:切换到closed状态
◦ 失败率超过阈值:切换到open状态
1.3 慢调⽤⽐例
慢调⽤⽐例: 需要设置允许的慢调⽤RT, 也就是最⼤响应时间.
当统计时⻓内请求数⽬ > 设置的最⼩请求数⽬, 并且慢调⽤的⽐例⼤于阈值, 则接下来的熔断时⻓内请求会⾃动被熔断. 经过熔断时⻓后熔断器会进⼊探测恢复状态(HALF-OPEN 状态), 若接下来的⼀个请求响应时间⼩于设置的慢调⽤ RT 则结束熔断, 若⼤于设置的慢调⽤ RT 则会再次被熔断.
先改为一个慢接口,在product-service中,因为我们的order是来调用product的
@RequestMapping("/{productId}")//PathVariable就是获取url里面的值public ProductInfo getProductById(@PathVariable("productId") Integer productId) {log.info("根据商品id查询商品信息"+productId);try {long time = new Random().nextInt(20)+50;Thread.sleep(time);} catch (InterruptedException e) {throw new RuntimeException(e);}return productService.selectProductById(productId);}
这个就会休眠50~70ms了
然后就是定义资源了
@SentinelResource("selectOrderById")public OrderInfo selectOrderById(Integer orderId) {OrderInfo orderInfo = orderMapper.selectOrderById(orderId);ProductInfo productInfo = productApi.getProductInfo(orderInfo.getProductId());orderInfo.setProductInfo(productInfo);return orderInfo;}
然后就可以重启了
10s内这个就表示资源selectOrderById中请求数大于5,超过50ms的比例大于了0.5,就熔断10s,对selectOrderById资源进行熔断,rongduan5s
/sentinel/id调用的selectOrderById,selectOrderById再去调用order-service
我们可以测试的在浏览器上
这个响应时间一定大于50ms的,因为我们配置的就是50~70ms
我们点快一点就变成这样了
过了一会儿,再次点击,因为现在状态机是半开状态
所以会成功一下
然后又点击,又变回来了,因为阈值一直都是大于0.5的
1.4 降级-捕获异常
当调⽤失败后, 业务直接报错, 给⽤⼾体验不太好, 应该返回⽤⼾⼀个友好提⽰或者默认结果, 这个就是降级.
⽐如获取⽤⼾信息时, 照⽚获取失败, 返回⼀个默认的头像.
当商品详情⻚的某些⾮核⼼信息(如⽤⼾评价, 相关推荐)加载失败时, 仍然能够显⽰商品的基本信息,
确保⽤⼾可以完成购买流程.
通常有以下⽅式:
- 捕获异常, 根据异常进⾏降级逻辑处理
- 通过FallbackFactory, 对远程调⽤的异常做处理.
第⼀种⽅式更通⽤, 适合各种场景, 第⼆种⽅式需要远程调⽤的服务进⾏处理. 这两种⽅式在服务开发中经常搭配着使⽤
抛出的异常叫这个名字,java.lang.reflect的UndeclaredThrowableException
@SentinelResource("/sentinel/id")@RequestMapping("/{orderId}")//PathVariable就是获取url里面的值public OrderInfo getOrderById(@PathVariable("orderId") Integer orderId) {try {OrderInfo orderInfo = orderService.selectOrderById(orderId);return orderInfo;}catch (UndeclaredThrowableException e){log.info("获取订单详情失败");return null;}}
这样就可以了,我们这里熔断的是selectOrderById方法
这样就成功了
1.5 降级-FallbackFactory
FallbackFactory 是⼀个在微服务架构中⽤于实现服务降级的接⼝, 当远程服务调⽤失败或超时,
FallbackFactory 会根据提供的异常信息创建⼀个降级处理实例, 以替代原服务调⽤. 并且可以根
据错误类型, 返回不同的降级响应
我们先在product-api 定义降级处理类
public class ProductFallbackFactory implements FallbackFactory<ProductApi> {@Overridepublic ProductApi create(Throwable cause) {return null;}
}
意思就是当ProductApi 调用出现问题的时候,使用这个来进行替代
所以ProductApi 出现了哪些接口,这个也要定义哪些接口
@Slf4j
public class ProductFallbackFactory implements FallbackFactory<ProductApi> {@Overridepublic ProductApi create(Throwable cause) {return new ProductApi() {@Overridepublic ProductInfo getProductInfo(Integer productId) {log.error("获取商品信息失败");return new ProductInfo();}@Overridepublic String p1(Integer id) {log.error("p1请求失败");return "p1请求失败";}@Overridepublic String p2(Integer id, String name) {log.error("p2请求失败");return "p2请求失败";}@Overridepublic String p3(ProductInfo productInfo) {log.error("p3请求失败");return "p3请求失败";}@Overridepublic String p4(ProductInfo productInfo) {log.error("p4请求失败");return "p4请求失败";}};}
}
然后就要给ProductApi 与ProductFallbackFactory 关联起来,这样ProductApi 有问题的话,就会
调用ProductFallbackFactory 的方法了
@FeignClient(name = "product-service",path = "/product",fallbackFactory = ProductFallbackFactory.class)
上面写上这个就可以了
然后我们要把ProductFallbackFactory 交给spring管理
public class DefaultFeignConfiguration {@Beanpublic ProductFallbackFactory productFallbackFactory(){return new ProductFallbackFactory();}
}
在product-api中创建
@EnableFeignClients(clients = {ProductApi.class},defaultConfiguration = DefaultFeignConfiguration.class)
@SpringBootApplication
public class OrderServiceApplication {public static void main(String[] args) {SpringApplication.run(OrderServiceApplication.class, args);}
}
我们这样修改,就是相当于加为bean了
DefaultFeignConfiguration 类中定义的 @Bean(这里是 productFallbackFactory)会成为这些 Feign 客户端的默认配置项
然后在order-service修改配置, 开启 feign 对 Sentinel 功能
开启后,Feign 会与 Sentinel 框架集成,由 Sentinel 负责监控服务调用
feign:sentinel:enabled: true
defaultConfiguration 指定全局默认配置,让 ProductApi 使用 DefaultFeignConfiguration 中的 Bean
我们对GET:http://product-service/product/{productId}进行熔断,记得还要去掉以前写的try,catch
这样product-inifo里面就没有值了
验证限流结果
当触发限流时, 也会执⾏FallbackFactory预设的逻辑
删除熔断配置, 添加限流配置(防⽌⼲扰, 判断不出是触发限流还是熔断).
会发现当限流时, 也会返回预设的降级逻辑.
如果限流了,也是会返回我们这个设计的降级处理的
但是限流的配置也是对GET:http://product-service/product/{productId}进行限流的,如果超过了GET:http://product-service/product/{productId}的阈值,就也会去调用ProductFallbackFactory
1.6 异常⽐例
先模拟异常
@RequestMapping("/{productId}")//PathVariable就是获取url里面的值public ProductInfo getProductById(@PathVariable("productId") Integer productId) throws InterruptedException {log.info("根据商品id查询商品信息"+productId);if(productId==1001){Thread.sleep(60);return productService.selectProductById(productId);}else if(productId==1002){throw new RuntimeException("发送异常");}else{return productService.selectProductById(productId);}}
我们1001就慢调用,1002就抛出异常
未触发熔断
快速多次请求: http://127.0.0.1:8080/order/1, (对应产品ID 1001)⼀直不会熔断,因为我们去掉了慢调用熔断
⼀次请求: http://127.0.0.1:8080/order/2, (对应产品ID 1002), 出现异常, ⾛降级逻辑.
再请求 http://127.0.0.1:8080/order/1, 正常返回,因为异常比例少
触发熔断
快速多次请求 http://127.0.0.1:8080/order/2, 出现异常, ⾛降级逻辑.,异常⽐例达到阈值, 触发熔断.还是会走降级逻辑,我们看不出来效果
再请求 http://127.0.0.1:8080/order/1, 已经熔断了–》抛出异常,⾛降级逻辑
1.7 异常数
异常数 ( ERROR_COUNT ):统计单位时⻓内的异常数⽬, 超过阈值之后, 触发熔断. 经过熔断时⻓后熔断器会进⼊探测恢复状态(HALF-OPEN 状态),若接下来的⼀个请求成功完成(没有错误)则结束熔断,否则会再次被熔断.
异常数和异常⽐例⽐较相似
熔断规则配置如下:
统计最近10000ms内的请求, 如果请求量超过5次,并且异常数⼤于, 则触发熔断
触发熔断
快速多次请求 http://127.0.0.1:8080/order/2, 出现异常, ⾛降级逻辑.,异常⽐例达到阈值, 触发熔断.还是会走降级逻辑,我们看不出来效果
再请求 http://127.0.0.1:8080/order/1, 已经熔断了–》抛出异常,⾛降级逻辑
2. 授权规则
存在问题:
⽬前订单项⽬, 直接就可以通过浏览器访问, 获取订单的信息, 这样很不安全.
解决⽅案:
微服务架构中, 许多系统包含敏感信息, 如个⼈⾝份信息, 财务数据, 商业机密等. 只有经过验证或者授权的⽤⼾才可以访问这些数据. ⽐如在医疗系统中, 只有授权的医⽣和护⼠可以查看患者的病历.
授权规则是对请求者的⾝份进⾏判断, 决定是否允许该请求访问特定资源
Sentinel提供了两种授权模式:⽩名单和⿊名单
• ⽩名单:请求来源位于⽩名单内的调⽤者才允许访问.
• ⿊名单:请求来源位于⿊名单内的调⽤者不允许访问,其余请求通过
Sentinel根据来源来进⾏判断, 所以调⽤⽅需要设置来源, 被调⽤⽅需要获取来源
Sentinel进⾏授权管理, 主要分以下⼏步
- 服务端(被调⽤⽅)获取来源
- 客⼾端(调⽤⽅)设置来源
- 配置授权规则, 即⿊⽩名单
服务端(被调⽤⽅)获取来源:来源放在header中,客户端放的来源
服务端也就是order-service项⽬.
Sentinel是通过 RequestOriginParser 这个接⼝的 parseOrigin 来获取请求的来源的.
在服务端中实现RequestOriginParser这个接⼝即可
定义请求来源放在Header中, key为origin(⾃定义)
假设客户端我们把key设置为origin
@Component
public class HeaderOriginParser implements RequestOriginParser {@Overridepublic String parseOrigin(HttpServletRequest httpServletRequest) {String origin = httpServletRequest.getHeader("origin");if(!StringUtils.hasLength(origin)){return "default";}return origin;}
}
我们设置了这个方法,那么sentinel就会去从parseOrigin方法中获得来源
然后网关服务可以设置来源
spring:cloud:gateway:default-filters:- AddRequestHeader=origin,gateway
这个就是给网关的每个请求都添加上key为origin,value为gateway的header
最后就是配置授权规则了
因为网关要访问这个,所以给这个添加白名单,意思就是访问/order/{orderId}接口,白名单要为gateway才可以访问接口,意思就是parseOrigin要返回gateway才可以
我们直接访问发现是不行的,因为已经被限制住了,因为没有配置header的
得通过网关才可以
发现通过网关就可以了
也可以通过apifox添加header
3. 定义异常返回结果
这个返回结果不是很友好, ⽽且调⽤⽅分辨不出来异常原因
Sentinel提供了⼀个接⼝ BlockExceptionHandler , ⽤于⾃定义处理 BlockException 异常.
当请求被 Sentinel 限流、降级或授权拒绝时, 会抛出 BlockException . 通过实现
BlockExceptionHandler 接⼝, 可以定义统⼀的异常处理逻辑, 返回更友好的错误信息或执⾏特
定的降级操作.
Sentinel 默认提供了⼀个 DefaultBlockExceptionHandler 实现类, 当请求被阻塞时, 会返回⼀
个简单的字符串提⽰"Blocked by Sentinel (flow limiting)"(不同版本可能会不⼀样)
所以返回的都是Blocked by Sentinel (flow limiting)这句话
@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {@Overridepublic void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {}
}
然后BlockException有很多的子类,比如限流的,授权的,等等,根据不同子类返回不同东西
然后我们模仿默认的handler来处理就可以了
@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {@Overridepublic void handle(HttpServletRequest httpServletRequest, HttpServletResponse response, BlockException e) throws Exception {response.setContentType("text/html;charset=utf-8");//万一返回中文呢int status = 429;String msg = "Blocked by Sentinel (flow limiting)";if(e instanceof AuthorityException){status = 401;msg = "授权失败";} else if (e instanceof DegradeException) {msg = "熔断降级";} else if (e instanceof FlowException) {msg =" 限流";} else if (e instanceof ParamFlowException) {msg = "热点限流";}response.setStatus(status);PrintWriter out = response.getWriter();out.print(msg);out.flush();out.close();}
}
因为我们自定义异常是在ordder中的,所以熔断的配置也要在order中,不然对product熔断了,就是product抛出异常,捕获不到的
热点限流的话,不能对自带的springmvc进行限制,必须是我们自定义的
这个是因为版本问题,我用的版本比较低,最新的版本应该是可以实现效果的
4. 规则管理及推送
4.1 生产环境使用Sentinel
前⾯的学习中, 我们也发现了⼀个问题, 就是服务重启后, 我们之前设定的规则就会消失. 这是因为
Sentinel 默认是将这些管理规则保存在内存中, 在⽣产环境中, 这个问题是不可接受的. 规则的丢失会导致系统失去流量控制和保护机制.
⽣产环境中, Sentinel需要规则持久化, sentinel-core 提供 API 和扩展接⼝来接收信息. 开发者需
要根据⾃⼰的环境, 选取⼀个可靠的推送规则⽅式. 同时, 规则最好在控制台中集中管理.
为什么会丢失呢,配置的东西,因为默认是把配置保存到内存里面的
在生产环境中使用-Sentinel
第一是Sentinel的配置不能持久化
第二实时实时监控那里不能持久化,只能保存五分钟,我们这里的
第三就是只有有权限的人员才可以去修改配置
监控的持久化—》要可视化的界面,要改造sentinel原码–》了解
4.2 规则管理持久化模式介绍
现在用的就是原始模式
pull 模式的数据源(如本地⽂件、RDBMS (数据库)等)⼀般是可写⼊的. 使⽤时需要在客⼾端(后端代码配置文件)注册数据源:将对应的读数据源注册⾄对应的 RuleManager,将写数据源注册⾄ transport 的WritableDataSourceRegistry 中
一个文件可读可写,先从这个文件读取数据,然后把读的数据注册到RuleManager,然后是写数据
4.3 规则管理持久化-pull模式实现
TypeReference引入的是alibaba的fastjson,这个在sentinel里面已经引入了
System.getProperty(“user.home”)这个会拿到我的用户路径C:\Users\zjdsx
- 注册数据源
public class FileDataSourceInit implements InitFunc {@Overridepublic void init() throws Exception {String ruleDir = System.getProperty("user.home") + "/sentinel/rules/orderService";String flowRulePath = ruleDir + "/flow-rule.json";//文件路径mkdirIfNotExist(ruleDir);//创建路径createFileIfNotExist(flowRulePath);//创建文件
// 注册⼀个可读数据源,⽤来定时读取本地的json⽂件,更新到规则缓存中
// 流控规则ReadableDataSource<String, List<FlowRule>> ds = new FileRefreshableDataSource<>(flowRulePath, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));//读取文件,把规则注册到FlowRuleManager
// 将可读数据源注册⾄FlowRuleManager
// 这样当规则⽂件发⽣变化时,就会更新规则到内存FlowRuleManager.register2Property(ds.getProperty());WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>(flowRulePath,this::encodeJson);
// 将可写数据源注册⾄transport模块的WritableDataSourceRegistry中
// 这样收到控制台推送的规则时,Sentinel会先更新到内存,然后将规则写⼊到⽂件中WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);}private <T> String encodeJson(T t) {return JSON.toJSONString(t);}private void mkdirIfNotExist(String filePath) throws IOException {File file = new File(filePath);if (!file.exists()) {file.mkdirs();//创建多重路径,mkdir是创建单重路径}}private void createFileIfNotExist(String filePath) throws IOException {File file = new File(filePath);if (!file.exists()) {file.createNewFile();}}
}
-
在resources下创建META-INF/services⽬录,并创建⽂件:
com.alibaba.csp.sentinel.init.InitFunc, 写本地数据源的路径
添加com.ck.order.sentinel.FileDataSourceInit
-
重启服务, 设置流控, 会发现流控规则同步到指定的⽂件中
这样就成功了
我们重启服务,再次请求,发现配置还在,如果不重新请求,还是看不见我们以前的设置的,重新请求才会有,,,,—》不是实时
4.4 规则管理持久化-push模式实现
⽣产环境下⼀般更常⽤的是 push 模式的数据源. 对于 push 模式的数据源,如远程配置中⼼
(ZooKeeper, Nacos, Apollo等等),推送的操作不应由 Sentinel 客⼾端进⾏,⽽应该经控制台统⼀
进⾏管理,直接进⾏推送,数据源仅负责获取配置中⼼推送的配置并更新到本地。因此推送规则正确做法应该是 配置中⼼控制台/Sentinel 控制台 → 配置中⼼ → Sentinel 数据源 → Sentinel,⽽不是
经 Sentinel 数据源推送⾄配置中⼼。这样的流程就⾮常清晰了:
动态规则扩展
我们推荐通过控制台设置规则后将规则推送到统一的规则中心,客户端实现 ReadableDataSource 接口端监听规则中心实时获取变更
就是sentinel配置了,同步到nacos,然后同步到后端的ruleManager
<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId><version>1.8.6</version>
</dependency>
然后就是配置数据源了,原来是给文件胚子,这次就给nacos配置了
public class NacosDatasourceInit implements InitFunc {@Overridepublic void init() throws Exception {final String remoteAddress = "localhost:8848";final String groupId = "SENTINEL_GROUP";final String dataId = "sentinel-order-service-flow-rule";ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(remoteAddress, groupId, dataId,source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));FlowRuleManager.register2Property(flowRuleDataSource.getProperty());}
}
groupId和dataId在这里
最后配置这个
然后我们在对应的环境里面进行配置,注意groupId和dataId
json就是复制的原来文件里面的配置
[{"clusterConfig": {"acquireRefuseStrategy": 0,"clientOfflineTime": 2000,"fallbackToLocalWhenFail": true,"resourceTimeout": 2000,"resourceTimeoutStrategy": 0,"sampleCount": 10,"strategy": 0,"thresholdType": 0,"windowIntervalMs": 1000},"clusterMode": false,"controlBehavior": 0,"count": 10.0,"grade": 1,"limitApp": "default","maxQueueingTimeMs": 500,"resource": "/order/{orderId}","strategy": 0,"warmUpPeriodSec": 10
}]
这个配置中clusterConfig是集群的配置,我们可以删掉
[{"clusterMode": false,"controlBehavior": 0,"count": 10.0,"grade": 1,"limitApp": "default","maxQueueingTimeMs": 500,"resource": "/order/{orderId}","strategy": 0,"warmUpPeriodSec": 10
}]
注意我们配置的NacosDatasourceInit ,默认是在public命名空间下的
public class NacosDatasourceInit implements InitFunc {@Overridepublic void init() throws Exception {final String remoteAddress = "localhost:8848";final String groupId = "SENTINEL_GROUP";final String dataId = "sentinel-order-service-flow-rule";// 命名空间ID(注意是命名空间的ID而不是名称)final String namespace = "618c9fc5-87b2-4129-8d7e-37fd867c66f7";// 创建Nacos配置属性对象Properties properties = new Properties();properties.put(PropertyKeyConst.SERVER_ADDR, remoteAddress);properties.put(PropertyKeyConst.NAMESPACE, namespace);// 使用带Properties参数的构造函数ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(properties, groupId, dataId,source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));FlowRuleManager.register2Property(flowRuleDataSource.getProperty());}
}
我们改一下NacosDatasourceInit
这样就成功了
Properties就是来自于java.util
这个count就是阈值,我们nacos进行修改,sentinel那边也会修改的
但是我们sentinel修改了,nacos不会修改,意思是只会nacos同步到sentinel,sentinel不能同步到nacos
4.5 Sentinel集成Nacos持久化原码改造
- 下载Sentinel源码
下载地址: https://github.com/alibaba/Sentinel/releases
我们直接用idea用项目的方式打开这个文件夹
- 修改pom⽂件
打开这个
<!-- for Nacos rule publisher sample --><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId><scope>test</scope></dependency>
找到这个
去掉
<scope>test</scope>
变为
<!-- for Nacos rule publisher sample --><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId></dependency>
为什么删掉呢,因为这个表示的是sentinel-datasource-nacos只在测试用例test里面生效,删掉之后就可以在main原码里面生效了
然后这里有maven冲突,可以去包
3. 添加Nacos⽀持
直接复制nacos文件夹
粘贴到这里
- 修改Nacos配置
修改NacosConfig
@Beanpublic ConfigService nacosConfigService() throws Exception {return ConfigFactory.createConfigService("localhost:8848");}
- 配置Nacos数据源
开启 Controller 层操作 Nacos 的开关
代码位于:
com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControll
@Autowired@Qualifier("flowRuleNacosProvider")private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;@Autowired@Qualifier("flowRuleNacosPublisher")private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
这两个修改为我们刚刚粘贴进来的东西
- 修改前端⻚⾯
前端共3处修改
修改
src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.html
<li ui-sref-active="active" ng-if="entry.appType==0"><a ui-sref="dashboard.flow({app: entry.app})"><i class="glyphicon glyphicon-filter"></i> 流控规则 V1</a></li>
打开这个的注释
修改 src/main/webapp/resources/app/scripts/controllers/identity.js
⼤概第4⾏左右, 修改 FlowServiceV1 -> FlowServiceV2
还是在这个文件搜索"/dashboard/flow/", ⼤概98⾏左右
修改 /dashboard/flow/ -> /dashboard/v2/flow/
- 重新打包, 启动
上⾯的操作完成之后, 重新编译打包, 需要跳过单元测试
只打dashboard的包
4.6 集成nacos持久化验证
[INFO] Building jar: D:\spring-project2\spring-cloud-sentinel- demo2\Sentinel-1.8.8\sentinel-dashboard\target\sentinel-dashboard.jar
找到它
复制到这里,然后改个名字
java -jar -Dserver.port=8100 -Dsentinel.dashboard.auth.username=admin -Dsentinel.dashboard.auth.password=admin sentinel-dashboard-nacos.jar
然后我们启动sentinel-dashboard-nacos.jar,这个我们新搞得sentinel-dashboard
注意我们以前修改了前端页面,增肌了一个流控规则v1,所以要刷新缓存
这里删除浏览数据
只删除缓存的图片和文件
这样就成功了,看到了流控规则v1
我们直接干掉这个,因为这个已经和4.4没有关系了
这个也删掉
然后
配置Nacos
修改order-service 服务, 让其监听Nacos的规则配置
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
spring:cloud:sentinel:datasource:flow-rules: #流控规则nacos:server-addr: ${spring.cloud.nacos.discovery.server-addr}dataId: ${spring.application.name}-flow-rules## namespace: 618c9fc5-87b2-4129-8d7e-37fd867c66f7groupId: SENTINEL_GROUPrule-type: flow
这个配置的就是第一就是nacos地址server-addr,还有dataId,groupId
然后就可以重启了
注意低版本可能不能用namespace,这里没有实践过
我们添加流控成功以后,就跳转到了http://127.0.0.1:8100/#/dashboard/v2/flow/order-service
其中含有v2
也是我们修改的前端页面
/v2/flow/对应的就是流控规则v1
流控规则v1和流控规则都含有这些配置,
我们看到这里自动生成了一个配置
我们把34改为100
这样就成功了
我们在sentinel把100修改为99
必须在流控规则v1修改才行
我们这个意思就是新创建了一个流控规则v1,默认的流控规则没有改动它(不管它了),流控规则v1与nacos进行了绑定,数据是同步的
nacos修改了—》流控规则v1和流控规则都变
流控规则v1改–》流控规则和nacos变
流控规则变–》流控规则v1和nacos不变
我们可以去前端页面注释掉流控规则,让它不显示