一、Sentinel的引入
在我们日常生活中,经常会在淘宝、天猫、京东、拼多多等平台上参与商品的秒杀、抢购以及一些优惠活动,也会在节假日使用12306 手机APP抢火车票、高铁票,甚至有时候还要帮助同事、朋友为他们家小孩拉投票、刷票,这些场景都无一例外的会引起服务器流量的暴涨,导致网页无法显示、APP反应慢、功能无法正常运转,甚至会引起整个网站的崩溃。
Sentinel为了解决上述这些问题,由此应运而生。它通过为秒杀、抢购、抢票、拉票等功能提供API接口层面的流量限制,让突然暴涨而来的用户访问受到统一的管控,使用合理的流量放行规则使得用户都能正常得到服务。
另外,在微服务项目中,经常存在服务A调用服务B,服务B又调用服务C等微服务级联调用的场景,当服务C出现故障,服务B和服务A都会跟着出现故障,因为它们之间存在调用链关系;有时候调用链会很长并且很复杂,比如服务A不仅调用了服务B,还调用了服务H、服务I、服务J等等,同时服务A调用链的最长链条终端有可能是从服务C、服务D一直到服务Z,这种调用复杂的调用链条一旦出现故障,有可能直接让整个微服务体系都无法提供服务,造成的影响是致命的。这种由于调用链中某一个节点出现故障而引发的级联故障,称为应用雪崩,也称为级联故障、级联失效(Cascading Failure)。
Sentinel的出现,正好可以解决这种雪崩效应引发的一系列问题
二、什么是雪崩效应
①:正常情况下,微服务A B C D 都是正常的
②:随着时间推移,在某一个时间点 微服务A突然挂了, 此时的微服务B 还在疯狂的调用微服务A,由于 A已经挂了,所以B调用A必须等待服务调用超时。而我们知道每次B->A的时候B都会去创建线程(而 线程由是计算机的资源 比如cpu 内存等)。由于是高并发场景B就会阻塞大量的线程。那么B所在的机器就会去创建线程,但是计算机资源是有限的,最后B的服务器就会宕机。(说白了微服务B 活生生 的被猪队友微服务A给拖死的)
③: 由于微服务A这个猪队友活生生的把微服务B给拖死,导致微服务B也宕机了,然后也会导致微服务 C D 出现类是的情况,最终我们的猪队友A成功的把微服务 B C D 都拖死了。
这种情况就叫做服务雪崩。也有一个专业术语(cascading failures) 级联故障
下面有3种方法解决这个问题
1、超时机制:配置一下超时时间,例如1秒——每次请求在1秒内必须返回,否则到点 就把线程掐死,释放资源! 思路:一旦超时,就释放资源。由于释放资源速度较快,应用就不会那么容易被拖死
@Configuration
public class WebConfig {
@Bean
public RestTemplate restTemplate() {
//设置restTemplate的超时时间
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setReadTimeout(1000);
requestFactory.setConnectTimeout(1000);
RestTemplate restTemplate = new RestTemplate(requestFactory);
return restTemplate;
}
}
@ControllerAdvice
public class TulingExceptionHandler {
@ExceptionHandler(value = {RuntimeException.class})
@ResponseBody
public Object dealBizException() {
OrderVo orderVo = new OrderVo();
orderVo.setOrderNo("-1");
orderVo.setUserName("容错用户");
return orderVo;
}
}
2、舱壁隔离模式:一般来说,现代的轮船都会分很多舱室,舱室之间用钢板焊 死,彼此隔离。这样即使有某个/某些船舱进水,也不会影响其他舱室,浮力够,船不会沉。
举个例子:M类调用B服务,N类调用C服务,如果M类和N类使用相同的线程池,那么如果B服务挂了,M类调用B服务的接口并发又很高,你又没有任何保护措施,你的服务就很可能被M类拖死。
而如果M类有自己的线程池,N类也有自己的线程池,如果B服务挂了,M类顶多是将自己的线程池占满,不会影响N类的线程池——于是N类依然能正常工作
3、断路器模式:现实世界的断路器大家肯定都很了解,每个人家里都会有断路器。断路器实时监控电路的情况,如果 发现电路电流异常,就会跳闸,从而防止电路被烧毁。
软件世界的断路器可以这样理解:实时监测应用,如果发现在一定时间内失败次数/失败率达到一定阈值,就“跳闸”,断路器打开——此时,请求直接返回,而不去调用原本调用的逻辑。 跳闸一段时间后(例如15秒),断路器会进入半开状态,这是一个瞬间态,此时允许一次请求调用该 调的逻辑,如果成功,则断路器关闭,应用正常调用;如果调用依然不成功,断路器继续回到打开状 态,过段时间再进入半开状态尝试——通过”跳闸“,应用可以保护自己,而且避免浪费资源;而通过半开的设计,可实现应用的“自我修复“。
而上述功能,Sentinel都拥有
Sentinel 是面向分布式服务架构的轻量级流量控制产品,主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来帮助您保护服务的稳定性。
三、Sentinel初体验
Sentinel有好几个版本的使用方法。
3.1 V1版本
①:添加依赖包
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.7.1</version>
</dependency>
②:编写测试 controller
@RestController
@RequestMapping("order1")
public class OrderController1 {
/*** 初始化流控规则*/
@PostConstruct
public void init() {
List<FlowRule> flowRules = new ArrayList<>();
//创建流控规则对象
FlowRule flowRule = new FlowRule();
//设置流控规则 QPS
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 设置受保护的资源
flowRule.setResource("helloSentinelV1");
// 设置受保护的资源的阈值,一秒/个
flowRule.setCount(1);
flowRules.add(flowRule);
//加载配置好的规则
FlowRuleManager.loadRules(flowRules);
}
/**
* 频繁请求接口 http://localhost:8080/helloSentinelV1
* 这种做法的缺点:
* )业务侵入性很大,需要在你的controoler中写入 非业务代码..
* 2)配置不灵活 若需要添加新的受保护资源 需要手动添加 init方法来添加流控规则
* @return
*/
@RequestMapping("/helloSentinelV1")
public String testHelloSentinelV1() {
Entry entity =null;
//关联受保护的资源
try {
entity = SphU.entry("helloSentinelV1");
// 开始执行 自己的业务方法
System.out.println("执行自己的任务");
// 结束执行自己的业务方法
} catch (BlockException e) {
return "testHelloSentinelV1方法被流控了";
}finally {
if(entity!=null) {
entity.exit();
}
}
return "OK";
}
}
v1版本的缺陷:如下业务侵入性很大,需要在你的controoler中写入 非业务代码. 配置不灵活 若需要添加新的受保护资源 需要手动添加 init方法来添加流控规则
3.2 V2版本
①:V2版本: 基于v1版本 再添加一个依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.7.1</version>
</dependency>
②:编写测试 controller
@Configuration
public class SentinelConfig {
@Bean
public SentinelResourceAspect sentinelResourceAspect(){
return new SentinelResourceAspect();
}
}
@RestController
@RequestMapping("order1")
public class OrderController1 {
/*** 初始化流控规则*/
@PostConstruct
public void init() {
List<FlowRule> flowRules = new ArrayList<>();
//创建流控规则对象
FlowRule flowRule = new FlowRule();
//设置流控规则 QPS
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 设置受保护的资源
flowRule.setResource("helloSentinelV2");
// 设置受保护的资源的阈值,一秒/个
flowRule.setCount(1);
flowRules.add(flowRule);
//加载配置好的规则
FlowRuleManager.loadRules(flowRules);
}
@RequestMapping("/helloSentinelV2")
@SentinelResource(value = "helloSentinelV2",blockHandler ="testHelloSentinelV2BlockMethod")
public String testHelloSentinelV2() {
System.out.println("执行自己的任务");
return "OK";
}
public String testHelloSentinelV2BlockMethod(BlockException e) {
return "testHelloSentinelV2方法被流控了...."+e;
}
}
优点: 需要配置aspectj的切面SentinelResourceAspect ,添加注解@SentinelResource ,解决了v1版本中 sentinel的业务侵入代码问题,通过blockHandler指定被流控后调用的方法.
缺点: 若我们的controller中的方法逐步变多,那么受保护的方法也越来越多,会导致一个问题 blockHandler的方法也会越来越多引起方法急剧膨胀。
注意点: blockHandler 对应处理 BlockException 的函数名称, 可选项。blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数, 类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中
3.3 V3版本
V3:版本 基于V2缺点改进
@Configuration
public class SentinelConfig {
@Bean
public SentinelResourceAspect sentinelResourceAspect(){
return new SentinelResourceAspect();
}
}
public class BlockUtils {
public static String testHelloSentinelV2BlockMethod(BlockException e) {
return "testHelloSentinelV2方法被流控了...."+e;
}
}
@RestController
@RequestMapping("order1")
public class OrderController1 {
/*** 初始化流控规则*/
@PostConstruct
public void init() {
List<FlowRule> flowRules = new ArrayList<>();
//创建流控规则对象
FlowRule flowRule = new FlowRule();
//设置流控规则 QPS
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 设置受保护的资源
flowRule.setResource("helloSentinelV2");
// 设置受保护的资源的阈值,一秒/个
flowRule.setCount(1);
flowRules.add(flowRule);
//加载配置好的规则
FlowRuleManager.loadRules(flowRules);
}
@RequestMapping("/helloSentinelV2")
@SentinelResource(value = "helloSentinelV2",blockHandler ="testHelloSentinelV2BlockMethod",blockHandlerClass = BlockUtils.class)
public String testHelloSentinelV2() {
System.out.println("执行自己的任务");
return "OK";
}
}
缺点: 不能动态的添加规则
四、Sentinel和Spring的整合
<!--加入sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--加入actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
添加Sentinel后,会暴露/actuator/sentinel端点http://localhost:8080/actuator/sentinel
但是注意:Springboot默认是没有暴露该端点的,所以我们需要自己设置
server:
port: 8080
management:
endpoints:
web:
exposure:
include: '*'
如果我们想动态的配置Sentinel的流控规则,那么我们需要整合Sentinel-dashboard(哨兵流量卫兵)
下载地址:https://github.com/alibaba/Sentinel/releases,本文下载的是1.6.3版本的
第一步:执行 java -jar sentinel-dashboard-1.6.3.jar --server.port=9999
启动(就是一个Springboot工程)默认端口是8080
第二步: 访问我们的sentinel控制台(1.6版本加入登陆页面) http://192.168.93.224:9999/ 默认账号密码 sentinel/sentinel
第三步:我们的微服务order-server 也整合好了sentinel,我们也搭建 好了Sentinel控制台了,临门一脚 为微服务添加sentinel的控制台地址
spring:
application:
name: order-service #服务名是必须设置的,否则nacos发现不了这个服务
cloud:
sentinel:
transport:
dashboard: 192.168.93.224:9999
五、sentinel监控性能指标详解
4.1 实时监控面板
在这个面板中我们监控我们接口的通过的QPS和拒绝的QPS 在没有设置流控规则 我们是看不到拒绝的QPS
设置流控规则为2的时候的监控图
4.2 流控规则
用来显示微服务的所监控的API
簇点链路 选择具体的访问的API 然后点击流控按钮
资源名称::为我们接口的API /order/getOrder
针对来源::这里是默认的default(标示不针对来源),还有一种情况就是 假设微服务A需要调用这个资源,微服务B也需要调用这个资源,那么我们就可以单独的为 微服务A和微服务B进行设置阈值。
阈值类型: 分为QPS和线程数 假设阈值为2
QPS类型:只得是每秒钟访问接口的次数>2就进行限流
线程数:为接受请求该资源 分配的线程数>2就进行限流.
流控模式:
①:直接:这种很好理解,就是达到设置的阈值后直接被流控抛出异常
②:关联,业务场景 我们现在有二个api,第一个是保存订单,一个是查询订单,假设我们希望优先操作是"保存订单"
其意思是当/saveOrder接口访问的QPS达到阀值后,限制接口/findById/1的调用
③:链路模式:只针对从指定链路访问到本资源的请求做统计,判断是否超过阈值
例如有两条请求链路:
/test1 /common
/test2 /common
如果只希望统计从/test2进入到/common的请求,对/test2 进行限流,则可以这样配置
流控效果
①:快速失败(直接抛出异常) ,例如:每秒的QPS 操过1 就直接抛出异常 设置如下
②:Warm Up, 当流量突然增大的时候,我们常常会希望系统从空闲状态到繁忙状态的切换的时间长一些。即如果系统在此之前长期处于空闲的状态,我们希望处理请求的数量是缓步的增多,经过预期的时间以后,到 达系统处理请求个数的最大值。Warm Up(冷启动,预热)模式就是为了实现这个目的的。 冷加载因子: codeFactor 默认是3 默认 coldFactor 为 3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值。
上图设置: 就是QPS从100/3=33开始算 经过10秒钟,到达一百的QPS 才进行限制流量
③:排队等待,这种方式适合用于请求以突刺状来到,这个时候我们不希望一下子把所有的请求都通过,这样可能会 把系统压垮;同时我们也期待系统以稳定的速度,逐步处理这些请求,以起到“削峰填谷”的效果, 而不是拒绝所有请求。 选择排队等待的阈值类型必须是QPS
单机阈值:10表示 每秒通过的请求个数是10,那么每隔100ms通过一次请求. 每次请求的最大等待时间为20000=20s,超过20S就丢弃请求。
4.3 降级规则
①:RT(平局响应时间, Sentinel 默认统计的 RT 上限是 4900 ms,超出此阈值的都会算作 4900 ms,若需要变更此上限可以通过启动配置项 -Dcsp.sentinel.statistic.max.rt=xxx 来配置
时间窗口(以 s 为单位)
上图配置的意思就是,如果/order/getOrder这个接口响应时间超过1秒,就会降级,那么在接下的5秒之内,调用这个方法的都会自动地熔断抛出 DegradeException,5秒后恢复正常
②:异常比例
上图意思是,当资源的每秒请求量 >= 5,并且每秒异常总数占通过量的比值超过阈值0.5 之后,资源进入降级状态,即在接下的时间窗口10秒之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
③:异常数
上图意思是,在1分钟内,如果接口异常数目超过100之后就会进行熔断。又因为由于统计时间窗口是分钟级别的,而我们设置的时间窗口是10秒,其小于60秒,所以60秒后才会结束熔断状态。当然了如果我们设置的时间窗口是70秒,那么70秒后才会结束熔断状态.
4.4 热点规则
业务场景: 秒杀业务,比如商城做促销秒杀,针对苹果11(商品id=5)进行9.9秒杀活动,那么这个时候,我们去请 求订单接口(商品id=5)的请求流量十分大,我们就可以通过热点参数规则来控制 商品id=5的请求的并发量。而其他正常商品的请求不会收到限制。那么这种热点参数规则很使用。
六、Sentinel-dashboard控制台和微服务通信原理
我们通过观察到sentinel-dashboard的机器列表上观察注册服务微服务信息。我们的 控制台就可以通过这些微服务的注册信息跟我们的具体的微服务进行通信.
如果我们要对SpringMvc端点保护关闭(一般应用场景是做压测需要关闭 )
spring:
application:
name: store-service #服务名是必须设置的,否则nacos发现不了这个服务
cloud:
sentinel:
transport:
dashboard: 192.168.93.224:9999
filter:
enabled: false #关闭Spring mvc的端点保护
那么我们的这种类型的接口 不会被sentinel保护
@RestController
@RequestMapping("store")
public class StoreController {
@GetMapping("getInfo")
public JsonResult getStore(){
return JsonResultHelper.JsonResultSuccess();
}
只有加了@SentinelResource的注解的资源才会被保护
@RestController
@RequestMapping("store")
public class StoreController {
@SentinelResource("store/getInfo")
@GetMapping("getInfo")
public JsonResult getStore(){
return JsonResultHelper.JsonResultSuccess();
}
七、Ribbon整整合Sentinel
第一步: 加配置
<!--加入ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<!--加入sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--加入actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
第二步:加注解@SentinelRestTemplate
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SentinelRestTemplate {
//限流策略(限流方法类的方法名,方法必须是静态的,且返回值必须是SentinelClientHttpResponse)
String blockHandler() default "";
Class<?> blockHandlerClass() default void.class;//限流方法类
//熔断降级策略(熔断降级类的方法名,方法必须是静态的,且返回值必须是SentinelClientHttpResponse)
String fallback() default "";
Class<?> fallbackClass() default void.class;//熔断降级类
}
在我们的RestTemplate组件上添加 @SentinelRestTemplate注解,并且我们可以通过在@SentinelRestTemplate 同样的可以指定我们的 blockHandlerClass,fallbackClass,blockHandler和fallback 这四个属性
@Configuration
public class WebConfig {
@Bean
@LoadBalanced
@SentinelRestTemplate(
blockHandler = "handleException",blockHandlerClass = GlobalExceptionHandler.class,
fallback = "fallback",fallbackClass = GlobalExceptionHandler.class
)
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
public class GlobalExceptionHandler {
/**
* 限流后处理方法
* @param request
* @param body
* @param execution
* @param ex
* @return
*/
public static SentinelClientHttpResponse handleException(HttpRequest request,
byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
try {
ObjectMapper objectMapper = new ObjectMapper();
return new SentinelClientHttpResponse(objectMapper.writeValueAsString(JsonResultHelper.JsonResultSuccess("被限制流量拉")));
} catch (JsonProcessingException e) {
e.printStackTrace();
return null;
}
}
/**
* 熔断后处理的方法
* @param request
* @param body
* @param execution
* @param ex
* @return
*/
public static SentinelClientHttpResponse fallback(HttpRequest request,
byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
try {
ObjectMapper objectMapper = new ObjectMapper();
return new SentinelClientHttpResponse(objectMapper.writeValueAsString(JsonResultHelper.JsonResultSuccess("被降级拉")));
} catch (JsonProcessingException e) {
e.printStackTrace();
return null;
}
}
}
第三步:添加配置
server:
port: 8082
#是否开启@SentinelRestTemplate注解
resttemplate:
sentinel:
enabled: true
现在有2个微服务store-service和order-service,如果store-service想调order-service,那么上述配置要写在store-service服务中,但是我们的限制和降级策略要对order-service服务中接口使用。
因为@SentinelRestTemplate是对RestTemplate进行处理的
八、OpenFeign整合我们的Sentinel
store-service服务调用order-service服务
第一步在store-service服务中加依赖
<dependency>
<groupId>com.clyu.shop</groupId>
<artifactId>clyu-shop-feign-api</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<!--加入sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--加入actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
第二步:在我们的Feign的声明式接口上添加fallback属性或者 fallbackFactory属性
@FeignClient(name = "order-service",fallback = ProductCenterFeignApiWithSentinelFallback.class)
//@FeignClient(name = "order-service",fallbackFactory = ProductCenterFeignApiWithSentielFallbackFactory.class)
public interface OrderFeignApi {
@RequestMapping(method = RequestMethod.GET,value = "/order/getOrder" )
JsonResult getOrder();
}
@Component//必须加注入到容器中,否则fallbac不生效
public class ProductCenterFeignApiWithSentinelFallback implements OrderFeignApi {
public ProductCenterFeignApiWithSentinelFallback(){
System.out.println("ddddddddddd");
}
@Override
public JsonResult getOrder() {
return JsonResultHelper.JsonResultSuccess("触发了流控");
}
}
下面这个,可以区分异常的类型
@Component //必须加注入到容器中,否则fallbackFactory不生效
public class ProductCenterFeignApiWithSentielFallbackFactory implements FallbackFactory<OrderFeignApi> {
public ProductCenterFeignApiWithSentielFallbackFactory(){
System.out.println("ddddddddddd");
}
@Override
public OrderFeignApi create(Throwable throwable) {
return new OrderFeignApi() {
@Override
public JsonResult getOrder() {
if(throwable instanceof FlowException) {
return JsonResultHelper.JsonResultSuccess("触发了流控");
}else if(throwable instanceof ParamFlowException) {
return JsonResultHelper.JsonResultSuccess("触发了授权规则");
}else if(throwable instanceof AuthorityException) {
return JsonResultHelper.JsonResultSuccess("触发了授权规则");
}else if(throwable instanceof SystemBlockException) {
return JsonResultHelper.JsonResultSuccess("触发了系统规则");
}else{
return JsonResultHelper.JsonResultSuccess("触发了降级规则");
}
}
}
}
第三步:加配置
因为store-service是调用方,所以下面的配置是在store-service中
feign:
sentinel:
enabled: true
第四步:加载到容器中
ProductCenterFeignApiWithSentinelFallback和ProductCenterFeignApiWithSentielFallbackFactory是com.clyu.shop.feign.handler包下
而store-service的包结构是这样,所以StoreApplication中的@SpringBootApplication不能扫描到com.clyu.shop.feign.handler下的类。
这时候我们需要用到注解@ComponentScans,把com.clyu.shop.feign.handler的类扫描到容器中。
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages="com.clyu.shop.feign.*")
@ComponentScans({
@ComponentScan("com.clyu.shop.feign.handler")
})
public class StoreApplication {
public static void main( String[] args )
{
SpringApplication.run(StoreApplication.class, args);
}
}
注意@SpringBootApplication 和 @ComponentScan同时使用的话,会使@SpringBootApplication的扫描功能失效
九、Sentinel规则持久化
我们知道Sentinel-dashboard配置的规则,在我们的微服务以及控制台重启的时候就清空了,因为他是基于内存的.
Sentinel推送数据的方式有3种
9.1 原生模式
Sentinel-dashboard将规则推送至客户端并直接更新到内存中,扩展写据源(WritableDataSource
)
优点:简单,无任何依赖性
缺点:不保证一致性;规则保存在内存中,重启即消失。强烈不建议用于生产环境
9.2 pull模式
扩展写数据源(WritableDataSource
),客户端主动向Sentinel-dashboard定期轮询拉取规则,这个规则中心可以是
RDBMS、文件等
优点:简单,无任何依赖;规则持久化
缺点:不保证一致性;实时性不保证,拉取过于频繁也可能会有性能问题。
首先 Sentinel-dashboard 控制台通过 API 将规则推送至客户端并更新到内存中,接着注册 的写数据源会将新的规则保存到本地的文件中。使用 pull 模式的数据源时一般 不需要对 Sentinel 控制台进行改造。 这种实现方法好处是简单,不引入新的依赖,坏处是无法保证监控数据的一致性
9.3 push模式
扩展读数据源(ReadableDataSource
),Sentinel-dashboard统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用Nacos、Zookeeper等配置中心。这种方式有更好的实时性和一致性保证。生产环境下一般采用push模式的数据源。
优点:一致性,规则持久化
缺点:引入第三方依赖
Sentinel-dashboard将规则推送到Nacos或其他远程配置中心,Sentinel客户端链接Nacos,获取规则配置;并监听Nacos配 置变化,如发生变化,就更新本地缓存,从而让本地缓存总是和 Nacos一致