springcloudAlibaba---Sentinel

分布式系统遇到的问题

服务的可用性场景
在一个高度服务化的系统中,我们实现的一个业务逻辑通常会依赖多个服务,如果其中的下单服务不可用, 就会出现线程池里所有线程都因等待响应而被阻塞, 从而造成整个服务链路不可用, 进而导致整个系统的服务雪崩.
导致服务不可用的原因:
激增流量
1.激增流量导致系统CPU/load飙高,无法正常处理请求
2.激增流量打垮冷系统(数据库连接未创建,缓存未预热)
3.消息投递速度过快,导致消息处理积压
不稳定服务依赖
1.慢SQL查询卡爆连接池
2.第三方服务不响应,卡满连接池
3.业务调用持续出现异常,产生大量副作用
在服务提供者不可用的时候,会出现大量重试的情况:用户重试、代码逻辑重试,这些重试最终导致:进一步加大请求
流量。所以归根结底导致雪崩效应的最根本原因是:大量请求线程同步等待造成的资源耗尽。当服务调用者使用同步调
用时, 会产生大量的等待线程占用系统资源。一旦线程资源被耗尽,服务调用者提供的服务也将处于不可用状态, 于是服务
雪崩效应产生了。

解决方案(恢复性,稳定性)
常见的容错机制:
超时机制
在不做任何处理的情况下,服务提供者不可用会导致消费者请求线程强制等待,而造成系统资源耗尽。加入超时机制,一旦超时,就释放资源。由于释放资源速度较快,一定程度上可以抑制资源耗尽的问题。
服务限流
拒绝超出服务承受能力的请求
隔离
原理:用户的请求将不再直接访问服务,而是通过线程池中的空闲线程来访问服务,如果线程池已满,则会进行降级
处理,用户的请求不会被阻塞,至少可以看到一个执行结果(例如返回友好的提示信息),而不是无休止的等待或者看
到系统崩溃
隔离前:
在这里插入图片描述
隔离后:
在这里插入图片描述
信号隔离:
信号隔离也可以用于限制并发访问,防止阻塞扩散, 与线程隔离最大不同在于执行依赖代码的线程依然是请求线程(该线程需要通过信号申请, 如果客户端是可信的且可以快速返回,可以使用信号隔离替换线程隔离,降低开销。信号量的大小可以动态调整, 线程池大小不可以
服务熔断
远程服务不稳定或网络抖动时暂时关闭,就叫服务熔断。
现实世界的断路器大家肯定都很了解,断路器实时监控电路的情况,如果发现电路电流异常,就会跳闸,从而防止电路
被烧毁。
软件世界的断路器可以这样理解:实时监测应用,如果发现在一定时间内失败次数/失败率达到一定阈值,就“跳闸”,断路
器打开——此时,请求直接返回,而不去调用原本调用的逻辑。跳闸一段时间后(例如10秒),断路器会进入半开状
态,这是一个瞬间态,此时允许一次请求调用该调的逻辑,如果成功,则断路器关闭,应用正常调用;如果调用依然不
成功,断路器继续回到打开状态,过段时间再进入半开状态尝试——通过”跳闸“,应用可以保护自己,而且避免浪费资
源;而通过半开的设计,可实现应用的“自我修复“。
所以,同样的道理,当依赖的服务有大量超时时,在让新的请求去访问根本没有意义,只会无畏的消耗现有资源。比如
我们设置了超时时间为1s,如果短时间内有大量请求在1s内都得不到响应,就意味着这个服务出现了异常,此时就没有必
要再让其他的请求去访问这个依赖了,这个时候就应该使用断路器避免资源浪费。
服务降级
有服务熔断,必然要有服务降级。所谓降级,就是当某个服务熔断之后,服务将不再被调用,此时客户端可以自己准备一个本地的fallback(回退)回调,返回一个缺省值。 例如:(备用接口/缓存/mock数据) 。这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强,当然这也要看适合的业务场景。

什么是Sentinel

sentinel是阿里巴巴开源的,面向分布式服务架构的高可用防护组件
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以
流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。
Sentinel具有以下特征:
丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控
制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。
完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,
甚至 500 台以下规模的集群的汇总运行情况。
广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、
gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
完善的 SPI 扩展点: Sentinel 提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。
例如定制规则管理、适配数据源等。

在官方文档中,定义的Sentinel进行资源保护的几个步骤:

  1. 定义资源
  2. 定义规则
  3. 检验规则是否生效
1 Entry entry = null;
2 // 务必保证 finally 会被执行
3 try {
    
    
4 // 资源名可使用任意有业务语义的字符串 开启资源的保护
5  entry = SphU.entry("自定义资源名");
6 // 被保护的业务逻辑 method
7 // do something...
8 } catch (BlockException ex) {
    
    
9 // 资源访问阻止,被限流或被降级 Sentinel定义异常 流控规则,降级规则,热点参数规则。。。。 服务降级(降级规则)
图灵课堂
10 // 进行相应的处理操作
11 } catch (Exception ex) {
    
    
12 // 若需要配置降级规则,需要通过这种方式记录业务异常 RuntimeException 服务降级 mock feign:fallback
13  Tracer.traceEntry(ex, entry);
14 } finally {
    
    
15 // 务必保证 exit,务必保证每个 entry 与 exit 配对
16 if (entry != null) {
    
    
17  entry.exit();
18 }

Sentinel资源保护的方式
1.引入依赖

1 <dependency>
2 <groupId>com.alibaba.csp</groupId>
3 <artifactId>sentinel‐core</artifactId>
4 <version>1.8.0</version>
5 </dependency>

2.编写测试逻辑

1 @RestController
2 @Slf4j
3 public class HelloController {
    
    
4
5 private static final String RESOURCE_NAME = "hello";
6
7  @RequestMapping(value = "/hello")
8 public String hello() {
    
    
9
10  Entry entry = null;
11 try {
    
    
12 // 资源名可使用任意有业务语义的字符串,比如方法名、接口名或其它可唯一标识的字符串。
13  entry = SphU.entry(RESOURCE_NAME);
14 // 被保护的业务逻辑
15  String str = "hello world";
16  log.info("====="+str);
17 return str;
18 } catch (BlockException e1) {
    
    
19 // 资源访问阻止,被限流或被降级
20 //进行相应的处理操作
21  log.info("block!");
22 } catch (Exception ex) {
    
    
23 // 若需要配置降级规则,需要通过这种方式记录业务异常
24  Tracer.traceEntry(ex, entry);
25 } finally {
    
    
26 if (entry != null) {
    
    
27  entry.exit();
28 }
29 }
30 return null;
31 }
32
33 /**
34 * 定义流控规则
35 */
36  @PostConstruct
37 private static void initFlowRules(){
    
    
38  List<FlowRule> rules = new ArrayList<>();
39  FlowRule rule = new FlowRule();
40 //设置受保护的资源
41  rule.setResource(RESOURCE_NAME);
42 // 设置流控规则 QPS
43  rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
44 // 设置受保护的资源阈值
45 // Set limit QPS to 20.
46  rule.setCount(1);
47  rules.add(rule);
48 // 加载配置好的规则
49  FlowRuleManager.loadRules(rules);
50 }
51 }

缺点:
业务侵入性很强,需要在controller中写入非业务代码.
配置不灵活 若需要添加新的受保护资源 需要手动添加 init方法来添加流控规则
@SentinelResource注解实现
@SentinelResource 注解用来标识资源是否被限流、降级。
blockHandler: 定义当资源内部发生了BlockException应该进入的方法(捕获的是Sentinel定义的异常)
fallback: 定义的是资源内部发生了Throwable应该进入的方法
exceptionsToIgnore:配置fallback可以忽略的异常
1.引入依赖

1 <dependency>
2 <groupId>com.alibaba.csp</groupId>
3 <artifactId>sentinel‐annotation‐aspectj</artifactId>
4 <version>1.8.0</version>
5 </dependency>

2.配置切面支持

1 @Configuration
2 public class SentinelAspectConfiguration {
    
    
3
4  @Bean
5 public SentinelResourceAspect sentinelResourceAspect() {
    
    
6 return new SentinelResourceAspect();
7 }
8 }
3.UserController中编写测试逻辑,添加@SentinelResource,并配置blockHandler和fallback
1 @RequestMapping(value = "/findOrderByUserId/{id}")
2 @SentinelResource(value = "findOrderByUserId",
3  fallback = "fallback",fallbackClass = ExceptionUtil.class,
4  blockHandler = "handleException",blockHandlerClass = ExceptionUtil.class
5 )
6 public R findOrderByUserId(@PathVariable("id") Integer id) {
    
    
7 //ribbon实现
8  String url = "http://mall‐order/order/findOrderByUserId/"+id;
9 R result = restTemplate.getForObject(url,R.class);
10
图灵课堂
11 if(id==4){
    
    
12 throw new IllegalArgumentException("非法参数异常");
13 }
14
15 return result;
16 }

4.编写ExceptionUtil,注意如果指定了class,方法必须是static方法

1 public class ExceptionUtil {
    
    
2
3 public static R fallback(Integer id,Throwable e){
    
    
4 return R.error(2,"===被异常降级啦===");
5 }
6
7 public static R handleException(Integer id, BlockException e){
    
    
8 return R.error(2,"===被限流啦===");
9 }
10 }

5.流控规则设置可以通过Sentinel dashboard配置
客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信。

1 <dependency>
2 <groupId>com.alibaba.csp</groupId>
3 <artifactId>sentinel‐transport‐simple‐http</artifactId>
4 <version>1.8.0</version>
5 </dependency>
1Dcsp.sentinel.dashboard.server=consoleIp:port

Sentinel控制台使用

下载控制台 jar 包并在本地启动:
https://github.com/alibaba/Sentinel/releases
1 #启动控制台命令
2 java ‐jar sentinel‐dashboard‐1.8.0.jar
用户可以通过如下参数进行配置:
-Dsentinel.dashboard.auth.username=sentinel 用于指定控制台的登录用户名为 sentinel;
-Dsentinel.dashboard.auth.password=123456 用于指定控制台的登录密码为 123456;如果省略这两个参数,默认用户和密码均为
sentinel;
-Dserver.servlet.session.timeout=7200 用于指定 Spring Boot 服务端 session 的过期时间,如 7200 表示 7200 秒;60m 表示 60 分钟,
默认为 30 分钟;
java ­Dserver.port=8858 ­Dsentinel.dashboard.auth.username=xushu ­Dsentinel.dashboard.auth.password=123456 ­jar sentineldashboard­1.8.0.jar
为了方便快捷启动可以在桌面创建.bat文件
1 java ‐Dserver.port=8858 ‐Dsentinel.dashboard.auth.username=xushu ‐Dsentinel.dashboard.auth.password=123456 ‐jar D:\s
erver\sentinel‐dashboard‐1.8.0.jar
2 pause
访问http://localhost:8080/#/login ,默认用户名密码: sentinel/sentinel

springcloud Alibaba整合Sentinel

1.引入依赖

1 <dependency>
2 <groupId>com.alibaba.cloud</groupId>
3 <artifactId>spring‐cloud‐starter‐alibaba‐sentinel</artifactId>
4 </dependency>

2.添加yml配置,为微服务设置sentinel控制台地址
添加Sentinel后,需要暴露/actuator/sentinel端点,而Springboot默认是没有暴露该端点的,所以需要设置,测试
http://localhost:8800/actuator/sentinel

server:
2  port: 8800
3
4 spring:
5  application:
6  name: mall‐user‐sentinel‐demo
7  cloud:
8  nacos:
9  discovery:
10  server‐addr: 127.0.0.1:8848
11
12  sentinel:
13  transport:
14  # 添加sentinel的控制台地址
15  dashboard: 127.0.0.1:8080
16  # 指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer
17  # port: 8719

3.在sentinel控制台中设置流控规则
资源名: 接口的API
针对来源: 默认是default,当多个微服务都调用这个资源时,可以配置微服务名来对指定的微服务设置阈值
阈值类型: 分为QPS和线程数 假设阈值为10
QPS类型: 只得是每秒访问接口的次数>10就进行限流
线程数: 为接受请求该资源分配的线程数>10就进行限流
在这里插入图片描述
实时监控
监控接口的通过的QPS和拒绝的QPS
在这里插入图片描述
簇点链路
用来显示微服务的所监控的API
在这里插入图片描述
流控规则
流量控制(flow control),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。 ==== FlowRule RT(响应时间) 1/0.2s =5
同一个资源可以创建多条限流规则。FlowSlot 会对该资源的所有限流规则依次遍历,直到有规则触发限流或者所有规则遍
历完毕。一条限流规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限流效果。

限流阈值类型
QPS(Query Per Second):每秒请求数,就是说服务器在一秒的时间内处理了多少个请求。
QPS
进入簇点链路选择具体的访问的API,然后点击流控按钮
并发线程数
并发数控制用于保护业务线程池不被慢调用耗尽。例如,当应用所依赖的下游应用由于某种原因导致服务不稳定、响应
延迟增加,对于调用者来说,意味着吞吐量下降和更多的线程数占用,极端情况下甚至导致线程池耗尽。为应对太多线
程占用的情况,业内有使用隔离的方案,比如通过不同业务逻辑使用不同线程池来隔离业务自身之间的资源争抢(线程
池隔离)。这种隔离方案虽然隔离性比较好,但是代价就是线程数目太多,线程上下文切换的 overhead 比较大,特别是
对低延时的调用有比较大的影响。Sentinel 并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目
(正在执行的调用数目),如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。并发数控制通常在调用端
进行配置。

BlockException异常统一处理
springwebmvc接口资源限流入口在HandlerInterceptor的实现类AbstractSentinelInterceptor的preHandle方
法中,对异常的处理是BlockExceptionHandler的实现类
自定义BlockExceptionHandler 的实现类统一处理BlockException

1 @Slf4j
2 @Component
3 public class MyBlockExceptionHandler implements BlockExceptionHandler {
    
    
4  @Override
5 public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
    
    
6  log.info("BlockExceptionHandler BlockException================"+e.getRule());
7
8 R r = null;
9
10 if (e instanceof FlowException) {
    
    
11  r = R.error(100,"接口限流了");
12
13 } else if (e instanceof DegradeException) {
    
    
14  r = R.error(101,"服务降级了");
15
16 } else if (e instanceof ParamFlowException) {
    
    
17  r = R.error(102,"热点参数限流了");
18
19 } else if (e instanceof SystemBlockException) {
    
    
20  r = R.error(103,"触发系统保护规则了");
21
22 } else if (e instanceof AuthorityException) {
    
    
23  r = R.error(104,"授权规则不通过");
24 }
25
26 //返回json数据
27  response.setStatus(500);
28  response.setCharacterEncoding("utf‐8");
29  response.setContentType(MediaType.APPLICATION_JSON_VALUE);
30 new ObjectMapper().writeValue(response.getWriter(), r);
31
32 }
33 }

流控模式
基于调用关系的流量控制,调用关系包括调用方,被调用方,一个方法可能会调用其他方法,形成一个调用链路的层次关系

直接
资源调用达到设置的阈值后直接被流控抛出异常

关联
当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。比如对数据库同一个字段的读操作和写
操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本
身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢,举例来说,read_db 和
write_db 这两个资源分别代表数据库读写,我们可以给 read_db 设置限流规则来达到写优先的目的:设置 strategy 为
RuleConstant.STRATEGY_RELATE 同时设置 refResource 为 write_db。这样当写库操作过于频繁时,读数据的请求会被限流。
链路
根据调用链路入口限流。
下面中记录了资源之间的调用链路,这些资源通过调用关系,相互之间构成一棵调用树。这棵树的根节点是一个名字为
getUser 的虚拟节点,调用链的入口都是这个虚节点的子节点。
一棵典型的调用树如下图所示:

1  getUser
2 / \
3 / \
4 /order/test1 /order/test2

来自入口 /order/test1 和 /order/test2的请求都调用到了资源 getUser,Sentinel 允许只根据某个入口的统计信息对
资源限流。

快速失败
(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被
立即拒绝,拒绝方式为抛出FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统
的准确水位时。

Warm Up(激增流量)
Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量
突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐
增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
冷加载因子: codeFactor 默认是3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值。

匀速排队(脉冲流量)
匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,也即是让请
求以均匀的速度通过,对应的是漏桶算法。这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。

降级规则
除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。我们需要对不稳定
的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身
的手段,通常在客户端(调用端)进行配置。

熔断降级与隔离

熔断降级规则说明
熔断降级规则(DegradeRule)包含下面几个重要的属性:
Field 说明 默认值
resource 资源名,即规则的作用对象
grade 熔断策略,支持慢调用比例/异常比例/异常数策略 慢调用比例
count 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
timeWindow 熔断时长,单位为 s
minRequestAmount 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入) 5
statIntervalMs 统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入) 1000 ms
slowRatioThreshold 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)

