[Alibaba微服务技术入门]_Sentinel热点参数限流_第14讲
热点限流官方文档:https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制
比如:
- 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
- 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效
Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式
热点参数限流实战
第一步:在 FlowLimitController 新增 testHotKey 方法,且在方法上加入 @SentinelResource 注解 + 两个参数
package com.liuyangjava.controller; import com.alibaba.csp.sentinel.annotation.SentinelResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.TimeUnit; @RestController public class FlowLimitController { @Value("${server.port}") private String port; private Logger logger = LoggerFactory.getLogger(FlowLimitController.class); @GetMapping("/sentinel/service") public String getInfo() { return "sentinel service is running, server port: " + port; } @GetMapping("/sentinel/playInfo") public String playInfo() { logger.info(Thread.currentThread().getName()+"\t"+".../sentinel/playInfo"); return "sentinel service is playInfo"; } @GetMapping("/sentinel/testRT") public String testRT() { try { // 模拟此接口一秒钟才处理完一个请求,其处理请求时间远大于RT响应时间 TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } logger.info(Thread.currentThread().getName()+"\t"+".../sentinel/testRT"); return "sentinel service RT is Opening"; } @GetMapping("/sentinel/testException") public String testException() { // 触发异常, 如果异常发生比例超过阈值, 服务熔断降级 int i = 10 / 0; return "sentinel service testException is Opening"; } @GetMapping("/sentinel/testHotKey") @SentinelResource(value = "testHotKey") public String testHotKey(@RequestParam(value = "p1", required = false) String p1, @RequestParam(value = "p2", required = false) String p2) { return "sentinel service resource is Opening"; } }
第二步:配置热点参数
注意:
- 通过浏览器返回接口 /sentinel/testHotKey,不加入参数的时候,接口是不会出现异常的
- 但是在接口 /sentinel/testHotKey 上面加入参数p1,进行测试QPS > 1,接口就会出现限流的异常。且后台会抛出 ParamFlowException
第三步:在 @SentinelResource 注解上加入 blockHandler 属性,通过它来自定义热点参数限流成功后的反馈信息定义
@GetMapping("/sentinel/testHotKey") @SentinelResource(value = "testHotKey", blockHandler = "handlerTestHotKey") public String testHotKey(@RequestParam(value = "p1", required = false) String p1, @RequestParam(value = "p2", required = false) String p2) { return "sentinel service resource is Opening"; } public String handlerTestHotKey(String p1, String p2, BlockException exception) { return "对不起, 当前流量过高..."; }
参数例外项
-
我们期望p1参数当它是某个特殊值时,它的限流值和平时不一样
-
假如,当p1的值等于5时,它的阈值可以达到200
注意:@SentinelResource只负责热点参数限流的配置,但是如果方法自身发生的异常,@SentinelResource的属性 blockHandler 是不负责处理改异常信息