我正在参与「启航计划」
SpringCloud实践系列(一):Nacos注册中心
Nacos: 注册中心,处理服务注册与发现
SpringCloud实践系列(二):Ribbon负载均衡
Ribbon: 客户端的负载均衡器,处理服务集群的负载均衡
SpringCloud实践系列(三):OpenFeign服务调用
OpenFeign:声明式的HTTP客户端,服务长途调用
SpringCloud实践系列(四):Nacos装备中心
Nacos:装备中心,中心化办理装备文件
SpringCloud实践系列(五):Sentinel流控
Sentinel:微服务流量卫兵,以流量为进口,维护微服务,避免呈现服务雪崩
SpringCloud实践系列(六):Gateway网关(待更新)
Gateway: 微服务网关,服务集群的进口,路由转发以及负载均衡(结合Sentinel)
SpringCloud实践系列(七):Sleuth链路追寻(待更新)
Sleuth: 链路追寻,链路快速整理、毛病定位等
SpringCloud实践系列(八):Seata分布式业务(待更新)
Seata: 分布式业务处理计划
一、概述
1.1、高并发带来的问题
在微服务架构中,咱们将业务拆分红一个个的服务,服务与服务之间能够彼此调用,可是因为网络原因或许本身的原因,服务并不能确保服务的100%可用,假如单个服务呈现问题,调用这个服务就会呈现网络推迟,此刻若有大量的网络涌入,会形成任务堆积,最终导致服务瘫痪。
1.2、服务雪崩
1.2.1、服务雪崩现象
【现象】
一个服务不可用导致一些列的服务不可用
1.3、常见容错计划
要避免雪崩的分散,咱们就要做好服务的容错,容错说白了便是维护自己不被猪队友拖垮的一些办法。
常见的容错思路有阻隔、超时、限流、熔断、降级这几种。
1.3.1、阻隔机制
比方服务A内总共有100个线程, 现在服务A可能会调用服务B,服务C,服务D.咱们在服务A进行长途调用的时分,给不同的服务分配固定的线程,不会把一切线程都分配给某个微服务. 比方调用服务B分配30个线程,调用服务C分配30个线程,调用服务D分配40个线程. 这样进行资源的阻隔,确保即使下流某个服务挂了,也不至于把服务A的线程耗费完。比方服务B挂了,这时分最多只会占用服务A的30个线程,服务A还有70个线程能够调用服务C和服务D。
1.3.2、超时机制
在上游服务调用下流服务的时分,设置一个最大呼应时刻,假如超越这个时刻,下流未作出反应,就断开恳求,释放掉线程。
1.3.3、限流机制
限流便是约束体系的输入和输出流量已到达维护体系的意图。为了确保体系的稳固运转,一旦到达的需求约束的阈值,就需求约束流量并采取少数办法以完结约束流量的意图。
1.3.4、熔断机制
在互联网体系中,当下流服务因拜访压力过大而呼应变慢或失利,上游服务为了维护体系全体的可用性,能够暂时堵截对下流服务的调用。这种献身局部,保全全体的办法就叫做熔断。
服务熔断一般有三种状况:
- 熔断封闭状况(Closed):服务没有毛病时,熔断器所在的状况,对调用方的调用不做任何约束。
- 熔断敞开状况(Open):后续对该服务接口的调用不再经过网络,直接执行本地的fallback办法。
- 半熔断状况(Half-Open):测验康复服务调用,允许有限的流量调用该服务,并监控调用成功率。假如成功率到达预期,则说明服务已康复,进入熔断封闭状况;假如成功率依旧很低,则从头进入熔断封闭状况。
1.3.5、降级机制
降级其实便是为服务供给一个兜底计划,一旦服务无法正常调用,就运用兜底计划。
1.4、常见容错组件
Hystrix | Resilience4J | Sentinel |
---|---|---|
Hystrix是由Netflflix开源的一个推迟和容错库,用于阻隔拜访长途体系、服务或许第三方库,避免级联失利,从而提高体系的可用性与容错性。 | Resilicence4J一款十分轻量、简略,而且文档十分清晰、丰富的熔断工具,这也是Hystrix官方推荐的代替产品。不仅如此,Resilicence4j还原生支撑Spring Boot 1.x/2.x,而且监控也支撑和prometheus等多款主流产品进行整合。 | Sentinel 是阿里巴巴开源的一款断路器完结,本身在阿里内部现已被大规模采用,十分安稳。 |
1.5、Sentinel
1.5.1、什么是Sentinel
Sentinel (分布式体系的流量防卫兵) 是阿里开源的一套用于服务容错的综合性处理计划。它以流量为切入点, 从流量控、熔断降级、体系负载维护等多个维度来维护服务的安稳性。
1.5.2、Sentinel特点
- 丰富的运用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的中心场景, 例如秒杀(即突发流量操控在体系容量能够承受的规模)、消息削峰填谷、集群流量操控、实时熔断下流不可用运用等。
- 齐备的实时监控:Sentinel 供给了实时的监控功用。经过操控台能够看到接入运用的单台机器秒级数据, 乃至 500 台以下规模的集群的汇总运转情况。
- 广泛的开源生态:Sentinel 供给开箱即用的与其它开源结构/库的整合模块, 例如与 SpringCloud、Dubbo、gRPC 的整合。只需求引入相应的依靠并进行简略的装备即可快速地接入Sentinel。
- 完善的SPI扩展点:Sentinel供给了简略易用、完善的SPI扩展接口。您能够经过完结扩展接口来快速的定制逻辑。例如定制规矩办理、适配动态数据源等。
1.5.3、Sentinel组成部分
Sentinel分为两部分:
- 中心库(Java 客户端)不依靠任何结构/库,能够运转于一切 Java 运转时环境,一起对 Dubbo /Spring Cloud 等结构也有较好的支撑。
- 操控台(Dashboard)根据 Spring Boot 开发,打包后能够直接运转,不需求额定的 Tomcat 等运用容器。
1.5.4、Sentinel架构
【API调用】常见api
# 接口概览
http://localhost:8720/api
# 获取资源的metrics信息
http://localhost:8720/cnode?id=接口路径
# 获取流控规矩接口
http://localhost:8720/getRules?type=flow
# 设置规矩接口
http://localhost:8720/setRules
二、装置部署Dashboard
下载jar包
github.com/alibaba/Sen…
发动操控台
# 直接到jar包目录下,运用jar指令发动项目(操控台本身是一个SpringBoot项目)
java -Dserver.port=8088 -Dcsp.sentinel.dashboard.server=localhost:8088 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar
页面拜访
# http://localhost:8088/#/login
# 默许用户名暗码是 sentinel/sentinel
三、快速开端
-
添加依靠
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
-
装备文件
spring: application: name: cloud-order # 服务名 cloud: nacos: discovery: server-addr: localhost:8848 # 指定nacos-server的地址 username: nacos password: nacos namespace: dev sentinel: transport: port: 8719 # 默许8719(当时服务,对sentinel供给的,调用端口号,用于监控服务拜访数据) dashboard: localhost:8888 # dashboard地址 eager: true # 发动项目是主动注入到sentinel中 server: port: 9003
发动项目,拜访http://localhost:8088即可看到,现已注册进去了
四、Sentinel规矩操作
【流控】:当满意被流控规矩,操控流量 — api层
【熔断降级】:当满意规矩,走备用计划 — api层
【热门】:细化到接口的参数,当携带指定参数时,对其做QPS约束 — api的参数层
【体系规矩】: 对整个服务做流控— 整个服务层
【授权】:装备当时服务,那些服务能调用(白名单)、哪些服务不能调用(黑名单)。
4.1、流控
【流控】:当满意被流控规矩,操控流量 — api层
4.1.1、针对来历
针对某个服务做流控
default代表对一切服务的调用做流控
4.1.2、流控规矩
-
QPS
每秒恳求数
-
线程数
一起恳求的线程数量
4.1.3、流控形式
-
直接(默许)
接口到达限流条件时,敞开限流
-
相关
当相关的资源到达限流条件时,敞开限流 [适合做运用退让]
-
链路
当从某个接口,进入当时资源到达限流条件时,敞开限流
4.1.4、流控效果
-
快速失利(默许)
直接失利,抛出反常,不做任何额定的处理,是最简略的效果
-
Warm Up
它从开端阈值到最大QPS阈值会有一个
缓冲
阶段,一开端的阈值是最大QPS阈值的1/3,然后渐渐增加,直到最大阈值,适用于将忽然增大的流量转换为缓步增加的场景。eg:预热时长填10,QPS填900,那么假如一下进来900,会当即完结300,剩余的在10s内完结
-
排队等待
让恳求以
均匀
的速度经过,单机阈值为每秒经过数量,其余的排队等待; 它还会让设置一个超时时刻,当恳求超越超时刻时刻还未处理,则会被丢掉。
4.2、熔断降级
【熔断降级】:当满意规矩,走备用计划 — api层
4.2.1、慢调用份额
上面装备表明
在【计算时长】内,恳求数超越【最小恳求数】,而且恳求中呼应时刻大于【最大RT】的份额超越【份额阈值】,就会触发熔断,在【熔断时长内】直接走降级办法。
4.2.2、反常份额
上面装备表明
在【计算时长】内,恳求数超越【最小恳求数】,而且反常份额超越【份额阈值】,就会触发熔断,在【熔断时长内】直接走降级办法。
4.2.3、反常数
上面装备表明
在【计算时长】内,恳求数超越【最小恳求数】,而且反常数超越【反常数】,就会触发熔断,在【熔断时长内】直接走降级办法。
4.3、热门
【热门】:细化到接口的参数,当携带指定参数时,对其做QPS约束 — api的参数层
上面装备表明
恳求该资源时,携带了第【参数索引】个参数,且在【计算窗口时长】内,QPS到达【单机阈值】则被流控
:资源需求运用注解@SentinelResource自界说才干收效
而且,因为运用了该注解,抛出的反常ParamFlowException,需求自己捕获
4.4、体系规矩
【体系规矩】: 对整个服务做流控— 整个服务层
体系规矩支撑以下的形式:
-
Load 自适应(仅对 Linux/Unix-like 机器收效):体系的 load1 作为启示指标,进行自适应体系维护。当体系 load1 超越设定的启示值,且体系当时的并发线程数超越预算的体系容量时才会触发体系维护(BBR 阶段)。体系容量由体系的
maxQps * minRt
预算得出。设定参考值一般是CPU cores * 2.5
。 - CPU usage(1.5.0+ 版本):当体系 CPU 运用率超越阈值即触发体系维护(取值规模 0.0-1.0),比较活络。
- 均匀 RT:当单台机器上一切进口流量的均匀 RT 到达阈值即触发体系维护,单位是毫秒。
- 并发线程数:当单台机器上一切进口流量的并发线程数到达阈值即触发体系维护。
- 进口 QPS:当单台机器上一切进口流量的 QPS 到达阈值即触发体系维护。
4.5、授权
【授权】:装备当时服务,那些服务能调用(白名单)、哪些服务不能调用(黑名单)。
上面装备表明
/auth/login接口,不允许cloud-order和cloud-jifen这两个服务调用
五、@SentinelResource及反常捕获
5.1、@SentinelResource运用
5.1、运用规矩
【作用】
1、用在办法上,用于自界说资源名
2、在设置热门时,有必要运用该注解自界说的资源名,不然不收效
@SentinelResource 用于界说资源,并供给可选的反常处理和 fallback 装备项。
属性 | 作用 |
---|---|
value | 资源称号,必需项(不能为空) |
entryType | entry 类型,可选项(默以为 EntryType.OUT ) |
blockHandler/ blockHandlerClass |
blockHandler 对应处理 BlockException 的函数称号,可选项。blockHandler 函数拜访规模需求是 public ,返回类型需求与原办法相匹配,参数类型需求和原办法相匹配而且最后加一个额定的参数,类型为 BlockException 。blockHandler 函数默许需求和原办法在同一个类中。若希望运用其他类的函数,则能够指定 blockHandlerClass 为对应的类的 Class 目标,留意对应的函数必需为 static 函数,不然无法解析。 |
fallback/ fallbackClass |
fallback 函数称号,可选项,用于在抛出反常的时分供给 fallback 处理逻辑。fallback 函数能够针对一切类型的反常(除了 exceptionsToIgnore 里边排除去的反常类型)进行处理。fallback 函数签名和方位要求: 1. 返回值类型有必要与原函数返回值类型共同; 2.办法参数列表需求和原函数共同,或许能够额定多一个 Throwable 类型的参数用于接纳对应的反常。 3.fallback 函数默许需求和原办法在同一个类中。若希望运用其他类的函数,则能够指定 fallbackClass 为对应的类的 Class 目标,留意对应的函数必需为 static 函数,不然无法解析。 |
defaultFallback |
默许的 fallback 函数称号,可选项,通常用于通用的 fallback 逻辑(即能够用于许多服务或办法)。默许 fallback 函数能够针对一切类型的反常(除了 exceptionsToIgnore 里边排除去的反常类型)进行处理。若一起装备了 fallback 和 defaultFallback,则只有 fallback 会收效。defaultFallback 函数签名要求: 1. 返回值类型有必要与原函数返回值类型共同; 2. 办法参数列表需求为空,或许能够额定多一个 Throwable 类型的参数用于接纳对应的反常。 3. defaultFallback 函数默许需求和原办法在同一个类中。若希望运用其他类的函数,则能够指定 fallbackClass 为对应的类的 Class 目标,留意对应的函数必需为 static 函数,不然无法解析。 |
exceptionsToIgnore |
用于指定哪些反常被排除去,不会计入反常计算中,也不会进入 fallback 逻辑中,而是会原样抛出。 |
5.2、运用示例
运用@SentinelResource对流控、降级做自界说处理
-
方法一:写在同一个类里
@RestController @Slf4j public class AnnoController { @RequestMapping("/anno1") /** * 当拜访资源呈现【流控】,会进入 blockHandler 指定的办法去进行处理 * 当拜访资源呈现 反常/【熔断降级】,会进入到 fallback 去进行处理 */ @SentinelResource(value = "anno1", blockHandler="anno1BlockHandler", fallback = "anno1Fallback") public String anno1(String name){ if("wolfcode".equals(name)){ throw new RuntimeException(); } return "anno1"; } /** * 限流备用办法 */ public String anno1BlockHandler(String name, BlockException ex){ log.error("{}", ex); return "接口被限流了"; } /** * 反常或降级备用办法 */ public String anno1Fallback(String name, Throwable throwable) { log.error("{}", throwable); // 区分熔断降级和其他反常 if (throwable instanceof DegradeException) { return "熔断降级"; } return "非sentinel反常"; } }
-
写到别的类中
@RestController @Slf4j public class AnnoController { @RequestMapping("/anno1") /** * 当拜访资源呈现【限流】,会进入 BlockExceptionHandler类的anno1BlockHandler办法 */ @SentinelResource(value = "anno1", blockHandler="anno1BlockHandler", blockHandlerClass="BlockExceptionHandler", fallback = "anno1Fallback", fallbackClass = "DegradeExceptionHandler" ) public String anno1(String name){ if("wolfcode".equals(name)){ throw new RuntimeException(); } return "anno1"; } }
-
限流备用办法
public class BlockExceptionHandler { /** * 静态办法 */ public static String anno1BlockHandler(String name, BlockException ex){ log.error("{}", ex); return "接口被限流了"; } public static String anno1Fallback(String name, Throwable throwable) { log.error("{}", throwable); // 区分熔断降级和其他反常 if (throwable instanceof DegradeException) { return "熔断降级"; } return "非sentinel反常"; } }
-
反常/降级备用办法
public class DegradeExceptionHandler { /** * 静态办法 */ public static String anno1Fallback(String name, Throwable throwable) { log.error("{}", throwable); // 区分熔断降级和其他反常 if (throwable instanceof DegradeException) { return "熔断降级"; } return "非sentinel反常"; } }
-
5.2、大局反常捕获
给每个办法都写一个对应的兜底办法,效率太低了
能够运用大局反常捕获对一切办法做兜底
5.2.1、Sentinel反常
5.2.2、大局反常处理
@Slf4j
@ControllerAdvice
public class MyResponseBodyAdvice implements ResponseBodyAdvice<Object> {
/**
* 流控处理
*/
@ExceptionHandler(FlowException.class)
@ResponseStatus(HttpStatus.OK)
@ResponseBody // 该注解用于把目标转为json
public OperationInfo handlerFlowException(HttpServletRequest request, HttpServletResponse response, Exception ex) {
log.info("{}, 流控, {}", request.getRequestURI(), LogUtil.getStack(ex));
return OperationInfo.failure("流控");
}
/**
* 熔断降级处理
*/
@ExceptionHandler(DegradeException.class)
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public OperationInfo handlerDegradeException(HttpServletRequest request, HttpServletResponse response, Exception ex) {
log.info("{}, 熔断降级, {}", request.getRequestURI(), LogUtil.getStack(ex));
return OperationInfo.failure("熔断降级");
}
// 其他略。。。。。。
}
六、规矩耐久化
6.1、默许形式
【规矩】:假如不做任何修正,Dashboard的推送规矩方法是经过API将规矩推送至客户端,并直接更新到内存中
【长处】:简略、无依靠
【坏处】:运用重启规矩会消失,仅用于测试,不能用于出产环境
6.2、Pull形式
【规矩】
FileRefreshableDataSource守时从指定文件中读取规矩JSON文件【本地文件】,假如发现文件发生变化,就更新规矩缓存
FileRefreshableDataSource接纳操控台规矩推送,并根据装备,修正规矩JSON【本地文件】
【长处】
能耐久化装备的规矩
【缺点】
服务部署在多台服务器上,无法同享本地文件
6.3、Push形式
【规矩】
将规矩耐久化在装备中心中,Sentinel把规矩发送到装备中心,各个服务从装备中心中拿对应的规矩
6.3.1、Sentinel Dashboard代码改造
-
Sentinel Dashboard默许是往Sentinel客户端发送,需求修正为往 装备中心发送
修正源码之后,从头打成jar包运用
6.3.2、微服务端
在要做Sentinel操控的服务里边装备
-
添加依靠
<!-- sentinel --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <!--sentinel的nacos耐久化--> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>spring-datasource-nacos</artifactId> </dependency>
-
添加装备
spring: cloud: nacos: config: server-addr: localhost:8848 namespace: dev group: DEFAULT_GROUP prefix: cloud-order file-extension: yml username: nacos password: nacos sentinel: transport: port: 8730 # 默许8719(当时服务对sentinel供给拜访的端口号) dashboard: localhost:8088 # dashboard地址 eager: true # 发动项目是主动注入到sentinel中 web-content-unify: false datasource: flow: nacos: server-addr: {nacos.server-addr} username: {nacos.username} password: {nacos.password} namespace: {nacos.namespace} groupId: DEFAULT_GROUP dataId: ${spring.application.name}-flow-rules data‐type: json rule‐type: flow degrade: nacos: server-addr: {nacos.server-addr} username: {nacos.username} password: {nacos.password} namespace: {nacos.namespace} groupId: DEFAULT_GROUP dataId: ${spring.application.name}-degrade-rules data‐type: json rule‐type: degrade param-flow: nacos: server-addr: {nacos.server-addr} username: {nacos.username} password: {nacos.password} namespace: {nacos.namespace} groupId: DEFAULT_GROUP dataId: ${spring.application.name}-param-flow-rules data‐type: json rule‐type: param-flow system: nacos: server-addr: {nacos.server-addr} username: {nacos.username} password: {nacos.password} namespace: {nacos.namespace} groupId: DEFAULT_GROUP dataId: ${spring.application.name}-system-rules data‐type: json rule‐type: system authority: nacos: server-addr: {nacos.server-addr} username: {nacos.username} password: {nacos.password} namespace: {nacos.namespace} groupId: DEFAULT_GROUP dataId: ${spring.application.name}-authority-rules data‐type: json rule‐type: authority nacos: server-addr: localhost:8848 username: nacos password: nacos namespace: sentinel