熔断策略

慢调用比例
慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),
请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并
且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态
(HALF­OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会
再次被熔断。
异常比例
异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例
大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF­OPEN 状
态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],
代表 0% ­ 100%。
异常数
异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探
测恢复状态(HALF­OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
注意:异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。

热点参数限流
热点识别流控
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的数据,并对其访问进行限制。
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热
点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

单机阈值: 针对所有参数的值进行设置的一个公共的阈值

  1. 假设当前 参数 大部分的值都是热点流量, 单机阈值就是针对热点流量进行设置, 额外针对普通流量进行参数值流控
  2. 假设当前 参数 大部分的值都是普通流量, 单机阈值就是针对普通流量进行设置, 额外针对热点流量进行参数值流控

Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口
QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让
系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
Load 自适应(仅对 Linux/Unix­like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统
load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统
容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5。
https://www.cnblogs.com/gentlemanhai/p/8484839.html
CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0­1.0),比较灵敏。
平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

授权控制规则

很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源访问控制(黑白名单
控制)的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名
单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。
来源访问控制规则(AuthorityRule)非常简单,主要有以下配置项:
resource:资源名,即限流规则的作用对象。
limitApp:对应的黑名单/白名单,不同 origin 用 , 分隔,如 appA,appB。
strategy:限制模式,AUTHORITY_WHITE 为白名单模式,AUTHORITY_BLACK 为黑名单模式,默认为白名单模式。

集群规则

为什么要使用集群流控呢?假设我们希望给某个用户限制调用某个 API 的总 QPS 为 50,但机器数可能很多(比如有
100 台)。这时候我们很自然地就想到,找一个 server 来专门来统计总的调用量,其它的实例都与这台 server 通信来判
断是否可以调用。这就是最基础的集群流控的方式。
另外集群流控还可以解决流量不均匀导致总体限流效果不佳的问题。假设集群中有 10 台机器,我们给每台机器设置单机
限流阈值为 10 QPS,理想情况下整个集群的限流阈值就为 100 QPS。不过实际情况下流量到每台机器可能会不均匀,
会导致总量没有到的情况下某些机器就开始限流。因此仅靠单机维度去限制的话会无法精确地限制总体流量。而集群流
控可以精确地控制整个集群的调用总量,结合单机限流兜底,可以更好地发挥流量控制的效果。

集群流控中共有两种身份:
Token Client:集群流控客户端,用于向所属 Token Server 通信请求 token。集群限流服务端会返回给客户端
结果,决定是否限流。
Token Server:即集群流控服务端,处理来自 Token Client 的请求,根据配置的集群规则判断是否应该发放
token(是否允许通过)。
Sentinel 集群流控支持限流规则和热点规则两种规则,并支持两种形式的阈值计算方式:
集群总体模式:即限制整个集群内的某个资源的总体 qps 不超过此阈值。
单机均摊模式:单机均摊模式下配置的阈值等同于单机能够承受的限额,token server 会根据连接数来计算总
的阈值(比如独立模式下有 3 个 client 连接到了 token server,然后配的单机均摊阈值为 10,则计算出的集群总量
就为 30),按照计算出的总的阈值来进行限制。这种方式根据当前的连接数实时计算总的阈值,对于机器经常进行
变更的环境非常适合。
启动方式
Sentinel 集群限流服务端有两种启动方式:
独立模式(Alone),即作为独立的 token server 进程启动,独立部署,隔离性好,但是需要额外的部署操
作。独立模式适合作为 Global Rate Limiter 给集群提供流控服务

嵌入模式(Embedded),即作为内置的 token server 与服务在同一进程中启动。在此模式下,集群中各个
实例都是对等的,token server 和 client 可以随时进行转变,因此无需单独部署,灵活性比较好。但是隔离性不
佳,需要限制 token server 的总 QPS,防止影响应用本身。嵌入模式适合某个应用集群内部的流控。
云上版本 AHAS Sentinel 提供开箱即用的全自动托管集群流控能力,无需手动指定/分配 token server 以及管理连接状
态,同时支持分钟小时级别流控、大流量低延时场景流控场景,同时支持 Istio/Envoy 场景的 Mesh 流控能力。

Sentinel持久化模式

原始模式
如果不做任何修改,Dashboard 的推送规则方式是通过 API 将规则推送至客户端并直接更
新到内存中:
在这里插入图片描述
1.2 拉模式
pull 模式的数据源(如本地文件、RDBMS 等)一般是可写入的。使用时需要在客户端注册
数据源:将对应的读数据源注册至对应的 RuleManager,将写数据源注册至 transport 的
WritableDataSourceRegistry 中。
1.3 推模式
生产环境下一般更常用的是 push 模式的数据源。对于 push 模式的数据源,如远程配置中心
(ZooKeeper, Nacos, Apollo等等),推送的操作不应由 Sentinel 客户端进行,而应该经控
制台统一进行管理,直接进行推送,数据源仅负责获取配置中心推送的配置并更新到本
地。因此推送规则正确做法应该是 配置中心控制台/Sentinel 控制台 → 配置中心 →
Sentinel 数据源 → Sentinel,而不是经 Sentinel 数据源推送至配置中心。这样的流程就非
常清晰了:

基于Nacos配置中心控制台实现推送

官方demo: sentinel­demo­nacos­datasource
引入依赖

1 <dependency>
2 <groupId>com.alibaba.csp</groupId>
3 <artifactId>sentinel‐datasource‐nacos</artifactId>
4 </dependency>

nacos配置中心中配置流控规则

1 [
2 {
    
    
3 "resource": "TestResource",
4 "controlBehavior": 0,
5 "count": 10.0,
6 "grade": 1,
7 "limitApp": "default",
8 "strategy": 0
9 }
10 ]

yml中配置

1 spring:
2  application:
3  name: mall‐user‐sentinel‐demo
4  cloud:
5  nacos:
6  discovery:
7  server‐addr: 127.0.0.1:8848
8
9  sentinel:
10  transport:
11  # 添加sentinel的控制台地址
12  dashboard: 127.0.0.1:8080
13  # 指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer
14  port: 8719
15  datasource:
16  ds1:
17  nacos:
18  server‐addr: 127.0.0.1:8848
19  dataId: ${
    
    spring.application.name}
20  groupId: DEFAULT_GROUP
21  data‐type: json
22  rule‐type: flow
3)nacos配置中心中添加
1 [
2 {
    
    
3 "resource": "userinfo",
4 "limitApp": "default",
5 "grade": 1,
6 "count": 1,
7 "strategy": 0,
8 "controlBehavior": 0,
9 "clusterMode": false
10 }
11 ]
1 <!‐‐sentinel持久化 采用 Nacos 作为规则配置数据源‐‐>
2 <dependency>
3 <groupId>com.alibaba.csp</groupId>
4 <artifactId>sentinel‐datasource‐nacos</artifactId>
5 </dependency>
增加yml配置
1 server:
2  port: 8806
3
4 spring:
5  application:
6  name: mall‐user‐sentinel‐rule‐push‐demo #微服务名称
7
8  #配置nacos注册中心地址
9  cloud:
10  nacos:
11  discovery:
12  server‐addr: 127.0.0.1:8848
13
14  sentinel:
图灵课堂
15  transport:
16  # 添加sentinel的控制台地址
17  dashboard: 127.0.0.1:8080
18  # 指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer
19  #port: 8719
20  datasource:
21 # ds1: #名称自定义,唯一
22 # nacos:
23 # server‐addr: 127.0.0.1:8848
24 # dataId: ${
    
    spring.application.name}
