前言
在现代分布式系统中,如何有效地保护系统免受突发流量和故障的影响,是每个开发人员和架构师都需要思考的重要问题。在这样的背景下,Sentinel作为一个强大的系统保护和控制组件,为我们提供了降级、限流、熔断等多种策略,帮助我们更好地保障系统的稳定性和可用性。
https://sentinelguard.io/zh-cn/docs/quick-start.html
- 在微服务的体系架构中,如果遇到
服务提供方
不能提供服务
时,怎么办?- 将采用spring cloud alibaba sentinel进行解决。
- 在学习sentinel之前,先了解相关的观念。
正文
一. 微服务常见概念
1 服务雪崩
- 服务雪崩:在整条链路的服务中,一个服务失败,导致整条链路的服务都失败的情形。
- 存在整条链路服务(Service A、Service B、Service C)
- Service A 流量突然性增加,导致Service B 和Service C 流量也增加。
- Service C 因为抗不住请求,变得不可用。导致Service B的请求变得阻塞。
- 当Service B的资源耗尽,Service B就会变得不可用。
- 最后 Service A 不可用。
2 服务熔断
- 服务熔断:当下游的服务因为某种原因突然变得不可用或响应过慢,上游服务为了保证自己整体服务的可用性,不再继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用。
最开始处于
closed
状态,一旦检测到错误到达一定阈值,便转为open
状态;这时候会有个 reset timeout,到了这个时间了,会转移到
half open
状态;尝试放行一部分请求到后端,一旦检测成功便回归到
closed
状态,即恢复服务;
3 服务降级
- 什么是服务降级呢?
- 当下游的服务因为某种原因响应过慢,下游服务主动停掉一些不太重要的业务,释放出服务器资源,增加响应速度!
- 当下游的服务因为某种原因不可用,上游主动调用本地的一些降级逻辑,避免卡顿,迅速返回给用户!
4 熔断和降级的区别
-
服务熔断和服务降级的区别?
- 服务降级有很多种降级方式!如开关降级、限流降级、熔断降级!
- 服务熔断属于降级方式的一种!
- 当发生下游服务不可用的情况,熔断和降级必定是一起出现。
-
服务降级大多是属于一种业务级别的处理,熔断属于框架层级的实现
-
开关降级
在配置中心配置一个开关(变量),在配置中心更改开关,决定哪些服务进行降级
5 Sentinel 介绍
- Sentinel :一个高可用的流量控制与防护组件,保障微服务的稳定性。
- Sentinel分为两个部分,sentinel-core与sentinel-dashboard。
- sentinel-core 部分能够支持在本地引入sentinel-core进行限流规则的整合与配置。
- sentinel-dashboard 则在core之上能够支持在线的流控规则与熔断规则的维护与调整等。
二. core:降级
1 现象1
-
提供者搭建集群(8170/8270),调用者调用,此时关闭提供者的一个服务(8270)
-
存在现象:访问8170成功访问,不能访问8270
- RestTemplate:8170可访问,当访问8270时异常。稍等片刻只有8170.
-
略有卡顿,稍等片刻后,不再卡顿。
2 现象2:
-
提供者搭建集群(8170/8270),调用者调用,此时关闭提供者的所有服务
-
现象:无法访问
3 降级操作
-
添加坐标
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
-
修改yml文件,开启feign对sentinel的支持
feign: sentinel: enabled: true
-
修改启动类,开启feign
package com.czxy; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; /** * @author 薛慕昭 * @email 18716011269@163.com */ @SpringBootApplication @EnableDiscoveryClient //服务发现 @EnableFeignClients //远程调用 public class TestNacosConsumerApplication { public static void main(String[] args) { SpringApplication.run(TestNacosConsumerApplication.class, args ); } }
-
修改Feign实现
package com.czxy.feign; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; /** * @author 薛慕昭 * @email 18716011269@163.com */ // @FeignClient(value = "服务名", path = "controller配置的路径" ) @FeignClient(value = "service-provider", fallback = EchoFeignFallback.class ) public interface EchoFeign { // 与 nacos-provider-2.1>EchoController声明的方法的完全一致 @GetMapping("/echo/{string}") public String echo(@PathVariable String string); }
package com.czxy.feign; import org.springframework.stereotype.Component; /** * @author 薛慕昭 * @email 18716011269@163.com */ @Component public class EchoFeignFallback implements EchoFeign { @Override public String echo(String string) { return "降级处理:" + string; } }
-
关闭服务提供者,测试
- 注意:需重启服务
三. dashboard 控制面板
1 概述
-
Sentinel Dashboard 是一个
可视化
流控管理工具。 -
Sentinel Dashboard 是一个独立的项目,sentinel-dashboard-1.8.4.jar,需要使用 java -jar 运行
java -jar -Dserver.port=18080 sentinel-dashboard-1.8.4.jar
-
下载地址
https://github.com/alibaba/Sentinel/releases
2 配置dashboard
-
添加坐标(已有)
<!-- 降级 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
-
配置yml
#server.port=8071 #spring.application.name=service-consumer #spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 #spring.cloud.sentinel.transport.dashboard=192.168.152.153:8080 #端口号 server: port: 8071 spring: application: name: service-consumer #服务名 cloud: nacos: discovery: server-addr: 127.0.0.1:8848 #nacos服务地址 sentinel: transport: dashboard: 127.0.0.1:18080 feign: sentinel: enabled: true
-
测试
-
先访问资源
http://localhost:8071/feign/echo/123
-
dashboard 登录
-
查看控制面板
http://localhost:18080/
-
3 设置资源点(埋点)
-
通过 @SentinelResource 注解,设置监控点(定义控制资源、配置控制策略)
package com.czxy.nacos.controller; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.czxy.nacos.feign.TestFeign; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** * @author 薛慕昭 * @email 18716011269@163.com */ @RestController @RequestMapping("/feign") public class TestFeignController { @Resource private TestFeign testMyFeign; @RequestMapping(value = "/echo/{str}", method = RequestMethod.GET) @SentinelResource("/feign/echo") public String echo(@PathVariable String str) { return testMyFeign.echo(str); } }
-
测试
四. 限流
1 编写测试类
package com.czxy.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 薛慕昭
* @email 18716011269@163.com
*/
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/login")
public String login(String str) {
return "登录成功" + str;
}
@GetMapping("/register")
public String register(String str) {
return "注册成功";
}
}
2 限流方法
- 通过
@SentinelResource
注解的blockHandler
属性制定限流的处理函数
package com.czxy.nacos.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 薛慕昭
* @email 18716011269@163.com
*/
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/login")
// 限流设置
@SentinelResource(value="login", blockHandler = "loginBlockHandler")
public String login(String str) {
return "登录成功" + str;
}
public String loginBlockHandler(String str , BlockException e) {
return str + ": 请稍后重试";
}
@GetMapping("/register")
public String register(String str) {
return "注册成功";
}
}
3 限流操作
-
运行 sentinel-dashboard-1.8.4.jar
-
访问测试功能:http://localhost:8071/user/login?str=1234
-
通过 dashboard 设置限流
- QPS:一般指每秒查询率
-
连续快速2次访问测试功能
五. 熔断降级
1 降级方法
- 使用@SentinelResource注解的fallback属性来指定降级的方法名
package com.czxy.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.apache.commons.lang.math.RandomUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 薛慕昭
* @email 18716011269@163.com
*/
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/login")
// 限流设置
@SentinelResource(value="login", blockHandler = "loginBlockHandler")
public String login(String str) {
return "登录成功" + str;
}
public String loginBlockHandler(String str , BlockException e) {
return str + ": 请稍后重试";
}
@GetMapping("/register")
// 熔断降级
@SentinelResource(value="register", fallback = "registerFallback")
public String register(String str) {
int r = RandomUtils.nextInt(10);
if(r < 5) {
int i = 1 / 0;
}
return "注册成功";
}
public String registerFallback(String str) {
return str + ": 熔断降级";
}
}
2 测试
-
成功
-
熔断降级
3 降级操作
- 慢调用比例:
- RT:平均响应时间
- 比例阈值:
- 熔断时长:
- 最小请求数:
- 异常比例:每秒异常总数占通过量的比值超过阈值(DegradeRule 中的 count)之后,资源进入降级状态
- 异常数:当资源近 1 分钟的异常数目超过阈值之后会进行熔断
六. 限流和降级的区别?
- 限流是通过设置QPS(每秒查询率)/线程数,将超过阈值部分拒绝处理;
- 服务降级是监控请求响应时间、响应异常比例、异常数量;超过限定阈值,将进行服务降级熔断,一定时间内不可用;
结尾
k(String str) {
return str + “: 熔断降级”;
}
}
### 2 测试
* 成功
[外链图片转存中...(img-EtoFL8NX-1705283262451)]
* 熔断降级
[外链图片转存中...(img-SNdK9B8Y-1705283262451)]
### 3 降级操作
* 慢调用比例:
* RT:平均响应时间
* 比例阈值:
* 熔断时长:
* 最小请求数:
* 异常比例:每秒异常总数占通过量的比值超过阈值(DegradeRule 中的 count)之后,资源进入降级状态
* 异常数:当资源近 1 分钟的异常数目超过阈值之后会进行熔断
[外链图片转存中...(img-7eNiRPkH-1705283262452)]
## 六. 限流和降级的区别?
* 限流是通过设置QPS(每秒查询率)/线程数,将超过阈值部分拒绝处理;
* 服务降级是监控请求响应时间、响应异常比例、异常数量;超过限定阈值,将进行服务降级熔断,一定时间内不可用;
# 结尾
Sentinel的降级、限流、熔断等功能为我们构建健壮的分布式系统提供了强有力的支持。通过合理地设置各项保护和控制策略,我们可以更好地抵御恶劣环境下的挑战,保持系统的稳定和可靠。因此,在设计和实现分布式系统时,充分利用Sentinel的功能将是一个明智的选择,它将为系统的高可用性和稳定性保驾护航。