sentinel 可以完成的功能: 绿色方框列出的部分Sentinel 的开源生态:
拿旅游景点举个示例,每个旅游景点通常都会有最大的欢迎量,不可能无穷制的放游 客进入,比如长城每天只卖八万张票,超过八万的游客,无法买票进入,因为假如超过 八万人,景点的工作职员可能就忙不过来,过于拥挤的景点也会影响游客的体验和心情, 并且还会有安全隐患;只卖 N 张票,这就是一种限流的手段
除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,大概第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。假如依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。
- 在调用系统的时候,假如调用链路中的某个资源出现了不稳定,最终会导致请求发生 堆积,如下图:
- 熔断降级可以解决这个问题,所谓的熔断降级就是当检测到调用链路中某个资源出现不 稳定的表现,例如请求响应时间长或非常比例升高的时候,则对这个资源的调用进行限 制,让请求快速失败,制止影响到其它的资源而导致级联故障。
Sentinel 系统自顺应保护从整体维度对应用入口流量进行控制,结合应用的 Load、总体平均 RT、入口 QPS 和线程数等几个维度的监控指标,让系统的入口流量和系统的负载达到一个均衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
根据系统能够处置惩罚的请求,和答应进来的请求,来做均衡,追求的目标是在系统不被 拖垮的情况下, 进步系统的吞吐率
某瞬时来了大流量的请求, 而假如此时要处置惩罚全部请求,很可能会导致系统负载过高, 影响稳定性。但其实可能反面几秒之内都没有消息投递,若直接把多余的消息丢掉则没 有充实利用系统处置惩罚消息的本领2. Sentinel 控制台
Sentinel 的 Rate Limiter 模式能在某一段时间间隔内以匀速方式处置惩罚这样的请求, 充实利 用系统的处置惩罚本领, 也就是削峰填谷, 保证资源的稳定性
注意:Sentinel 控制台目前仅支持单机部署。Sentinel 控制台项目提供 Sentinel 功能全集示例,不作为开箱即用的生产环境控制台,若盼望在生产环境使用请根据文档自行进行定制和改造。
浏览器输入: http://localhost:9090, 用户和密码都是 sentinel
启动 Nacos Server 8848进入到 Sentinel 查看实时监控结果, http://localhost:8080/#/dashboard
启动 Sentinel8080 控制台/Sentinel dashboard
启动 member-service-nacos-provider-10004
浏览器: localhost:10004/member/get/1
Sentinel 控制台监控页面,浏览器输入: http://localhost:10004/member/get/1
- 对 QPS 而言,假如 1秒内,客户端发出了2次请求,就到达阈值,从而限流。 QPS 表示: 每秒钟的请求数量
- 对线程而言,假如在 1秒内,客户端降发出了 2 次请求,不一定达到线程限制的阈值,为什么呢,假设我们 1次请求背景会创建一个线程,但是这个请求完成时间是 0.1秒(可以视为该请求对应的线程存活 0.1 秒),
所以当客户端第2次请求时,(比如客户端是在 0.3 秒发出的),这时第1个请求的线程就是已经结束了,因此就没有达到线程的阈值,也不会
限流。
- 可以这样理解,假如 1 个请求对应的线程平均实验时间为 0.1 那么,就相当于 QPS 为 10
是否集群:不需要集群。
演示: 当调用 member-service-nacos-provider-10004 的 /member/get/ 接口/API 时,限制 1 秒内最多访问 1 次,否则直接失败,抛非常.配置实现步骤:
启动 Nacos Server 8848Sentinel 控制台监控页面:
启动 Sentinel909控制台/Sentinel dashboard
启动 member-service-nacos-provider-10004
浏览器: localhost:10004/member/get/1
方案一 :在sentinel中 /member/get?id=1 和 /member/get?id=2 被统一认为是 /member/get 所以只要对/member/get 限流就OK了.
复制代码
- 方案1: 在 sentinel 中/member/get?id=1 和 /member/get?id=2 被统一认为是 /member/get 所以
- 只要对 /member/get 限流就OK了。
- /**
- * 这里我们使用 url占位符 + @PathVariable
- *
- * @param id
- * @return
- */
- //@GetMapping("/member/get/{id}")
- // 在sentinel中 /member/get?id=1 和 /member/get?id=2 被统一认为是 /member/get 所以只要对/member/get 限流就OK了. 进行统一的限流
- @RequestMapping(value = "/member/get/", params = "id", method = RequestMethod.GET)
- //public Result getMemberById(@PathVariable("id") Long id, HttpServletRequest request) {
- public Result getParameter(Long id) {
- Member member = memberService.queryMemberById(id);
- //String color = request.getParameter("color");
- //String age = request.getParameter("age");
- // 模拟超时 ,这里暂停 5秒
- /* try {
- TimeUnit.SECONDS.sleep(5);
- } catch (Exception e) {
- e.printStackTrace();
- }*/
- // 使用 Result 把查询到的结果返回
- if (member != null) {
- //return Result.success("查询会员成功 member-service-nacos-provider-10004 color" + color + "age" + age, member);
- return Result.success("查询会员成功 member-service-nacos-provider-10004 color",member);
- } else {
- return Result.error("402", "ID" + id + "不存在 member-service-nacos-provider-10004 ");
- }
- }
方案二: URL 资源洗濯
可以通过 UrlCleaner 接口来实现资源洗濯,也就是对于 /member/get/{id} 这个 URL,
我们可以统一归集到 /member/get/* 资源下,具体的代码实现如下: 需要实现 UrlCleaner接口
并重写此中的 clean 方法即可。
5.2 流量控制实例-线程数复制代码
- package com.rainbowsea.springcloud.controller;
- import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner;
- import org.apache.commons.lang3.StringUtils;
- import org.springframework.stereotype.Component;
- /**
- * 方案2: URL 资源清洗
- * 可以通过 UrlCleaner 接口来实现资源清洗,也就是对于 /member/get/{id} 这个 URL,
- * 我们可以统一归集到 /member/get/* 资源下,具体的代码实现如下: 需要实现 UrlCleaner接口
- * 并重写其中的 clean 方法即可
- */
- @Component // 注意:同样要被 Spring IOC 容器管理起来
- public class CustomUrlCleaner implements UrlCleaner {
- @Override
- public String clean(String originUrl) {
- // 判断字符串是否为空 Null
- // 特别注意: StringUtils.isBlank 是在:org.apache.commons.lang3.StringUtils 包下的
- if (StringUtils.isBlank(originUrl)) {
- return originUrl;
- }
- if (originUrl.startsWith("/member/get")) {
- // 1.如果请求的是接口 /member/get 开头的,比如: /member/get/1
- // 2.给sentinel 的返回的资源名就是 /member/get/*
- // 3. 在 sentinel 对 /member/get/* 添加流控规则即可
- return "/member/get/*";
- }
- return originUrl;
- }
- }
当调用 member-service-nacos-provider-10004 的 /member/get/* 接口/API 时,限制 只有一个工作线程,否则直接失败,抛非常.配置实现步骤:
启动 Nacos Server 8848
启动 Sentinel8080 控制台/Sentinel dashboard
启动 member-service-nacos-provider-10004
浏览器: localhost:10004/member/get/1
结果页面:
浏览器输入: http://localhost:10004/member/get/1 , 快速刷新, 页面显示正常(缘故原由 是服务实验时间很短,刷新下一次的时候,启动的工作线程,已经完成)
为了看到结果,我们修改下 com/rainbowsea/springcloud/controller/MemberController.java。模拟延时。
注意事项和细节:复制代码
- // 让线程休眠1s,模拟执行时间
- try {
- TimeUnit.MILLISECONDS.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
重启 member-service-nacos-provider-10004 , 注意需要重新加入流控规则.复制代码
- @GetMapping("/member/get/{id}")
- public Result getMemberById(@PathVariable("id") Long id) {
- Member member = memberService.queryMemberById(id);
- //String color = request.getParameter("color");
- //String age = request.getParameter("age");
- // 让线程休眠1s,模拟执行时间
- try {
- TimeUnit.MILLISECONDS.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(" enter getMemberById... 当前线程id = " + Thread.currentThread().getId() + "时间 = " + new Date());
- // 使用 Result 把查询到的结果返回
- if (member != null) {
- //return Result.success("查询会员成功 member-service-nacos-provider-10004 color" + color + "age" + age, member);
- return Result.success("查询会员成功 member-service-nacos-provider-10004 color" + member);
- //return Result.success("查询会员成功 member-service-nacos-provider-10004 color",member);
- } else {
- return Result.error("402", "ID" + id + "不存在 member-service-nacos-provider-10004 ");
- }
- }
浏览器输入: http://localhost:10004/member/get/1 , 快速刷新 页面出现非常.
假如一个线程平均实验时间 为 0.05 秒,就说明在 1秒钟,可以实验 20次(相当于 QPS 为 20)5.3 流量控制实例-关联
假如一个线程平均实验时间 为 1秒,说明 1 秒钟,可以实验 1次数(相当于 QPS 为1)
假如一个线程平均实验时间 为 2 秒,说明2秒钟内,才能实验1次请求。
这里使用 postman 模拟高并发访问/t2 ;然后在 postman 实验高并发访问/t2没有结束时,去访问 /t1 才能看到流控非常出现。t1被流控了
启动 Nacos Server 8848
启动 Sentinel8080 控制台/Sentinel dashboard
启动 member-service-nacos-provider-10004
Postman 模拟高并发访问/t2
创建新的 http request
保存 request 到 一个新的 collection 中
设置 run collection 参数, 并运行
浏览器访问: http://localhost:10004/t1注意事项和细节:
启动 Nacos Server 8848
启动 Sentinel8080 控制台/Sentinel dashboard
启动 member-service-nacos-provider-10004
浏览器: localhost:10004/t2
浏览器访问 http://localhost:10004/t2 快速刷新页面,在前 3 秒,会出现流控非常, 后 3 秒就正常了(假如你刷新非常快 QPS>9 , 仍然会出现流控非常)
注意事项和细节:
启动 Nacos Server 8848
启动 Sentinel8080 控制台/Sentinel dashboard
启动 member-service-nacos-provider-10004
浏览器: localhost:10004/t2
- 浏览器访问 http://localhost:10004/t2 快速刷新页面 9 次,观察前台/背景输出的情
况
6. Sentinel 熔断降级
浏览器访问 http://localhost:10004/t2 快速刷新页面 20 次,当请求等待时间超过 10S, 仍然出现流控非常
- 输出结果分析
- 没有报错误
- 背景请求排队实验,每隔1s 匀速实验
梳理:
- 熔断夸大的是服务之间的调用能实现自我规复的状态
- 限流是从系统的流量入口思量, 从进入的流量上进行限制 达到保护系统的作用。
- 降级, 是从系统业务的维度思量,流量大了大概频仍非常, 可以牺牲一些非焦点业务,保 护焦点流程正常使用。
6.1 熔断策略
- 熔断是降级方式的一种
- 降级又是限流的一种方式
- 三者都是为了通过一定的方式在流量过大大概出现非常时, 保护系统的手段
非常比例:
- 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置答应的 慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用
- 当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的 比例大于阈值,则接下来的熔断时长内请求会自动被熔断
- 熔断时长后, 熔断器会进入探测规复状态(HALF-OPEN 状态),若接下来的一个请求响 应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断
- 配置参考:
启动 Nacos Server 8848
启动 Sentinel8080 控制台/Sentinel dashboard
启动 member-service-nacos-provider-10004
Postman 测试
- 先创建 collection , 也可以在已经存在的 collection 进行修改。
点击 Run sentinel
浏览器访问: http://localhost:10004/t3
停止 Postman
浏览器访问: http://localhost:10004/t3 , 结果正常了(需要在停止 Postman 10s 后)注意事项和细节:
启动 Nacos Server 8848
启动 Sentinel8080 控制台/Sentinel dashboard
启动 member-service-nacos-provider-10004
Postman 测试:
- 先创建给 collection , 也可以在已经存在的 collection 进行修改, 一定确保更新成功.
- 点击 Run sentinel
- 浏览器访问: http://localhost:10004/t4
- 停止 Postman
- 浏览器访问: http://localhost:10004/t4 , 结果正常了(一次返回非常,一次返回正确结果)
注意事项和细节
7.1 热门 Key 限流-实例
- 热门参数限流会统计传入参数中的热门参数,并根据配置的限流阈值与模式,对包含 热门参数的资源调用进行限流。
- 热门参数限流可以看做是一种特殊的流量控制,仅对包含热门参数的资源调用生效
- Sentinel 利用 LRU 策略统计最近最常访问的热门参数,结合令牌桶算法来进行参数 级别的流控 https://blog.csdn.net/qq_34416331/article/details/106668747
- 热门参数限流支持集群模式
启动 Nacos Server 8848配置步骤:
启动 Sentinel8080 控制台/Sentinel dashboard 10.6.4.3.3
启动 member-service-nacos-provider-10004
图示解读:系统规则:
- 系统处置惩罚请求的过程想象为一个水管,到来的请求是往这个水管灌水,当系统处置惩罚顺 畅的时候,请求不需要排队,直接从水管中穿过,这个请求的RT是最短的;
- 反之,当请求堆积的时候,那么处置惩罚请求的时间则会变为:排队时间 + 最短处置惩罚时间
启动 Nacos Server 8848
启动 Sentinel8080 控制台/Sentinel dashboard
启动 member-service-nacos-provider-10004
浏览器: http://localhost:10004/t1
- 每个@SentinelResource 对应一个非常处置惩罚方法,会造成方法很多
- 非常处置惩罚方法和资源请求方法在一起,不利于业务逻辑的分离
- 解决方案-> 自定义全局限流处置惩罚类.
创建 com/rainbowsea/springcloud/handler/CustomGlobalBlockHandler.java
修改 com/rainbowsea/springcloud/controller/MemberController.java 增长方法 t6()复制代码
- package com.rainbowsea.springcloud.handler;
- import com.alibaba.csp.sentinel.slots.block.BlockException;
- import com.rainbowsea.springcloud.entity.Result;
- /**
- * 1. CustomGlobalBlockHandler : 全局限流处理类
- * 2. 在 CustomGlobalBlockHandler 类中,可以编写限流处理方法,但是要求方法是static
- */
- public class CustomGlobalBlockHandler {
- public static Result handlerMethod1(BlockException blockException) {
- return Result.error("400", "客户自定义异常/限流处理方法handlerMethod1");
- }
- public static Result handlerMethod2(BlockException blockException) {
- return Result.error("401", "客户自定义异常/限流处理方法handlerMethod2");
- }
- }
配置实现步骤复制代码
- private static int num = 0; // 执行的计数器-static静态
- // 这里我们使用全局限流处理类,显示限流信息
- /**
- * value="t6" 表示 sentinel 限流资源的名字
- * blockHandlerClass = CustomGlobalBlockHandler.class:全局限流处理类
- * blockHandler = "handlerMethod1" 指定使用全局限流处理类哪个方法,来处理限流信息
- * fallbackClass = CustomGlobalFallbackHandler.class 全局 fallback处理类
- * fallback = "fallbackHandlerMethod1" 指定使用全局fallback处理类哪个方法来处理java异常/业务异常
- * exceptionsToIgnore = {NullPointerException.class}
- *
- * @return
- */
- @GetMapping("/t6")
- @SentinelResource(value = "t6",
- // //设置处理sentinel 控制台违规后的异常 blockHand
- blockHandlerClass = CustomGlobalBlockHandler.class,
- blockHandler = "handlerMethod1",
- //设置处理Java异常的 fallback
- fallbackClass = CustomGlobalFallbackHandler.class,
- fallback = "fallbackHandlerMethod1",
- // 如果希望忽略某个异常,可以使用 exceptionsToIgnore,这里忽略NullPointerException异常
- exceptionsToIgnore = {NullPointerException.class}
- )
- public Result t6() {
- log.info("执行t6() 线程id={}", Thread.currentThread().getId());
- // 假定;当访问t6资源次数是5倍数时,就出现Java异常
- if (++num % 5 == 0) {
- throw new NullPointerException("null 指针异常 num=" + num);
- }
- if (++num % 6 == 0) {
- throw new RuntimeException("RuntimeException num=" + num);
- }
- return Result.success("200", "t6()执行OK~~~");
- }
为资源 /t6 增长流控规则,方便测试
- 在流控规则菜单,可以看到新增规则
测试
启动 Nacos Server 8848
启动 Sentinel8080 控制台/Sentinel dashboard
启动 member-service-nacos-provider-10004
浏览器: http://localhost:10004/t6
- 浏览器输入: http://localhost:10004/t6 , 假如 QPS 没有超过 1, 返回正常结果
9.1 @ fallback
- 浏览器输入: http://localhost:10004/t6 , 假如 QPS 超过 1, 断路器打开,返回自定义限流处置惩罚方法信息。
启动 Nacos Server 8848
启动 Sentinel8080 控制台/Sentinel dashboard
启动 member-service-nacos-provider-10004
浏览器: http://localhost:10004/t6
浏览器输入: http://localhost:10004/t6 , 访问次数不是 5 的倍数, 返回正常结果
浏览器输入: http://localhost:10004/t6 , 访问次数是 5 的倍数 返回 fallback 指定方法
,信息
为资源 /t6 增长流控规则,方便测试
在流控规则菜单,可以看到新增规则
浏览器输入: http://localhost:10004/t6 , 假如访问 QPS 大于 1 , 由 blockHandler 指 定的方法处置惩罚,访问次数是 5 的倍数, 由 fallback 指定方法处置惩罚, 其它情况返回正常的结果.
9.2 @exceptionsToIgnore 忽略
“在这个末了的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的范畴奋斗。感谢你们,我们总会在某个时刻再次相遇。”
欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) | Powered by Discuz! X3.4 |