随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
1、sentinel的特征
2、sentinel的主要特性
sentinel的开源生态
sentinel 的架构图
3、sentinel的主要优势和特性
4、sentinel与spring cloud Hystrix 对比
Sentinel | Hystrix | |
---|---|---|
隔离策略 | 信号量隔离 | 线程池隔离/信号量隔离 |
熔断降级策略 | 基于响应时间或失败比率 | 基于失败比率 |
实时指标实现 | 滑动窗口 | 滑动窗口(基于 RxJava) |
规则配置 | 支持多种数据源 | 支持多种数据源 |
扩展性 | 多个扩展点 | 插件的形式 |
基于注解的支持 | 支持 | 支持 |
限流 | 基于 QPS,支持基于调用关系的限流 | 有限的支持 |
流量整形 | 支持慢启动、匀速器模式 | 不支持 |
系统负载保护 | 支持 | 不支持 |
控制台 | 开箱即用,可配置规则、查看秒级监控、机器发现等 | 不完善 |
常见框架的适配 | Servlet、Spring Cloud、Dubbo、gRPC 等 | Servlet、Spring Cloud Netflix |
5、sentinel分为两个部分
1、Sentinel控制台的下载
下载地址:https://github.com/alibaba/Sentinel/releases/tag/1.8.3
cmd 启动jar包
java -jar sentinel-dashboard-1.8.3.jar
浏览器输入:localhost:8080
账号密码 默认都是 sentinel
3、为服务打开sentinel的监控
引入sentinel依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>${spring-cloud-alibaba.version}</version>
</dependency>
专栏的上一篇文章已经为项目引入了sentinel的依赖,以及介绍了feign的使用 感兴趣的可以跳转
手把手教你搭建springcloud alibaba微服务–openfeign
yml文件添加sentinel相关配置
server:
port: 9090
spring:
application:
name: mdx-shop-user
cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: mdx
group: mdx
sentinel:
transport:
dashboard: localhost:8080 #配置Sentinel dashboard地址
feign:
sentinel:
enabled: true
启动user服务并访问user服务的测试接口
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("getOrderNo")
public String getOrderNo(String userId,String tenantId,HttpServletRequest request){
return userService.getOrderNo(userId,tenantId,request);
}
}
浏览器访问
http://localhost:9090/user/getOrderNo?userId=mdx123456&tenantId=123
1.1、流控规则的各个属性
资源名称就是我们的接口访问路径
然后我们一秒一次访问一下接口(正常)
http://localhost:9090/user/getOrderNo?userId=mdx123456&tenantId=123
可以看到正常返回数据
1.3、流控规则–关联流控模式
我们模拟一下流控模式中的关联模式
关联: 当关联的资源达到阈值时,就限流自己,也就是说关联的资源(接口),QPS为1时,一秒内被多次请求的时候,自己的接口就会被限流。
我们在user服务中创建一个关联接口 /user/sentinelB
@GetMapping("sentinelB")
public String sentinelB(){
return "我是关联接口";
}
然后修改一下流控规则
我们用jmeter模拟一下请求sentinelB接口
一秒3个请求并循环
在这期间我们访问/user/getOrderNo接口
发现被限流了
2.1、@SentinelResource的属性
2.2、按照资源名称的方式限流,并对限流流进行友好处理
我们修改一下/user/getOrderNo接口的代码,增加@SentinelResource注解,并做后续处理
演示代码:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("getOrderNo")
@SentinelResource(value = "getOrderNoResource",blockHandler = "getOrderNoBlockHandler",blockHandlerClass = UserController.class)
public String getOrderNo(String userId, String tenantId, HttpServletRequest request){
return userService.getOrderNo(userId,tenantId,request);
}
/**
* 限流后续操作方法
* @param e
* @return
*/
public static String getOrderNoBlockHandler(String userId, String tenantId, HttpServletRequest request,BlockException e){
String msg = "不好意思,前方拥挤,请您稍后再试";
return msg;
}
}
其中 getOrderNoResource 为资源名称,getOrderNoBlockHandler 为兜底方法的方法名称,blockHandlerClass = UserController.class 这个是兜底方法所在的类, 与资源方法在同一个类中 这属性可以省去,这里只是演示
注意:返回类型与原方法一致,参数类型需要和原方法相匹配,并在最后加上BlockException类型的参数
然后再修改一下流控规则,把资源名称换成我们注解中的 getOrderNoResource
快速访问我们的接口,http://localhost:9090/user/getOrderNo?userId=mdx123456&tenantId=123
发现返回的信息已经变成我们兜底方法自定义的返回提示了
3.1、熔断规则的几种策略
3.2、新建一个熔断规则
我们先写一个新的接口并且睡眠一秒,使用注解资源名称的形式,并创建自定义兜底方法
方法接口地址 /user/sentinelA
@GetMapping("/sentinelA")
@SentinelResource(value = "sentinelAResource" , fallback = "sentinelAResource", fallbackClass = UserSentinelResourceHandler.class)
public String sentinelA(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是sentinelA");
return "我是sentinelA";
}
创建单独的handler类来处理兜底方法
@Component
public class UserSentinelResourceHandler {
public static String sentinelAResource(Throwable throwable){
System.out.println("触发熔断,服务不可用");
return "触发熔断,服务不可用";
}
}
我们对以上添加的熔断规则解释一下:
在 2 秒的统计时间(统计时长)内,对资源接口的请求数大于 5 (最小请求数),请求响应时间(最大 RT)大于200毫秒的请求占比超过比例阈值 0.1 ,则下一个请求开始触发熔断,熔断时长是 5 秒,也就是 5 秒内,熔断器是打开状态,这期间的请求都会触发熔断,5秒过后熔断器关闭,此时熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
RT(平均响应时间): 当1s内持续进入5个请求,且对应请求的平均响应时间(秒级)均超过阈值,那么在接下来的时间窗口期内,对该方法的调用都会自动的熔断。注意Sentinel默认统计的RT上限是4900ms,超出此阈值的都会算作4900ms,若需要更改上限可以通过启动配置项-Dcsp.sentinel.statistic.max.rt=xxx来配置
然后我们测试一下
模拟下并发,一秒十个请求循环调用
我们发现触发阈值之后 已经触发了熔断机制,如下
热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的数据,并对其访问进行限制,比如对某个商品id进行限制,或者对某个用户id进行限制
3.1、热点规则属性
参数索引:方法中参数的索引第几个参数
单机阈值:每秒达到单机阈值的数量就会触发兜底方法
4.1、新建一个热点规则
我们先创建一个测试方法,使用注解资源名称的形式,并创建自定义兜底方法
/**
* 测试centinel热点规则限流
* @param userId
* @param shopId
* @return
*/
@GetMapping("/hotspot")
@SentinelResource(value = "hotspotResource" , blockHandler = "hotspotResource", blockHandlerClass = UserSentinelResourceHandler.class)
public String hotspot(@RequestParam(value = "userId" ,required = false) String userId,
@RequestParam(value = "shopId" ,required = false) String shopId){
System.out.println("我是hotspot");
return "我是hotspot";
}
兜底方法
public static String hotspotResource(String userId, String shopId,BlockException blockException){
System.out.println("您被认为恶意访问,触发热点限流");
return "您被认为恶意访问,触发热点限流";
}
然后我们在控制台新建热点规则
其中参数索引 0 代表的就是userId这个参数
我们访问一下接口
先访问带shopId的(一秒内多次访问) http://localhost:9090/user/hotspot?shopId=4
正常返回
再访问下带userId参数的(一秒内多次访问) http://localhost:9090/user/hotspot?userId=4
返回降级函数的内容
系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性
如果配置了系统规则,所有的接口都会被限流
这里系统规则就不演示了,关于sentinel还有很多规则,策略和属性,大家有兴趣可以自行研究下。
关于sentinel的使用篇就到这里了。
创作不易,点个赞吧
最后的最后送大家一句话
白驹过隙,沧海桑田
与君共勉
上一篇文章
springcloud alibaba微服务 – openfeign的使用(保姆级)
下一篇文章
springcloud alibaba – seata原理和使用
项目地址
mdx-shop gitee地址