Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
本篇博客介绍CAP理论,微服务中的雪崩问题,和Hystix的解决方案;然后介绍sentinel,阐述流量控制和熔断降级的概念;给出了sentinel下载运行的流程以及参数解释。
1.CAP理论,微服务中的雪崩问题,和Hystix的解决方案;
2.sentinel,阐述流量控制和熔断降级的概念;
3.sentinel下载运行的流程以及参数解释;
A(可用性) C(一致性) P(分区容灾(可用))
AP,CP(最终一致性);
P是一定要实现的,可用性一定要有;
①一致性:对于客户端的每次读操作,要么读到的是最新的数据,要么读取失败。换句话说,一致性是站在分布式系统的角度,对访问本系统的客户端的一种承诺:要么我给您返回一个错误,要么我给你返回绝对一致的最新数据,不难看出,其强调的是数据正确。
②可用性:任何客户端的请求都能得到响应数据,不会出现响应错误。换句话说,可用性是站在分布式系统的角度,对访问本系统的客户的另一种承诺:我一定会给您返回数据,不会给你返回错误,但不保证数据最新,强调的是不出错。
③分区容忍性:由于分布式系统通过网络进行通信,网络是不可靠的。当任意数量的消息丢失或延迟到达时,系统仍会继续提供服务,不会挂掉。换句话说,分区容忍性是站在分布式系统的角度,对访问本系统的客户端的再一种承诺:我会一直运行,不管我的内部出现何种数据同步问题,强调的是不挂掉。
https://github.com/Netflix/Hystrix/wiki
在分布式环境中,许多服务依赖关系中的一些不可避免地会失败。Hystrix是一个库,通过添加延迟容忍和容错逻辑,可以帮助您控制这些分布式服务之间的交互。Hystrix通过隔离服务之间的访问点、停止跨服务的级联故障以及提供后备选项来实现这一点,所有这些都提高了系统的整体弹性。 improve your system’s overall resiliency.
微服务中,服务间调用关系错综复杂,一个请求,可能需要调用多个微服务接口才能实现,会形成非常复杂的调用链路:
复杂分布式体系结构中的应用程序有几十个依赖项,每个依赖项都不可避免地会在某个时刻失败。如果主机应用程序没有与这些外部故障隔离开来,那么它就有被这些故障摧毁的风险。
例如,对于一个依赖30个服务的应用程序,其中每个服务都有99.99%的正常运行时间,您可以期待以下内容:
99.99^30 = 99.7% uptime
0.3% of 1 billion requests = 3,000,000 failures
2+ hours downtime/month even if all dependencies have excellent uptime.
即使所有依赖关系都表现良好,如果不对整个系统进行弹性设计,数十项服务中每项服务的0.01%停机时间的总影响也可能相当于每月停机数小时。
当一切正常时,请求流可能如下所示:
如图,一次业务请求,需要调用A、P、H、I四个服务,这四个服务又可能调用其它服务。如果此时,某个服务出现异常:
在高流量的情况下,一个潜在的后端依赖可能会导致所有服务器上的所有资源在几秒钟内饱和。
应用程序中通过网络或进入客户端库可能导致网络请求的每一点都是潜在故障的根源。比故障更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,从而备份队列、线程和其他系统资源,从而导致系统中更多的级联故障。
例如微服务 I 发生异常,请求阻塞,用户不会得到响应,则tomcat的这个线程不会释放,于是越来越多的用户请求到来,越来越多的线程会阻塞:
当通过第三方客户端执行网络访问时,这些问题会加剧——这是一个“黑匣子”,其中的实现细节是隐藏的,可以随时更改,并且每个客户端库的网络或资源配置不同,通常很难监控和更改。
更糟糕的是,可传递的依赖关系在没有被应用程序显式调用的情况下执行潜在的昂贵或易出错的网络调用。
网络连接出现故障或降级。服务和服务器出现故障或速度变慢。新的库或服务部署会更改行为或性能特征。客户端库有错误。
所有这些都代表了需要隔离和管理的故障和延迟,这样单个故障依赖关系就不会导致整个应用程序或系统瘫痪。
当您使用Hystrix包装每个底层依赖项时,上图中所示的体系结构将更改为类似下图。每个依赖关系都是相互隔离的,在延迟发生时可能饱和的资源受到限制,并包含在回退逻辑中,该逻辑决定在依赖关系中发生任何类型的故障时做出什么响应:
Hystix解决雪崩问题的手段有两个:
隔离是 Hystrix 的核心功能之一。Hystrix 提供两种隔离策略:线程池隔离(Bulkhead Pattern)和信号量隔离,其中最推荐也是最常用的是线程池隔离。
Hystrix 的线程池隔离针对不同的资源分别创建不同的线程池,不同服务调用都发生在不同的线程池中,在线程池排队、超时等阻塞情况时可以快速失败,并可以提供 fallback 机制。线程池隔离的好处是隔离度比较高,可以针对某个资源的线程池去进行处理而不影响其它资源,但是代价就是线程上下文切换的 overhead 比较大,特别是对低延时的调用有比较大的影响。
但是,实际情况下,线程池隔离并没有带来非常多的好处。首先就是过多的线程池会非常影响性能。考虑这样一个场景,在 Tomcat 之类的 Servlet 容器使用 Hystrix,本身 Tomcat 自身的线程数目就非常多了(可能到几十或一百多),如果加上 Hystrix 为各个资源创建的线程池,总共线程数目会非常多(几百个线程),这样上下文切换会有非常大的损耗。另外,线程池模式比较彻底的隔离性使得 Hystrix 可以针对不同资源线程池的排队、超时情况分别进行处理,但这其实是超时熔断和流量控制要解决的问题,如果组件具备了超时熔断和流量控制的能力,线程池隔离就显得没有那么必要了。
Hystrix 的信号量隔离限制对某个资源调用的并发数。这样的隔离非常轻量级,仅限制对某个资源调用的并发数,而不是显式地去创建线程池,所以 overhead 比较小,但是效果不错,也支持超时失败
应用场景
线程池隔离:
请求并发量大,并且耗时长(请求耗时长一般是计算量大,读数据库),采用线程池隔离,这样的话,可以保证大量的容器线程可用,不会由于服务原因,一直处于阻塞状态或等待状态,快速失败返回。
信号量隔离:
请求并发量大,并且耗时短(请求耗时短可能是计算量小,读缓存),采用信号量隔离,因为这类服务的返回通常会非常快,不会占用容器线程太长时间,而且也减少了线程切换的一些开销,提高了缓存服务的效率。
熔断器模式(Circuit Breaker Pattern)
熔断器3个状态:
Closed:关闭状态,所有请求都正常访问。
Open:打开状态,所有请求都会被降级。
Hystrix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全打开。默认失败比例的阈值是50%,请求次数最少不低于20次。默认是 五秒之内请求20次 如果有10次失败(50%),则请求不能正常访问。
Half Open:半开状态,open状态不是永久的,打开后会进入休眠时间(默认是5S)。随后断路器会自动进入半开状态。
此时会释放部分请求通过,若这些请求都是健康的,则会完全关闭断路器,否则继续保持打开,再次进行休眠计时
https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。
只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。
Hystrix 和sentinel的用表格来进行对比总结:
Sentinel | Hystrix | |
---|---|---|
隔离策略 | 信号量隔离 | 线程池隔离/信号量隔离 |
熔断降级策略 | 基于响应时间或失败比率 | 基于失败比率 |
实时指标实现 | 滑动窗口 | 滑动窗口(基于 RxJava) |
规则配置 | 支持多种数据源 | 支持多种数据源 |
扩展性 | 多个扩展点 | 插件的形式 |
基于注解的支持 | 支持 | 支持 |
限流 | 基于 QPS,支持基于调用关系的限流 | 有限的支持 |
流量整形 | 支持慢启动、匀速器模式 | 不支持 |
系统负载保护 | 支持 | 不支持 |
控制台 | 开箱即用,可配置规则、查看秒级监控、机器发现等 | 不完善 |
常见框架的适配 | Servlet、Spring Cloud、Dubbo、gRPC 等 | Servlet、Spring Cloud Netflix |
流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:
流量控制有以下几个角度:
除了流量控制以外,及时对调用链路中的不稳定因素进行熔断也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,可能会导致请求发生堆积,进而导致级联错误。
Sentinel 和 Hystrix 的原则是一致的: 当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。
在限制的手段上,Sentinel 和 Hystrix 采取了完全不一样的方法。
Hystrix 通过 线程池隔离 的方式,来对依赖(在 Sentinel 的概念中对应 资源)进行了隔离。这样做的好处是资源和资源之间做到了最彻底的隔离。缺点是除了增加了线程切换的成本(过多的线程池导致线程数目过多),还需要预先给各个资源做线程池大小的分配。
Sentinel 对这个问题采取了两种手段:
和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。
除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。
https://github.com/alibaba/Sentinel/releases
java -Dserver.port=7777 -Dcsp.sentinel.dashboard.server=192.168.111.130:7777 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.6.jar
firewall-cmd --zone=public --add-port=7777/tcp --permanent
success
firewall-cmd --reload
success
firewall-cmd --zone=public --list-ports
7777/tcp
默认用户名密码sentinel
使用如下命令启动控制台:
-Dserver.port=8840
用于指定 Sentinel 控制台端口为 8840。默认是 8080 。
-Dproject.name=sentinel-dashboard
指定 Sentinel 控制台程序的名称。
说明
如果你有多张网卡的话,你还需要指定使用哪张网卡(IP)来接受各个微服务上报的信息:
从 1.6.0 起,sentinel-dashboard 引入基本的登录功能,默认用户名和密码都是 sentinel 。当然也可以
通过 JVM 参数的方式进行修改
-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 分钟;
Sentinel 本身就是一个 Spring Boot 应用,所以jar 包内部的 application.properties 文件也是可以修改配置的。
1.CAP理论,微服务中的雪崩问题,和Hystix的解决方案;
2.sentinel,阐述流量控制和熔断降级的概念;
3.sentinel下载运行的流程以及参数解释;