关于Sentinel
背景
不管是再网上还是再现实生活中,都有一个相同的概念"限流",比如,某品牌搞活动,一折出售商品,很多人听到消息后,凌晨就去排队,人流量越来越大,为了保证消费者的安全等问题,管理人员就会对消费者进行管理,比如限制每次进入商场的人数等手段.这就是限流,再比如在双十一,各大电商搞促销,尤其是凌晨12点,会出现一次消费顶峰,那么为了让消费者可以正常购物,只能说将大部分服务器投入到当中,部分服务器限制流量.那么限流是如何做到的呢?那就不得不说今天的主角Sentinel了
概述
Sentinel (分布式系统的流量防卫兵) 是阿里开源的一套用于服务容错的综合性解决方案。它以流量为切入点, 从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。
Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景, 例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
Sentinel核心分为两个部分:
核心库(Java 客户端):能够运行于所有 Java 运行时环境,同时对Dubbo /Spring Cloud 等框架也有较好的支持。
控制台(Dashboard):基于 Spring Boot 开发,打包后可以直接运行。
安装和使用
大家可以搜索一下安装问题,安装好后需要在sentinel对应的目录打开cmd输入以下命令
java -Dserver.port=8180 -Dcsp.sentinel.dashboard.server=localhost:8180 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.1.jar
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZdQUQQbq-1646268935233)(C:\Users\11500\AppData\Local\Temp\1646218917086.png)]
出现这样的内容说明成功了.
访问Sentinel
启动成功后在浏览器地址栏输入:localhost:8180即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9WFU825n-1646268935234)(C:\Users\11500\AppData\Local\Temp\1646219014525.png)]
默认账号密码都是sentinel
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LQ4AScqU-1646268935234)(C:\Users\11500\AppData\Local\Temp\1646219050784.png)]
登陆后就会显示这个图片
Sentinel限流入门
在系统中,数据可连接池,线程池,nginx等都会设置一个瞬时并发的限定,这本身就是一个限流的作用,就是为了放置恶意的访问攻击等.
开始使用
第一步:Sentinel应用与服务提供方,即我们之前创建的sca-qty-provider,在此包下的pom文件中添加以下依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
第二步:修改bootstrap.yml文件,注意格式
server:
port: 8083
spring:
application:
name: sca-qty-provider
cloud:
sentinel:
transport:
dashboard: localhost:8180
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
file-extension: yml
第三步:在controller包下创建一个测试类
@RestController
@RequestMapping("/provider")
public class ProviderSentinelController {
@GetMapping("/sentinel01")
public String doSentinel01(){
return "sentinel01 test";
}
}
第四步:启动服务,并访问相应服务,多次点击刷新
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IgdDns16-1646268935234)(C:\Users\11500\AppData\Local\Temp\1646219729410.png)]
第五步:查看并设置Sentinel
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uJSe99M2-1646268935235)(C:\Users\11500\AppData\Local\Temp\1646219819013.png)]
此时在实时监控就可以看到这个服务访问了几次
流控设置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k6ypl4mV-1646268935235)(C:\Users\11500\AppData\Local\Temp\1646219942783.png)]
点击簇点链路就会看到刚刚的服务path,在此页面我们会讲到其中三个功能:1.流控 2.降级 3.热点,首先我们来看流控.
####直接模式
第一步:点击流控
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ddDF4JLr-1646268935235)(C:\Users\11500\AppData\Local\Temp\1646220082008.png)]
解释:
资源名:即服务的path
针对来源:默认即可
阈值类型:
1)QPS: 每秒查询率QPS是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准,在因特网上,作为域名系统服务器的机器的性能经常用每秒查询率来衡量。 简单点来说就是每秒服务访问次数
2)线程数:额,就是访问线程数~
单机阈值:我们设置为1,意思就是每秒钟访问1次就会被限流,
流控模式:直接,关联,链路,默认是直接
流控效果:快速失败,Warm Up,排队等待
第二步:点击新增
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R3vFw5mA-1646268935236)(C:\Users\11500\AppData\Local\Temp\1646220479347.png)]
第三步:刷新服务页面,看效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cLi0R2eT-1646268935236)(C:\Users\11500\AppData\Local\Temp\1646220576021.png)]
页面显示"Blocked by Sentinel (flow limiting)",说明Sentinel起作用了,限制了此服务.
关联模式
关联那么肯定是涉及到一个以上的服务了,什么意思呢,就是当某个服务访问超过了QPS设置的值,就会限流与之相关联的服务,什么场景下会有这种操作,比如在电商大促期间,订单业务有两个服务,订单写入服务以及订单读取服务,此时订单写入服务等级一定比订单读取要重要,这时就可以写入服务写在关联资源,资源名写读取资源
第一步:在ProviderSentinelController中添加测试类
@GetMapping("/sentinel02")
public String doSentinel02(){
return "sentinel02 test";
}
第二步:重启服务
第三步:刷新服务页面
第四步:设置Sentinel
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PZ7WRDnx-1646268935236)(C:\Users\11500\AppData\Local\Temp\1646222075222.png)]
这时候,当01访问量大时就会限流02,我们在另一个页面打开01服务进行测试,同时刷新01,02服务
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rIj8RHi7-1646268935236)(C:\Users\11500\AppData\Local\Temp\1646222586784.png)]
01访问量大,02就被限流
链路模式
链路模式只记录指定的链路入口流量,假如有多个服务都调用指定资源,超出了指定的阈值,那么就限流.注意被调用的方法需要使用注解@SentinelResource,不同服务去调用,a服务设置了链路,b服务是不受影响的
第一步:创建业务类
@Service
public class ResourceService {
@SentinelResource("doGetResource")
public String doGetResource(){
return "doGetResource";
}
}
第二步:在ProviderSentinelController 中创建两个服务,相当于两个业务
@Autowired
private ResourceService resourceService;
@GetMapping("/sentinel03")
public String doSentinel03(){
resourceService.doGetResource();
return "sentinel03 test";
}
@GetMapping("/sentinel04")
public String doSentinel04(){
resourceService.doGetResource();
return "sentinel04 test";
}
第三步:重启服务,刷新业务
第四步:设置Sentinel
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eXhUQBnl-1646268935237)(C:\Users\11500\AppData\Local\Temp\1646223672146.png)]
第五步:再次访问服务03,04都会报500,并没有实现两条链路互不相干
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JNPozG2V-1646268935237)(C:\Users\11500\AppData\Local\Temp\1646223717541.png)]
第六步:配置bootstrap.yml,重启服务器,再次测试
sentinel:
transport:
dashboard: localhost:8180
web-context-unify: false # 聚合URL默认是true,所以不管是哪条链路访问都会被限流,改为false即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3kDpNLOL-1646268935237)(C:\Users\11500\AppData\Local\Temp\1646224154903.png)]
此时两条链路分开了,只设置03链路进行测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YcFFDFLi-1646268935237)(C:\Users\11500\AppData\Local\Temp\1646224283123.png)]
测试04链路
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TyHEmln9-1646268935238)(C:\Users\11500\AppData\Local\Temp\1646224306786.png)]
优化
当链路被限流时,用户在页面看到500,这样的效果很不理想,我们通过自定义拦截异常,修改返回内容显示在页面上
在controlle中创建异常拦截器
@RestController
public class SentinelExceptionController implements BlockExceptionHandler {
public SentinelExceptionController(){
}
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
httpServletResponse.setContentType("text/html;charset=utf-8");
httpServletResponse.setStatus(429);
PrintWriter writer = httpServletResponse.getWriter();
String msg = "访问太频繁,稍后再试";
if(e instanceof DegradeException){
msg = "服务不可用稍后再试";
}else if(e instanceof AuthorityException){
msg = "拒绝访问";
}
// 还可以根据异常类型添加msg
writer.println(msg);
writer.flush();
writer.close();
}
of DegradeException){
msg = “服务不可用稍后再试”;
}else if(e instanceof AuthorityException){
msg = “拒绝访问”;
}
// 还可以根据异常类型添加msg
writer.println(msg);
writer.flush();
writer.close();
}
需要实现BlockExceptionHandler并重写handle方法,根据异常类型返回