25 # groupId: DEFAULT_GROUP
26 # data‐type: json
27 # rule‐type: flow
28  flow‐rules:
29  nacos:
30  server‐addr: 127.0.0.1:8848
31  dataId: ${
    
    spring.application.name}‐flow‐rules
32  groupId: SENTINEL_GROUP # 注意groupId对应Sentinel Dashboard中的定义
33  data‐type: json
34  rule‐type: flow
35  degrade‐rules:
36  nacos:
37  server‐addr: 127.0.0.1:8848
38  dataId: ${
    
    spring.application.name}‐degrade‐rules
39  groupId: SENTINEL_GROUP
40  data‐type: json
41  rule‐type: degrade
42  param‐flow‐rules:
43  nacos:
44  server‐addr: 127.0.0.1:8848
45  dataId: ${
    
    spring.application.name}‐param‐flow‐rules
46  groupId: SENTINEL_GROUP
47  data‐type: json
48  rule‐type: param‐flow
49  authority‐rules:
50  nacos:
51  server‐addr: 127.0.0.1:8848
52  dataId: ${
    
    spring.application.name}‐authority‐rules
53  groupId: SENTINEL_GROUP
54  data‐type: json
55  rule‐type: authority
56  system‐rules:
57  nacos:
58  server‐addr: 127.0.0.1:8848
59  dataId: ${
    
    spring.application.name}‐system‐rules
