Sentinel
是面向分布式服务架构的高可用流量防护组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。
Sentinel
的关键概念。它可以是 Java
应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。只要通过 Sentinel API 定义的代码,就是资源,并能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL
,甚至服务名称作为资源名来标示资源。核心库(Java
客户端):不依赖任何框架/库,能够运行于所有 Java
运行时环境,同时对 Dubbo
/ Spring Cloud
等框架也有较好的支持。
控制台(Dashboard):基于 Spring Boot
开发,打包后可以直接运行,不需要额外的 Tomcat
等应用容器。
Sentinel
承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。Sentinel
同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。Sentinel
提供开箱即用的与其它开源框架 / 库的整合模块,例如与 Spring Cloud
、Dubbo
、gRPC
的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel
。Sentinel
提供简单易用、完善的 SPI
扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
Spring Cloud
中的Hystrix
是Netflix
开源的一款针对分布式系统延迟和容错的库,其目的是通过添加延迟容忍和容错逻辑,从而控制分布式服务之间的交互。
功能 | Sentinel | Hystrix |
---|---|---|
隔离策略 | 信号量隔离(并发线程数限流) | 线程池隔离/信号量隔离 |
熔断降级策略 | 基于响应时间、异常比率、异常数 | 基于异常比率 |
实时统计实现 | 滑动窗口(LeapArray ) |
滑动窗口(基于RxJava ) |
动态规则配置 | 支持多种数据源 | 支持多种数据源 |
拓展性 | 多个拓展点 | 插件形式 |
基于注解的支持 | 支持 | 支持 |
限流 | 基于QPS ,支持基于调用关系的限流 |
有限的支持 |
流量整形 | 支持预热模式、匀速器模式、预热排队模式 | 不支持 |
系统自适应保护 | 支持 | 不支持 |
控制台 | 可配置规则、查看秒级监控、机器发现等 | 简单的监控查看 |
除了流量控制以外,降低调用链路中的不稳定资源也是
Sentinel
的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。
Sentinel
和 Hystrix
的原则是一致的,当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。Hystrix
通过 线程池隔离 的方式,来对依赖(对应 Sentinel
中的资源)进行了隔离。这样做的好处是资源和资源之间做到了最彻底的隔离。缺点是除了增加了线程切换的成本(过多的线程池导致线程数目过多),还需要预先给各个资源做线程池大小的分配。Sentinel
采用了两种手段,一是通过并发线程数进行限制,二是通过响应时间对资源进行降级。Sentinel
通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。Sentinel
还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。SLOW_REQUEST_RATIO
):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT
(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN
状态),若接下来的一个请求响应时间小于设置的慢调用 RT
则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。ERROR_RATIO
):当单位统计时长内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN
状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。ERROR_COUNT
):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN
状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。Sentinel
在得知系统性能之后,可以在低峰期将流量都放进来,高峰期对流量进行限制。# 拉取镜像
$ docker pull bladex/sentinel-dashboard:1.6.3
# 运行
$ docker run --name sentinel -d -p 8858:8858 -d bladex/sentinel-dashboard:1.6.3
# 设置开机自启动
$ docker update sentinel --restart=always
# 浏览器访问
http://yourIp:8858
# 用户名/密码
sentinel/sentinel
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
application.properties
# 指定控制台地址
spring.cloud.sentinel.transport.dashboard=yourIp:8858
# 与sentinel单独连接的端口(启动该服务,会在应用程序的相应服务器上启动HTTP Server,并且该服务器将与Sentinel dashboard进行交互)
spring.cloud.sentinel.transport.port=8719
# 如果sentinel装在虚拟机,则必须配这个
# spring.cloud.sentinel.transport.client-ip=本机的ip
# 暴露应用的所有信息(包括当前应用的所有规则信息、日志目录、当前实例的 IP,Sentinel Dashboard 地址,Block Page,应用与 Sentinel Dashboard 的心跳频率等等信息)
management.endpoints.web.exposure.include=*
DispatcherServlet
,然后进入Controller
、Service
、Mapper
,这样的一个调用链就叫做簇点链路。簇点链路中被监控的每一个接口就是一个资源。Sentinel
会监控 SpringMVC
的每一个端点(Endpoint
,也就是 Controller
中的方法),因此 SpringMVC
的每一个端点(Endpoint
)就是调用链路中的一个资源。Sentinel
官方推荐在生产架构中使用第三方数据源作为永久存储中心,比如 nacos
、apollo
、zookeeper
。因为这几种数据源都是基于 push
模式,也就是由规则中心统一推送,Sentinel Client
只需通过注册监听器的方式时刻监听变化,并负责获取配置中心推送的配置并更新到本地,这种方式能更好的保证实时性和一致性,并且各个微服务的限流、降级规则都可以永久存储。当被触发流控规则后,
Sentinel
默认会提示Blocked by Sentinel (flow limiting)
。此时,我们可以优化为自定义的提示信息。
@Component
public class MySentinelExceptionHandler implements BlockExceptionHandler {
/**
* 自定义 sentinel 触发阻塞后的响应信息。
*
* @param request 请求
* @param response 响应
* @param e 阻塞类型
* @throws Exception 异常
*/
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
String msg = null;
if (e instanceof FlowException) {
msg = "访问频繁,请稍候再试";
} else if (e instanceof DegradeException) {
msg = "系统降级";
} else if (e instanceof SystemBlockException) {
msg = "系统规则限流或降级";
} else if (e instanceof AuthorityException) {
msg = "授权规则不通过";
} else {
msg = "未知限流降级";
}
// 设置响应信息
response.setStatus(500);
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Type", "application/json;charset=utf-8");
response.setContentType("application/json;charset=utf-8");
// 反序列化为json进行输出
new ObjectMapper().writeValue(response.getWriter(), msg);
}
}
# 调用方feign启用sentinel,当调用出错后实现容错降级
feign.sentinel.enabled=true
触发熔断后,调用
Fallback
方法。
@FeignClient(name = "service-provider", fallback = EchoServiceFallback.class, configuration = FeignConfiguration.class)
public interface EchoService {
@RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)
String echo(@PathVariable("str") String str);
}
class FeignConfiguration {
@Bean
public EchoServiceFallback echoServiceFallback() {
return new EchoServiceFallback();
}
}
class EchoServiceFallback implements EchoService {
@Override
public String echo(@PathVariable("str") String str) {
return "echo fallback";
}
}
Spring Cloud Sleuth
为SpringCloud
实现了一个分布式链路追踪解决方案,大量借鉴了Dapper
,Zipkin
和HTrace
等链路追踪技术。对于大多数用户而言,
Sleuth
应该是不可见的,并且您与外部系统的所有交互都应自动进行检测。您可以简单地在日志中捕获数据,也可以将其发送到远程收集器服务。
Google
的 Dapper
,Twitter
的 Zipkin
,以及阿里的 Eagleeye
(鹰眼)等,它们都是非常优秀的链路追踪开源组件。Spring Cloud Sleuth
中集成 Zipkin
非常的简单,只需要引入相应的依赖和做相关的配置即可。
Zipkin
是Google Dapper
实现。
REST API
接口来辅助我们查询跟踪数据以实现对分布式系统的监控程序,从而及时地发现系统中出现的延迟升高问题并找出系统性能瓶颈的根源。API
接口之外,它也提供了方便的 UI
组件帮助我们直观地搜索跟踪信息和分析请求链路明细,比如:可以查询某段时间内各用户请求的处理时间等。SkyWalking
更加轻量级,安装也非常简单,是中小规模的微服务项目首选方案。Spring Cloud Sleuth
是对 Zipkin
的一个封装,对于 Span
、Trace
等信息的生成、接入HTTP Request
,以及向 Zipkin Server
发送采集信息等全部自动完成。
Span(跨度):基本工作单元,发送一个远程调度任务 就会产生一个 Span,Span 是一个 64 位 ID 唯一标识的,Trace 是用另一个 64 位 ID 唯一标识的,Span 还有其他数据信息,比如摘要、时间戳事件、Span 的 ID、以及进度 ID。
Trace(跟踪):一系列 Span 组成的一个树状结构。请求一个微服务系统的 API 接口,这个 API 接口,需要调用多个微服务,调用每个微服务都会产生一个新的 Span,所有由这个请求产生的 Span 组成了这个 Trace。
Annotation(标注):用来及时记录一个事件的,一些核心注解用来定义一个请求的开始和结束 。这些注解包括以下:
cs
(Client Sent):客户端发送一个请求,这个注解描述了这个 Span
的开始。sr
(Server Received):服务端获得请求并准备开始处理它,用 sr 减去 cs 时间戳便可得到网络传输的时间。ss
(Server Sent - 服务端发送响应):该注解表明请求处理的完成(当请求返回客户端),如果 ss 的时间戳减去 sr 时间戳,就可以得到服务器请求的时间。cr
(Client Received - 客户端接收响应):此时 Span 的结束,如果 cr 的时间戳减去 cs 时间戳便可以得到整个请求所消耗的时间。概念图:
docker
下 安装 zipkin
$ docker run -d -p 9411:9411 openzipkin/zipkin
http://yourIp:9411/
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-zipkinartifactId>
dependency>
application.properties
# zipkin 服务器的地址
spring.zipkin.base-url=http://yourIp:9411/
# 关闭服务发现,否则 Spring Cloud 会把 zipkin 的 url 当做服务名称
spring.zipkin.discovery-client-enabled=false
# 设置使用 http 的方式传输数据
spring.zipkin.sender.type=web
# 设置抽样采集率为 100% ,默认为 0.1 ,即 10%
spring.sleuth.sampler.probability=1
“-------怕什么真理无穷,进一寸有一寸的欢喜。”
微信公众号搜索:饺子泡牛奶。