Sentinel官网地址 https://sentinelguard.io/zh-cn/index.html 最新版本v1.8.4
Sentinel官网文档地址 https://sentinelguard.io/zh-cn/docs/introduction.html
Sentinel GitHub源码地址 https://www.github.com/alibaba/Sentinel
Sentinel是面向分布式服务架构的高可用防护组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助用户保障微服务的稳定性。
分布式系统遇到常见棘手问题就是如何保障系统高可用性的场景,严重则会导致整个系统服务雪崩。
在微服务架构中,出现服务交叉调用是很常见的情况,如电商秒杀商品、商品详情、购物车等都会访问库存服务。如果其中下单服务不可用,就会出现线程池里的所有线程都因等待而被阻塞,进而导致整个系统的服务雪崩。服务雪崩效应是因服务提供者的不可用导致服务调用者的不可用,并将不可用逐步放大的过程。特别如果被一些非核心业务如积分服务而导致整个服务不可用那就非常不值得,假如积分服务有一些容错处理机制,到时在事后加一些补偿的机制加回来也是可以接收的。
常见容错机制
流量控制
Sentinel 的设计理念可以自由选择控制的角度,并进行灵活组合,从而达到想要的效果流量控制。流量控制有以下几个角度:
熔断降级
降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。Sentinel 和 Hystrix 的原则是一致的: 当调用链路中某个资源出现不稳定,例如,表现为 timeout,异常比例升高的时候,则对这个资源的调用进行限制,并让请求快速失败,避免影响到其它的资源,最终产生雪崩的效果。
设计理念:在限制的手段上,Sentinel 和 Hystrix 采取了完全不一样的方法。Hystrix 通过线程池的方式,来对依赖(在我们的概念中对应资源)进行了隔离。这样做的好处是资源和资源之间做到了最彻底的隔离。缺点是除了增加了线程切换的成本,还需要预先给各个资源做线程池大小的分配。Sentinel 对这个问题采取了两种手段:
和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。
除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。
系统负载保护
同类组件功能对比Sentinel VS Hystrix VS resilience4j
在 Sentinel 里面,所有的资源都对应一个资源名称以及一个 Entry。Entry 可以通过对主流框架的适配自动创建,也可以通过注解的方式或调用 API 显式创建;每一个 Entry 创建的时候,同时也会创建一系列功能插槽(slot chain)。这些插槽有不同的职责,例如:
NodeSelectorSlot
负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级;ClusterBuilderSlot
则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据;StatisticSlot
则用于记录、统计不同纬度的 runtime 指标监控信息;FlowSlot
则用于根据预设的限流规则以及前面 slot 统计的状态,来进行流量控制;AuthoritySlot
则根据配置的黑白名单和调用来源信息,来做黑白名单控制;DegradeSlot
则通过统计信息以及预设的规则,来做熔断降级;SystemSlot
则通过系统的状态,例如 load1 等,来控制总的入口流量;总体框架如下:
Sentinel 将 ProcessorSlot
作为 SPI 接口进行扩展(1.7.2 版本以前 SlotChainBuilder
作为 SPI),使得 Slot Chain 具备了扩展的能力。您可以自行加入自定义的 slot 并编排 slot 间的顺序,从而可以给 Sentinel 添加自定义的功能。
为了减少开发的复杂程度,对大部分的主流框架例如 Web Servlet、Dubbo、Spring Cloud、gRPC、Spring WebFlux、Reactor 等都做了适配。只需要引入对应的依赖即可方便地整合 Sentinel。
Sentinel 目前提供 Java、Go、C++ 、RUST等语言的原生支持。
Sentinel 可以简单的分为 Sentinel 核心库和 Dashboard,核心库不依赖 Dashboard,但是结合 Dashboard 可以取得最好的效果。
我们说的资源,可以是任何东西,服务,服务里的方法,甚至是一段代码。使用 Sentinel 来进行资源保护,主要分为几个步骤:
SphU.entry("HelloWorld")
和 entry.exit()
包围起来即可。使用之前得先引入依赖
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-core</artifactId> <version>1.8.4</version> </dependency>
package cn.itxs.ecom.storage.controller; import com.alibaba.csp.sentinel.Entry; import com.alibaba.csp.sentinel.SphU; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.PostConstruct; import java.util.ArrayList; import java.util.List; @RestController @RequestMapping("/sentinel") public class SentinelHelloControoler { private static final String RESOURCE_NAME = "hello"; @RequestMapping("/hello") public String hello(){ // 1.5.0 版本开始可以利用 try-with-resources 特性(使用有限制) // 资源名可使用任意有业务语义的字符串,比如方法名、接口名或其它可唯一标识的字符串。 try (Entry entry = SphU.entry(RESOURCE_NAME)) { // 被保护的业务逻辑 return "hello itxs"; } catch (BlockException ex) { // 资源访问阻止,被限流或被降级 // 在此处进行相应的处理操作 return "hello itxs block!"; } } @PostConstruct private void initFlowRules(){ List<FlowRule> rules = new ArrayList<>(); FlowRule rule = new FlowRule(); rule.setResource(RESOURCE_NAME); rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // Set limit QPS to 2. rule.setCount(2); rules.add(rule); FlowRuleManager.loadRules(rules); } }
连续访问访问测试http://localhost:4081/sentinel/hello,可以看到被流控了。
使用提供的@SentinelResource注解,getAccount()
方法就成了一个资源。注意注解支持模块需要配合 Spring AOP 或者 AspectJ 一起使用。
@RequestMapping("/account") @SentinelResource(value = ACCOUNT_RESOURCE_NAME,blockHandler = "blockHandlerForGetAccount") public Account getAccount(Integer id){ return new Account(1,"1001",100); } public Account blockHandlerForGetAccount(Integer id,BlockException ex){ ex.printStackTrace(); return new Account(1,"被流控了",100); }
连续访问测试http://localhost:4081/sentinel/account,可以看到也被流控了。
异常处理fallback机制
@RequestMapping("/account_exception") @SentinelResource(value = ACCOUNT_RESOURCE_NAME,fallback = "fallbackHandlerForGetAccount") public Account getAccountException(Integer id){ int i = 1/0; return new Account(1,"1001",100); } public Account fallbackHandlerForGetAccount(Integer id,Throwable ex){ ex.printStackTrace(); return new Account(1,"异常处理",100); }
访问测试http://localhost:4081/sentinel/account_exception,可以看到走fallback方法处理了。
@PostConstruct private void initDegradeRules(){ List<DegradeRule> rules = new ArrayList<>(); DegradeRule rule = new DegradeRule(); rule.setResource(DEGRADE_RESOURCE_NAME); rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT); rule.setCount(2); rule.setMinRequestAmount(2); rule.setStatIntervalMs(60*1000); rule.setTimeWindow(10); rules.add(rule); DegradeRuleManager.loadRules(rules); } @RequestMapping("/degrade") @SentinelResource(value = DEGRADE_RESOURCE_NAME,entryType = EntryType.IN,blockHandler = "blockHandlerForDegrade") public Account degrade(Integer id){ throw new RuntimeException("异常"); } public Account blockHandlerForDegrade(Integer id,BlockException ex){ ex.printStackTrace(); return new Account(1,"熔断降级",100); }
连续访问两次访问异常http://localhost:4081/sentinel/account_exception,之后十秒内访问都直接熔断降级,10秒后再访问两次显示异常
Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。通过整合 Sentinel 核心库和 Dashboard。Sentinel 控制台包含如下功能:
注意:Sentinel 控制台目前仅支持单机部署。Sentinel 控制台项目提供 Sentinel 功能全集示例,不作为开箱即用的生产环境控制台,若希望在生产环境使用请根据文档自行进行定制和改造。
# 下载 docker pull bladex/sentinel-dashboard:tagname,没有tag默认下载最新版本latest,本次使用1.8.4版本bladex/sentinel-dashboard:1.8.4 docker pull bladex/sentinel-dashboard # 运行,访问http 8858端口进入dashboard,用户名和密码sentinel/sentinel docker run --name sentinel -d -p 8858:8858 -d bladex/sentinel-dashboard
可以从其GitHub项目的 release 页面 下载最新版本的控制台 jar 包。目前最新版本为v1.8.4,也可以从最新版本的源码自行构建 Sentinel 控制台的jar包。由于下载源码1.8.4版本,那这里我们执行编译控制台源码得到二进制包。
# 启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本。其中 -Dserver.port=8858 用于指定 Sentinel 控制台端口为 8858,没有指定为8080。从 Sentinel 1.6.0 起,Sentinel 控制台引入基本的登录功能,默认用户名和密码都是 sentinel java -Dserver.port=8858 -Dsentinel.dashboard.auth.username=itxs -Dsentinel.dashboard.auth.password=123456 -jar sentinel-dashboard.jar
如果程序是Spring Boot 或 Spring Cloud 应用,则可以通过 Spring 配置文件来指定配置。
访问http://localhost:8858/
输入上面启动命令中的用户密码,进入控制台主页面
控制台启动后,客户端需要按照以下步骤接入到控制台。
pom.xml
引入 JAR 包:<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-transport-simple-http</artifactId> <version>1.8.4</version> </dependency>
-Dcsp.sentinel.dashboard.server=consoleIp:port
指定控制台地址和端口。若启动多个应用,则需要通过 -Dcsp.sentinel.api.port=xxxx
指定客户端监控 API 的端口(默认是 8719)如果是整合SpringCloud Alibaba加入
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>2021.0.1.0</version> </dependency>
**本人博客网站 **IT小神 www.itxiaoshen.com