西安网站策划设计,做任务打字赚钱的网站,东莞市天气,政民互动平台SpringCloudAlibaba Sentinel降级和熔断
接着上篇文章的内容#xff0c;在Sentinel中如何进行降级和熔断呢#xff1f;
熔断降级规则 降级规则 在Sentinel中降级主要有三个策略#xff1a;RT、异常比例、异常数#xff0c;也是针对某个资源的设置。而在1.8.0版本后RT改为…SpringCloudAlibaba Sentinel降级和熔断
接着上篇文章的内容在Sentinel中如何进行降级和熔断呢
熔断降级规则 降级规则 在Sentinel中降级主要有三个策略RT、异常比例、异常数也是针对某个资源的设置。而在1.8.0版本后RT改为了慢调用比例
需要设置允许的慢调用 RT即最大的响应时间请求的响应时间大于该值则统计为慢调用。当单位统计时长statIntervalMs内请求数目大于设置的最小请求数目并且慢调用的比例大于阈值则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态HALF-OPEN 状态若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断若大于设置的慢调用 RT 则会再次被熔断。
RT表示该资源1s内处理请求的平均响应时间。
注意RT值的上限时4900ms及时超过也是4900ms如需自定义可以在启动sentinel时增加参数
-Dcsp.sentinel.statistic.max.rtx慢调用比例 依旧是在簇点链路的列表视图选择/sentinelTest一行进入熔断设置参数如图 RT设置为800ms熔断时长设置为20s为了测试效果把接口睡眠1s。
RequestMapping(/sentinelTest)
public String sentinelTest() throws InterruptedException {Thread.sleep(1000);return sentinel-consumer9001 sentinelTest RandomUtils.nextInt(0, 1000);
}解读响应时间超过RT值的请求被称为慢调用。在单位时间(上图的统计时长1s)内请求的数量大于最小请求数(5)且慢调用的比例阈值此资源进入熔断状态(20s内不可用)。
Jmeter请求/sentinelTest使用10个线程执行100次结果。 前面几个请求是正常返回数据后面全部降级处理直接返回提示信息(此时该资源已经进入了熔断状态可以理解为家里的电闸给关了必须重新打开电闸才能恢复使用电力)。后面这个资源无论怎样被调用都无法进入接口直接返回提示。 异常比例 当单位统计时长statIntervalMs内请求数目大于设置的最小请求数目并且异常的比例大于阈值则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态HALF-OPEN 状态若接下来的一个请求成功完成没有错误则结束熔断否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0]代表 0% - 100%
表示请求该资源的异常总数占比。先模拟一个异常
RequestMapping(/sentinelTest)
public String sentinelTest() {int i 1 / 0; // 除数为0return sentinel-consumer9001 sentinelTest RandomUtils.nextInt(0, 1000);
}设置规则 解读当1s内请求数量5且异常的比例大于80%熔断20s
调用资源 前几个请求正常请求返回异常提示而后面的所有请求直接被拒绝访问。 异常数 该资源近1分钟内的异常数量。 解读当1s内请求数量5且异常的数量10熔断20s
经过熔断时长后熔断器会进入探测恢复状态HALF-OPEN 状态若接下来的一个请求成功完成没有错误则结束熔断否则会再次被熔断。 当到11个请求仍然是异常时直接熔断。
系统规则
之前的所有规则都是针对某个资源(接口)而言的后面我们将针对整个应用设置系统规则。相对更加粗粒度属于应用级别的入口流量控制。那么相对应的也有几种规则
LOAD负载当系统负载超过设定值且发现线程数超过预估系统容量就会触发保护机制。RT整个应用上所有资源平均的响应时间而不是固定某个资源线程数设定整个系统所能使用的业务线程数阈值不固定某个资源入口QPS整个应用所有的每秒处理的请求数CPU使用率这个应用占用的CPU的百分比
使用时可以根据服务器的情况设置即可。
授权规则
授权规则是根据调用方判断调用资源的请求是否应该被允许访问。Sentinel提供了黑白名单的授权类型白名单表示允许调用资源黑名单则不允许调用资源。
在java中实现相关的接口将返回值交给sentinel处理。注意这里是在服务提供者方设置的
Component
public class CustomRequestOriginParser implements RequestOriginParser {Overridepublic String parseOrigin(HttpServletRequest httpServletRequest) {String origin httpServletRequest.getParameter(origin); // 区分来源本质通过request域获取来源标识if (StringUtils.isEmpty(origin)) {throw new RuntimeException(origin不能为空);}return origin; // 将返回的结果交给sentinel处理}
}然后配置个授权规则 资源名/test设置app为黑名单
当请求provider服务上的接口时若origin为空则会被拒绝访问若originapp时仍会被拒绝而其他的值则是可以访问
D:\springcloud\doccurl localhost:8002/test?originapp
Blocked by Sentinel (flow limiting)
D:\springcloud\doccurl localhost:8002/test?originpc
sentinel-provider8002 test()921使用SentinelResource注解
之前主要是利用Sentinel仪表板控制一些参数保护应用。后面我们使用SentinelResource注解根据实际情况实现定制化功能对应用的保护更加细粒度。
现在限制达到阈值时直接提示Blocked by Sentinel(flow limiting)提示不太友好需要实现更精细化的控制。 blockHandler属性–负责响应控制面板配置 添加一个接口/blockHandlerTest资源名为blockHandlerTest如果违反Sentinel控制台的规则则进入blockHandlerTestHander。
RequestMapping(/blockHandlerTest)
SentinelResource(value blockHandlerTest, blockHandler blockHandlerTestHandler)
public String blockHandlerTest(String params) {return Test#blockHandlerTest RandomUtils.nextInt(0, 1000);
}public String blockHandlerTestHandler(String params, BlockException bl) {return Test#blockHandlerTest RandomUtils.nextInt(0, 1000) bl.getMessage();
}注意blockHandlerTestHandler方法的返回值要和原方法一致并且除了原有的参数还要带上BlockException的参数
设置一个流控在SentinelResouce注解中我们把资源名设置为blockHandlerTest那么设置流控也是针对这个资源设置让后面的请求进入我们自定义的处理中。 可以看到流控超过阈值后其他的所有请求都是走的我们自定义的处理器。 热点规则 在一段时间内访问很频繁的资源是热点资源需要针对资源做参数化定制。
RequestMapping(/testHotKeyA)
SentinelResource(value testHotKeyA, blockHandler blockTestHotKeyA)
public String testHotKeyA(RequestParam(value orderId, required false) String orderId,RequestParam(value userId, required false) String userId) {return Test#testHotKeyA RandomUtils.nextInt(0, 1000);
}public String blockTestHotKeyA(String orderId, String userId, BlockException bl) {return Test#blockTestHotKeyA RandomUtils.nextInt(0, 1000) bl.getMessage();
}去sentinel页面上加一个热点key规则 索引从0开始那么获取的就是我们的orderId参数在调用/testHotKeyA时要加上oderId参数否则不生效。 正确进入处理。
同时我们可以对热点资源具体的某个参数值做阈值限制。 上图是对orderId为111或222时阈值设置为500.再次测试基本上不会进入自定义的处理中。但是为其他值时还是会进入我们的自定义处理。
fallback处理
前面是针对违反sentinel控制台规则做的处理那么当我们的业务层面出现问题时要做异常回滚等则要使用fallback处理。同样是SentinelResource中的属性。sentinel-1.6.0之前的版本是不支持针对业务异常处理的
RequestMapping(/fallbackTest)
SentinelResource(value fallbackTest, fallback fallbackHandler)
public String fallbackTest(String params) {int i 1 / 0;return Test#fallbackTest RandomUtils.nextInt(0, 1000);
}public String fallbackHandler(String params) {return Test#fallbackHandler RandomUtils.nextInt(0, 1000);
} 所有的请求都进入到异常处理的方法中了。 fallbackblockHandler RequestMapping(/sentinelUnionTest)
SentinelResource(value sentinelUnionTest, fallback sentinelUnionTestFallback, blockHandler sentinelUnionTestBlockHandler)
public String sentinelUnionTest(String params) {int i 1 / 0;return Test#fallbackTest RandomUtils.nextInt(0, 1000);
}public String sentinelUnionTestFallback(String params) {return Test#sentinelUnionTestFallback RandomUtils.nextInt(0, 1000);
}public String sentinelUnionTestBlockHandler(String params, BlockException bl) {return Test#sentinelUnionTestBlockHandler RandomUtils.nextInt(0, 1000) bl.getMessage();
}对sentinelUnionTest资源设置流控调用接口观察结果 第一个接口是正常进入到了fallback处理然后后面的请求因为超过阈值直接进入block处理中了。 忽略异常–exceptionsToIngnore fallback定义的方法可以针对所有类型的异常我们也可以忽略某些异常。
RequestMapping(/fallbackTest)
SentinelResource(value fallbackTest, fallback fallbackHandler, exceptionsToIgnore ArithmeticException.class)
public String fallbackTest(String params) {int i 1 / 0;return Test#fallbackTest RandomUtils.nextInt(0, 1000);
}public String fallbackHandler(String params) {return Test#fallbackHandler RandomUtils.nextInt(0, 1000);
}模拟了一个计算异常但是此异常被忽略了所以不会进入到fallbackHandler中进行处理而是直接jvm抛异常给客户端响应。
代码优化
前面的代码中都是把fallback和block全都写在了一起这样是不符合程序单一性原则的毕竟controller层有很多之外的逻辑二来别的类也不好复用。
sentinel考虑到这些情况在SentinelResource中有blockHandlerClass和fallbackClass。顾名思义blockHandlerClass中写blockHandler函数fallbackClass中写fallback的函数。
// 异常fallback
public class ExceptionHandler {public static String sentinelTestFallback(String params) {return testCon#sentinelTestFallback RandomUtils.nextInt(0, 1000);}
}// blockHandler处理
public class BlockHandler {public static String sentinelBlock(String params, BlockException e) {return testCon#sentinelBlock RandomUtils.nextInt(0, 1000);}
}两个类中的方法必须是static 修饰的且参数要和原方法保持一致否则无法解析噢
接口原方法
RequestMapping(/sentinelUnionTest)
SentinelResource(value sentinelUnionTest,fallbackClass ExceptionHandler.class, fallback sentinelTestFallback, // 指定类和方法名blockHandlerClass BlockHandler.class, blockHandler sentinelBlock) // 指定类和方法名
public String sentinelUnionTest(String params) {int i 1 / 0;return Test#fallbackTest RandomUtils.nextInt(0, 1000);
}