利用 Sentinel 热点参数限流功能保护服务的方法
- 原理:热点参数限流是对特定参数值的请求进行限流,可针对参数值设置不同的限流阈值。在微服务业务场景中,某些参数值可能会频繁被访问导致流量集中,通过热点参数限流可避免这些参数值的请求量过大而压垮服务。
- 应用场景:例如电商系统中,商品详情页展示接口,对于热门商品 ID 的请求可能远多于其他商品 ID,可对商品 ID 这个参数进行热点参数限流。
热点参数限流规则具体配置步骤
- 引入依赖:在项目的
pom.xml
文件中引入 Sentinel 相关依赖。
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>x.x.x</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>x.x.x</version>
</dependency>
- 配置 Sentinel 控制台:启动 Sentinel 控制台,并将微服务注册到控制台。
- 定义热点参数限流规则:
- 方式一:通过注解方式
- 在需要限流的方法上添加
@SentinelResource
注解,例如:
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Service;
@Service
public class ProductService {
@SentinelResource(value = "productDetail", blockHandler = "handleProductDetailBlock")
public String getProductDetail(long productId) {
// 业务逻辑
return "Product detail for productId: " + productId;
}
public String handleProductDetailBlock(long productId, BlockException ex) {
return "限流了,当前商品访问量过大";
}
}
- 在配置文件(如 `application.yml`)中配置热点参数限流规则:
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-sentinel
groupId: DEFAULT_GROUP
rule-type: flow
- 在 Nacos 配置中心创建 `${spring.application.name}-sentinel` 文件,添加热点参数限流规则:
[
{
"resource": "productDetail",
"limitApp": "default",
"grade": 1,
"count": 10,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false,
"paramFlowItemList": [
{
"classType": "java.lang.Long",
"fieldName": "productId",
"count": 5,
"grade": 1,
"paramIdx": 0
}
]
}
]
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowItem;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import java.util.ArrayList;
import java.util.List;
public class HotParamLimitExample {
public static void main(String[] args) {
initFlowRules();
while (true) {
try (Entry entry = SphU.entry("productDetail",
RuleConstant.RES_TYPE_DEFAULT,
1,
1L)) {
// 业务逻辑
System.out.println("正常访问");
} catch (Exception e) {
System.out.println("限流了");
}
}
}
private static void initFlowRules() {
List<FlowRule> flowRules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("productDetail");
rule.setCount(10);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");
flowRules.add(rule);
FlowRuleManager.loadRules(flowRules);
List<ParamFlowRule> paramFlowRules = new ArrayList<>();
ParamFlowRule paramRule = new ParamFlowRule();
paramRule.setResource("productDetail");
paramRule.setCount(5);
paramRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
ParamFlowItem item = new ParamFlowItem();
item.setClassType("java.lang.Long");
item.setParamIdx(0);
paramRule.setParamFlowItemList(List.of(item));
paramFlowRules.add(paramRule);
ParamFlowRuleManager.loadRules(paramFlowRules);
}
}
可能遇到的问题及解决方案
- 规则不生效:
- 原因:可能是依赖版本不兼容,配置文件加载错误,或者 Sentinel 控制台与微服务连接问题。
- 解决方案:检查依赖版本是否匹配 Sentinel 控制台版本;确认配置文件路径和格式正确;检查 Sentinel 控制台与微服务的网络连接及注册配置。
- 限流误判:
- 原因:参数类型判断错误,或者参数位置索引错误。
- 解决方案:仔细确认热点参数的类型和在方法参数列表中的位置索引,确保配置正确。
- 性能问题:
- 原因:过多的热点参数限流规则可能会增加系统的计算开销。
- 解决方案:合理设置限流规则,避免设置过多不必要的规则;可以考虑在业务层对参数进行预处理,减少进入限流判断的请求量。