图灵课堂
60  groupId: SENTINEL_GROUP
61  data‐type: json
62  rule‐type: system
引入依赖
1 <!‐‐sentinel持久化 采用 Nacos 作为规则配置数据源‐‐>
2 <dependency>
3 <groupId>com.alibaba.csp</groupId>
4 <artifactId>sentinel‐datasource‐nacos</artifactId>
5 </dependency>
增加yml配置
1 server:
2  port: 8806
3
4 spring:
5  application:
6  name: mall‐user‐sentinel‐rule‐push‐demo #微服务名称
7
8  #配置nacos注册中心地址
9  cloud:
10  nacos:
11  discovery:
12  server‐addr: 127.0.0.1:8848
13
14  sentinel:
15  transport:
16  # 添加sentinel的控制台地址
17  dashboard: 127.0.0.1:8080
18  # 指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer
19  #port: 8719
20  datasource:
21 # ds1: #名称自定义,唯一
22 # nacos:
23 # server‐addr: 127.0.0.1:8848
24 # dataId: ${
    
    spring.application.name}
25 # groupId: DEFAULT_GROUP
26 # data‐type: json
27 # rule‐type: flow
28  flow‐rules:
29  nacos:
30  server‐addr: 127.0.0.1:8848
31  dataId: ${
    
    spring.application.name}‐flow‐rules
