1、超时
通过超时来释放资源,这样就不容易被拖死,只要释放够快。
2、限流
通过评估来限制流量,防止微服务被拖死。
3、仓壁模式
资源有对立线程池,拥有自己拒绝策略。资源之间不相互影响。
4、断路器模式
监控错误率或者错误次数达到一定阈值,就跳闸,就认为依赖微服务不可用,监控加开关
二 使用sentinel进行微服务容错
1、sentinel是什么
轻量级的流量控制、熔断降级java库
https://github.com/alibaba/Sentinel
2、整合sentinel
加依赖
三、整合控制台
根据自己的sentinel客户端下载对应的控制台版本
下载地址
https://github.com/alibaba/Sentinel/releases
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
启动命令
整合控制台
添加如下配置
spring:
sentinel:
dashboard:localhost:9090
然后访问localhost:8081
可以看到如下界面
点击簇点链路
并且设计流控规则
流控规则有
1、qps
2、线程数
3、还可以根据来源
4、高级配置里面还有关联,关联资源达到一定阈值就限流自己。使用场景就是查询接口不能过快,不能影响修改接口。
5、只记录链路上的流量,就是记录入口流量达到阈值就限流。演示如下
@GetMapping("/test-a")
public void testa(){
testService.commos();
}
@GetMapping("/test-b")
public void testb(){
testService.commos();
}
@Service
@Slf4j
public class TestService {
@SentinelResource("commons")
public void commos() {
log.info("被调用了");
}
}
访问test-a,访问test-b就会在簇点链路中展示资源
编辑流控规则如下
必须加上斜杠否则不生效。
流控效果
1、快速失效
源码类为com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController
2、warnup
根据codeFactor,从阈值/codeFactor作为新阈值,经过预热时间才能达到设置的QPS阈值
3、排队
请求排队匀速通过,流控模式不能设置线程数。
降级规则
1、RT平均响应时间,默认响应最大时间4900ms,需要修改-Dcsp.sentinel.statistic.max.rt=xxx修改
2、异常比例
3、异常数,分钟数的,时间窗口最好设置大于60s
4、sentinel目前没有断路器半开状态
5、热点规则配置如下,试用于某些参数请求qps特别高

源码
com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowChecker#passCheck
系统规则
1、load,load1,一分钟电脑负载负载超过阈值且并发线程数超过系统容量时触发,建议设置为CPU核心数*2.5,仅对Linux/Unix like机器生效
2、系统容量=maxQps*minRt
maxQps:秒级统计出来的最大QPS
minRt:秒级统计出来的最小响应时间
相关源代码
com.alibaba.csp.sentinel.slots.block.system.SystemRuleManager#checkBbr
系统RT:所有入口流量的平均RT达到阈值触发
线程数:所有入口流量的并发线程数达到阈值触发
入口QPS:所有入口流量的QPS达到阈值触发
com.alibaba.csp.sentinel.slots.block.system.SystemRuleManager#checkSystem
--------------------------------------------------------------------------------
代码配置规则
详情见
https://www.imooc.com/article/289345
@GetMapping("test-add-flow-rule")
public String testHot(){
this.initFlowQpsRule();
return "success";
}
private void initFlowQpsRule() {
List<FlowRule> rules = new ArrayList<>();
FlowRule flowRule = new FlowRule();
flowRule.setCount(20);
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
flowRule.setLimitApp("default");
rules.add(flowRule);
FlowRuleManager.loadRules(rules);
}
Sentinel控制台与微服务通讯原理
1、集成Sentinel-transport-simple-http,实现了一套微服务注册和发现机制
2、定时拉取监控规则
3、定时推送
源码
com.alibaba.csp.sentinel.transport.heartbeat.SimpleHttpHeartbeatSender
com.alibaba.csp.sentinel.command.CommandHandler的实现类
应用端配置项
sentinel:
transport:
dashboard: localhost:9090
#使用什么 ip
client-ip: 127.0.0.1
heartbeat-interval-ms: 10000
port: 8719
控制台的配置项
配置项 | 默认值 | 最小值 | 描述 |
server.port | 8080 | 指定端口 | |
csp.sentinel.dashboard.server | localhost:8080 | 指定地址 | |
csp.sentinel.dashboard.auth.username | sentinel | ||
csp.sentinel.dashboard.auth.password | sentinel | ||
server.servlet.session.timeout | 30分钟 | ||
project.name | 指定程序名称 |
Sentinel Api,Sentinel不统计除BlockException或者BlockException的子类
@GetMapping("test-add-flow-api")
public String testAddFlowApi(@RequestParam String a){
Entry entry = null;
try {
entry = SphU.entry("test-add-flow-api");
if(StringUtils.isEmpty(a)){
throw new IllegalArgumentException("a must be not null");
}
return "success";
}catch (BlockException e){
e.printStackTrace();
}finally {
if(entry!=null){
entry.exit();
}
}
return "success";
}
如果需要控制就如下
@GetMapping("test-add-flow-api")
public String testAddFlowApi(@RequestParam String a){
Entry entry = null;
try {
entry = SphU.entry("test-add-flow-api");
if(StringUtils.isEmpty(a)){
throw new IllegalArgumentException("a must be not null");
}
return "success";
}catch (BlockException e){
e.printStackTrace();
}catch (IllegalArgumentException e2){
Tracer.trace(e2);
return "参数非法";
}finally {
if(entry!=null){
entry.exit();
}
}
return "success";
}
针对来源
@GetMapping("test-add-flow-api")
public String testAddFlowApi(@RequestParam String a){
Entry entry = null;
String resource = "test-add-flow-api";
ContextUtil.enter(resource,"");
try {
entry = SphU.entry(resource);
if(StringUtils.isEmpty(a)){
throw new IllegalArgumentException("a must be not null");
}
return "success";
}catch (BlockException e){
e.printStackTrace();
}catch (IllegalArgumentException e2){
Tracer.trace(e2);
return "参数非法";
}finally {
if(entry!=null){
entry.exit();
}
ContextUtil.exit();
}
return "success";
}
使用sentinelResource,优化代码
@GetMapping("test-sentinelResource")
@SentinelResource(value = "test-sentinelResource",blockHandler = "block")
public String testSentinelResource(@RequestParam String a){
if(StringUtils.isEmpty(a)){
throw new IllegalArgumentException("a must be not null");
}
return "success";
}
public String block(String a,BlockException e){
log.warn("限流,或者降级了",e);
return "限流了,或者降级了";
}
源码
com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect
com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspectSupport
RestTemplate整合Sentinel
@Bean
@LoadBalanced
@SentinelRestTemplate
public RestTemplate restTemplate(){
return new RestTemplate();
}
resttemplate:
sentinel:
enabled: false
为Feign整合Sentinel
feign:
sentinel:
enabled: true
上面Feign和RestTemplate访问过的资源都可以添加监控。
@Component
@Slf4j
public class BaiduFallBackFactory implements FallbackFactory<BaiduFeignClient> {
@Override
public BaiduFeignClient create(Throwable throwable) {
return new BaiduFeignClient() {
@Override
public String index() {
log.warn(""+throwable);
return null;
}
};
}
}
打印异常。
如何在生产环境使用sentinel
推拉模式持久化规则
推模式
https://www.imooc.com/article/289402