随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助您保障微服务的稳定性。
多样化的流量控制
熔断降级
系统负载保护
实时监控和控制台
Sentinel 的使用可以分为两个部分:
核心库(Java 客户端):不依赖任何框架/库,能够运行于 Java 7 及以上的版本的运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持(见 主流框架适配)。
控制台(Dashboard):Dashboard 主要负责管理推送规则、监控、管理机器信息等。
Sentinel
与Hystrix
都能实现服务的限流、熔断、降级,上篇微服务实战(三) OpenFegin 声明式服务调用也简单介绍了Hystrix的熔断和降级。不敢说那个服务更好用,但就学习而言,Sentinel 文档要详细的多。
Hystrix在2018年也官宣进入维护模式,称Hystrix(版本1.5.18)足够稳定,可以满足Netflix
对我们现有应用程序的需求,并将resilience4j
这样的开放和活动项目用于新的内部项目。虽然不影响现有的项目,但相信会有越来越多的人倾向于选择Sentinel
、resilience4j
等。
Sentinel官方文档也简单做了同类组件功能对比:
Sentinel | Hystrix | resilience4j | |
---|---|---|---|
隔离策略 | 信号量隔离(并发控制) | 线程池隔离/信号量隔离 | 信号量隔离 |
熔断降级策略 | 基于慢调用比例、异常比例、异常数 | 基于异常比例 | 基于异常比例、响应时间 |
实时统计实现 | 滑动窗口(LeapArray) | 滑动窗口(基于 RxJava) | Ring Bit Buffer |
动态规则配置 | 支持近十种动态数据源 | 支持多种数据源 | 有限支持 |
扩展性 | 多个扩展点 | 插件的形式 | 接口的形式 |
基于注解的支持 | 支持 | 支持 | 支持 |
单机限流 | 基于 QPS,支持基于调用关系的限流 | 有限的支持 | Rate Limiter |
集群流控 | 支持 | 不支持 | 不支持 |
流量整形 | 支持预热模式与匀速排队控制效果 | 不支持 | 简单的 Rate Limiter 模式 |
系统自适应保护 | 支持 | 不支持 | 不支持 |
热点识别/防护 | 支持 | 不支持 | 不支持 |
多语言支持 | Java/Go/C++ | Java | Java |
Service Mesh 支持 | 支持 Envoy/Istio | 不支持 | 不支持 |
控制台 | 提供开箱即用的控制台,可配置规则、实时监控、机器发现等 | 简单的监控查看 | 不提供控制台,可对接其它监控系统 |
Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。 基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。
启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本。
下载地址:https://github.com/alibaba/Sentinel/releases
启动
#-Dserver.port=8080 用于指定 Sentinel 控制台端口为 8080
#-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=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
访问http://ip:8080
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
feign.hystrix.enabled
配置或设置为falsefeign.sentinel.enabled
配置spring:
application:
name: sunnyws-service-example2
profiles:
active: dev
cloud:
nacos:
discovery:
server-addr: 172.16.220.10:8848
namespace: e90d261b-9c05-4bcb-b99f-b419d952737a
config:
server-addr: 172.16.220.10:8848
file-extension: yml
namespace: e90d261b-9c05-4bcb-b99f-b419d952737a
sentinel:
transport:
#控制台地址
dashboard: 172.16.220.10:8080
port: 8917
eager: true
feign:
sentinel:
enabled: true
management:
# 端点检查(健康检查)
endpoints:
web:
exposure:
include: "*"
快速失败:直接失败,抛异常
Warm Up(预热):根据codeFactor(冷加载因子,默认值为3),从阈值/codeFactor,经过预热时长,才达到设置的QPS阈值。
即如果阈值为100,冷加载因子为3,预热时长为10秒,那么就会用100 / 3作为最初的阈值,经过10秒之后才会将阈值达到100,进而进行限流,意思就是让允许通过的流量缓慢增加,在达到一定的时间之后才达到阈值这样会更好的保护微服务
排队等待:匀速排队,让请求以均匀的速度通过,阈值类型必须设置成QPS,否则无效。此种模式可适用于应对突发流量的场景
- Sentinel 1.8后对熔断降级做了大的调整,可以定义任意时长的熔断时间,引入了半开启恢复支持。
- OpenFeign+Sentinel 熔断后降级 是将fallback交给feign处理
- Sentinel 默认统计的RT上限是4900ms,超出此阈值的都会算作4900ms,若需要变更此上限可以通过启动配置项
-Dcsp.sentinel.statistic.max.rt=xxx
来配置
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 默认将规则保存在内存中,重启即消失。
生产环境的 Sentinel Dashboard 规则需要集中管理和持久化。
官方文档中提到了三种推送模式来管理规则的推送。
推送模式 | 说明 | 优点 | 缺点 |
---|---|---|---|
原始模式 | API 将规则推送至客户端并直接更新到内存中,扩展写数据源(WritableDataSource ) |
简单,无任何依赖 | 不保证一致性;规则保存在内存中,重启即消失。严重不建议用于生产环境 |
Pull 模式 | 扩展写数据源(WritableDataSource ), 客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件 等 |
简单,无任何依赖;规则持久化 | 不保证一致性;实时性不保证,拉取过于频繁也可能会有性能问题。 |
Push 模式 | 扩展读数据源(ReadableDataSource ),规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。生产环境下一般采用 push 模式的数据源。 |
规则持久化;一致性;快速 | 引入第三方依赖 |
官方建议采用Push模式的数据源,并提供了 ZooKeeper, Apollo, Nacos 等的动态数据源实现,流程图如下:
使用Nacos存储Sentinel的限流规则
OpenFeign+Nacos+Sentinel
,sentinel
规则类型为flow
Sentinel Dashboard
代码,Nacos修改规则是可以同步到Sentinel的**,**但是通过Sentinel控制台修改或新增却不可以同步到Nacos。客户端添加注解
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-datasource-nacosartifactId>
dependency>
修改项目配置
sentinel.datasource
注入类型为Map
,所以flow
作为key可以随便填写。spring:
application:
name: sunnyws-service-example2
profiles:
active: dev
cloud:
nacos:
discovery:
server-addr: 172.16.220.50:8848
namespace: e90d261b-9c05-4bcb-b99f-b419d952737a
config:
server-addr: 172.16.220.50:8848
file-extension: yml
namespace: e90d261b-9c05-4bcb-b99f-b419d952737a
sentinel:
transport:
#控制台地址
dashboard: 172.16.220.50:8080
port: 8917
eager: true
datasource:
#随便填写
flow:
nacos:
server-addr: 172.16.220.50:8848
dataId: ${spring.application.name}-flow-rules
namespace: e90d261b-9c05-4bcb-b99f-b419d952737a
data-type: json
rule-type: flow
feign:
sentinel:
enabled: true
management:
# 端点检查(健康检查)
endpoints:
web:
exposure:
include: "*"
ribbon:
MaxAutoRetries: 0 #(默认1次 不包括第一次)最大重试次数,当注册中心中可以找到服务,但是服务连不上时将会重试,如果注册中心中找不到服务则直接走断路器
MaxAutoRetriesNextServer: 1 #(默认0次 不包括第一次)切换实例的重试次数
OkToRetryOnAllOperations: false #对所有操作请求都进行重试,如果是get则可以,如果是post,put等操作没有实现幂等的情况下是很危险的,所以设置为false
ConnectTimeout: 4000 #(默认1s)请求连接的超时时间
ReadTimeout: 3000 #(默认1s)请求处理的超时时间
Nacos Server添加配置文件
sentinel.datasource.xx.nacos.dataId
相同添加配置
[
{
"app":"sunnyws-service-example2",
"clusterConfig":{
"acquireRefuseStrategy":0,
"clientOfflineTime":2000,
"fallbackToLocalWhenFail":true,
"resourceTimeout":2000,
"resourceTimeoutStrategy":0,
"sampleCount":10,
"strategy":0,
"thresholdType":0,
"windowIntervalMs":1000
},
"clusterMode":false,
"controlBehavior":0,
"count":100,
"gmtCreate":1616226526395,
"gmtModified":1616226526395,
"grade":1,
"id":1,
"ip":"172.16.220.1",
"limitApp":"default",
"port":8917,
"resource":"GET:http://sunnyws-service-example1/test",
"strategy":0
}
]
- resource:资源名,即限流规则的作用对象
- limitApp:流控针对的调用来源,若为 default 则不区分调用来源
- grade:限流阈值类型(QPS 或并发线程数);0代表根据并发数量来限流,1代表根据QPS来进行流量控制
- count:限流阈值
- strategy:调用关系限流策略
- controlBehavior:流量控制效果(直接拒绝、Warm Up、匀速排队)
- clusterMode:是否为集群模式
下载源码包
修改配置
pom.xml
,注释test<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-datasource-nacosartifactId>
dependency>
修改代码
test
目录中sentinel-dashboard/src/test/java/com/alibaba/csp/sentinel/dashboard/rule/nacos
复制到sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos
DashboardConfig
增加配置项/**
* nacos server_addr
*/
public static final String CONFIG_NACOS_SERVER_ADDR = "sentinel.dashboard.nacos.server.addr";
/**
* nacos namespace
*/
public static final String CONFIG_NACOS_SERVER_NAMESPACE = "sentinel.dashboard.nacos.server.namespace";
/**
* nacos username
*/
public static final String CONFIG_NACOS_SERVER_USERNAME = "sentinel.dashboard.nacos.server.username";
/**
* nacos password
*/
public static final String CONFIG_NACOS_SERVER_PASSWORD = "sentinel.dashboard.nacos.server.password";
public static String getConfigNacosServerAddr(){
return getConfigStr(CONFIG_NACOS_SERVER_ADDR);
}
public static String getConfigNacosServerNamespace(){
return getConfigStr(CONFIG_NACOS_SERVER_NAMESPACE);
}
public static String getConfigNacosServerUsername(){
return getConfigStr(CONFIG_NACOS_SERVER_USERNAME);
}
public static String getConfigNacosServerPassword(){
return getConfigStr(CONFIG_NACOS_SERVER_PASSWORD);
}
NacosConfig
中nacosConfigService
@Bean
public ConfigService nacosConfigService() throws Exception {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, DashboardConfig.getConfigNacosServerAddr());
properties.put(PropertyKeyConst.NAMESPACE,DashboardConfig.getConfigNacosServerNamespace());
properties.put(PropertyKeyConst.USERNAME,DashboardConfig.getConfigNacosServerUsername());
properties.put(PropertyKeyConst.PASSWORD,DashboardConfig.getConfigNacosServerPassword());
return ConfigFactory.createConfigService(properties);
}
修改FlowControllerV1
Nacos修改配置文件
Data Id
为application.name
+-flow-rules
,Group
为SENTINEL_GROUP
FlowRuleNacosProvider
、FlowRuleNacosPublisher
中采用静态常量进行了初始化GROUP_ID
和FLOW_DATA_ID_POSTFIX
值,或和Nacos配置相同改为启动配置。重新部署和启动
#Dsentinel.dashboard.nacos.server.addr Nacos 地址
#Dsentinel.dashboard.nacos.server.namespace Nacos NameSpace
#Dsentinel.dashboard.nacos.server.username Nacos用户名
#Dsentinel.dashboard.nacos.server.password Nacos密码
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=172.16.220.50:8080 -Dproject.name=sentinel-dashboard -Dsentinel.dashboard.nacos.server.addr=172.16.220.50:8848 -Dsentinel.dashboard.nacos.server.namespace=e90d261b-9c05-4bcb-b99f-b419d952737a -Dsentinel.dashboard.nacos.server.username=nacos -Dsentinel.dashboard.nacos.server.password=nacos -jar sentinel-dashboard.jar
参考:https://www.jianshu.com/p/fb3218b21da5
作者: SunnyWs
链接: https://sunnyws.com/posts/104c04d2/
来源: SunnyWs’Blog