SpringCloud-Nacos+Sentinel+Feign
高并发
问题
多个服务之间相互依赖,可能会导致系统负载过高,突发流量或网络异常等情况,导致服务不可用。
解决方案
面向失败编程:
- 不被外界影响
- 不被请求拖垮
2.1 上游服务
2.2 下游服务
面向失败编程-容错方案
- 限流
- 漏斗,不管流量多大,均匀的流入容器,令牌桶算法,漏桶算法
- 熔断
- 降级
- 隔离
Sentinel
- 以流量为切入点,从流量控制,熔断降级,负载均衡保护等多个维度保护服务的稳定性
- 消息削峰填谷、集群流量控制、实时熔断下游不可用应用
- 完备的实时监控,Sentinel提供实时的监控功能
- 与SpringCloud、Dubbo、gRPC整个
核心概念
- 资源:可以是服务或方法甚至代码
- 规则:定义什么样的方式保护资源,主要包括流控规则,熔断降级规则等
配置
spring:
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:8080
port: 9999
微服务注册上去后,由于Sentinel是懒加载模式,所以需要访问微服务后才会在控制台出现。
流量控制
监控应用流量的QPS或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬间的流量高峰冲垮。
两种规则
- 基于统计并发线程数的流量控制
并发数控制用于保护业务线程池不被耗尽,Sentinel并发控制线程数不负责创建和管理线程池,只是简单的统计当前请求上下文的线程数目(正在执行的调用数目),如果超出阈值,新的请求就会被立即拒绝,相当于信号量隔离。 - 基于流量QPS的流量控制
当QPS超过某个阈值的时候,则采取控制流量
流控规则会下发到微服务,微服务如果重启,则流控规则会消失可以持久化配置
流量控制效果
- 直接拒绝:默认的流控方式,新请求会被直接拒绝
- Warm up:预热,如果系统在此之前长期处于空闲的状态,希望处理请求的数量缓步的增长,经过预期的时间之后,到底系统处理请求个数的最大值
- 匀速排队,严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏漏桶算法,主要用于处理理间隔性突发的流量量,如消息队列,想象一下这样的场景,在某一秒有大量量的请求到来,接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理理这些请求,而不是在第一秒直接拒绝多余的请求
3.1 匀速排队等待策略略是 Leaky Bucket 算法结合虚拟队列列等待机制实现的
3.2 匀速排队模式暂时不不⽀支持 QPS > 1000 的场景
流控一般在单机内做限制
熔断策略
- 响应时):选择以响应时间作为阈值,需要设置最大允许的响应时间,请求的响应时间大于该值则统计为慢调用。
1.1 阈值:修改后不生效,bug
1.2 熔断时长:超过时间后会尝试修复
1.3 最小请求数:熔断触发的最小请求数,小于该值时即使异常比例超出阈值也不会熔断
1.4 异常比例:当单位时间内请求数目大于设置的最小请求数,并且异常比例大于阈值,则接下来的熔断时长内请求会自动被熔断
1.5 异常数:当单位时间内请求的异常数超过阈值会自动被熔断
熔断状态
- 熔断关闭:服务没有故障时,对调用方的调用不做限制
- 熔断开启:后续对该服务接口的调用不再经过网络,直接执行本地的fallback方法
- 半熔断:尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率
Alibaba Cloud升级
v2.1.0到v2.2.0后,Sentinel里面依赖进行了改动,不向下兼容
异常种类
- FlowException
- DegradeException
- ParamFlowException
- SystemBlockException
- AuthorityException
package com.example.demo.config;
@Component
public class MyBlockHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest
httpServletRequest, HttpServletResponse
httpServletResponse, BlockException e) throws
IOException {
Map<String, Object> backMap = new HashMap<>();
if (e instanceof FlowException) {
backMap.put("code", -1);
} else if (e instanceof
DegradeException) {
backMap.put("code", -2);
} else if (e instanceof
ParamFlowException) {
backMap.put("code", -3);
} else if (e instanceof
SystemBlockException) {
backMap.put("code", -4);
} else if (e instanceof
AuthorityException) {
backMap.put("code", -5);
}
httpServletResponse.setStatus(200);
httpServletResponse.setHeader("content-Type", " application / json; charset = UTF - 8 ");
httpServletResponse.getWriter().write(JSON.toJSONString(backMap));
}
}
Feign+Sentinel
feign:
sentinel:
enabled: true
@FeignClient(value = "xx-service",
fallback = XXServiceFallback.class)
版权声明:本文为dhylanyu1原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。