32  groupId: SENTINEL_GROUP # 注意groupId对应Sentinel Dashboard中的定义
33  data‐type: json
34  rule‐type: flow
35  degrade‐rules:
36  nacos:
37  server‐addr: 127.0.0.1:8848
38  dataId: ${
    
    spring.application.name}‐degrade‐rules
39  groupId: SENTINEL_GROUP
40  data‐type: json
41  rule‐type: degrade
42  param‐flow‐rules:
43  nacos:
44  server‐addr: 127.0.0.1:8848
45  dataId: ${
    
    spring.application.name}‐param‐flow‐rules
46  groupId: SENTINEL_GROUP
47  data‐type: json
48  rule‐type: param‐flow
49  authority‐rules:
50  nacos:
51  server‐addr: 127.0.0.1:8848
52  dataId: ${
    
    spring.application.name}‐authority‐rules
53  groupId: SENTINEL_GROUP
54  data‐type: json
55  rule‐type: authority
56  system‐rules:
57  nacos:
58  server‐addr: 127.0.0.1:8848
59  dataId: ${
    
    spring.application.name}‐system‐rules
60  groupId: SENTINEL_GROUP
61  data‐type: json
62  rule‐type: system

猜你喜欢

转载自blog.csdn.net/wangjunlei666/article/details/129878639