Sentinel 是什么?
简言之,就是用于管理应用服务的流量控制、熔断降级的组件。当我们的服务有流量控制、熔断降级方面的需求时,可以考虑使用该组件。
Sentinel: 分布式系统的流量防卫兵
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助您保障微服务的稳定性。(摘自官方文档,更多介绍详见:https://sentinelguard.io/zh-cn/docs/introduction.html)
使用
使用方式主要是通过三个步骤:
- 定义资源resources (可以理解为Map中的key)
- 定义与资源相对应的规则rules (可以理解为Map中的value)
- 方法被调用时,通过Entry entry = SphU.entry(resource);进入Sentinel组件,通过resource找到对应rule,从而触发对应的限流或降级规则。
示例
官网教程中有一些demo,这里补充一个Springboot项目中的实际应用示例。
使用Apollo管理限流配置,更加灵活,可动态修改和加载。
/**
* Sentienl限流配置
*
* @author: Danger
* @time: 2022/6/1
*/
@Configuration
@EnableApolloConfig
@Slf4j
public class SentinelAutoConfig {
private static Map<String, Object> flowQpsRuleMap;
@ApolloJSONValue("${sentinel.flowrule:{\"sayHello\":{\"resource\":\"sayHello\",\"count\":1,\"grade\":1,\"limitApp\":\"default\"},\"sayBye\":{\"resource\":\"sayBye\",\"count\":20,\"grade\":1,\"limitApp\":\"default\"},\"testA\":{\"resource\":\"testA\",\"count\":10,\"grade\":1,\"limitApp\":\"default\"}}}")
public void setFlowQpsRuleMap(Map<String, Object> data) {
flowQpsRuleMap = data;
log.info("update apollo flowQpsRuleMap:{}", flowQpsRuleMap);
this.loadFlowQpsRules(flowQpsRuleMap);
}
private void loadFlowQpsRules(Map<String, Object> flowQpsRuleMap) {
List<FlowRule> flowRules = new ArrayList<>();
flowQpsRuleMap.forEach((k, v) -> {
FlowRule flowRule = JSON.parseObject(JSON.toJSONString(v), FlowRule.class);
flowRules.add(flowRule);
});
FlowRuleManager.loadRules(flowRules);
log.info("loadFlowQpsRules success, flowRules={}", FlowRuleManager.getRules());
}
}
/**
* Sentinel限流测试service
*
* @author: Danger
* @time: 2022/6/1
*/
@Service
@Slf4j
public class SentinelService {
@SentinelResource(value = "sayHello")
public String sayHello(String name) {
Entry entry = null;
// 务必保证finally会被执行
try {
// 资源名可使用任意有业务语义的字符串
entry = SphU.entry(name);
// 被保护的业务逻辑
return "Hello, " + name;
} catch (BlockException e) {
// 资源访问阻止,被限流或被降级
// 进行相应的处理操作
log.error("sayHello BlockException");
} finally {
if (entry != null) {
entry.exit();
}
}
return null;
}
@SentinelResource(value = "sayBye")
public String sayBye(String name) {
return "Bye, " + name;
}
/**
* 通过sentinelDTO中的属性匹配限流规则
*
* @author Danger
* @time: 2022/6/1
* @param sentinelDTO
* @return java.lang.String
*/
public String flowRuleTest(SentinelDTO sentinelDTO) {
Entry entry = null;
// 务必保证finally会被执行
try {
// 资源名可使用任意有业务语义的字符串
entry = SphU.entry(sentinelDTO.getName());
// 被保护的业务逻辑
printName(sentinelDTO);
return sentinelDTO.getName();
} catch (BlockException e) {
// 资源访问阻止,被限流或被降级
// 进行相应的处理操作
return handleBlockExecption(sentinelDTO);
} finally {
if (entry != null) {
entry.exit();
}
}
}
/**
* 触发限流时的业务操作
*
* @author Danger
* @time: 2022/6/1
* @param sentinelDTO
* @return java.lang.String
*/
private String handleBlockExecption(SentinelDTO sentinelDTO) {
log.error("flowRuleSayHello handleBlockExecption, sentinelDTO={}", sentinelDTO);
return "handleBlockExecption";
}
private void printName(SentinelDTO sentinelDTO) {
System.out.println(sentinelDTO.getName());
}
}
写一个测试Controller,使用Jmeter调用,可观察到测试结果如下:
请求flowRuleTest方法,触发“testA”的限流规则,由于使用的压测工具设置的qps为100,所以观察到结果如下:前10次请求正常,之后触发限流,执行了handleBlockExecption逻辑
以上。