熔断、降级和限流
- 熔断:A服务调用B服务的某个功能,由于网络不稳定问题,或者B服务卡顿,导致功能时间超长。如果这样子的次数太多,我们直接将B断路了(A不再请求B接口),凡是调用B的直接返回降级数据,不必等待B的超长执行。这样B的故障问题,就不会级联影响到A
- 降级:整个网站处于流量高峰期,服务器压力剧增,根据当前业务情况以及流量,对一些服务和页面进行有策略的降级(停止服务,所有调用直接返回降级数据)。以此缓解服务器资源的压力,以保证核心业务的正常运行,同时也保持了客户端和大部分客户得到正确的响应。
- 相同点:为了保证集群中大部分服务的可用性和可靠性,防止崩溃;用户最终体验到的都是某个服务不可用。
- 不同点:熔断是被调用方的故障,触发系统的主动规则;降级是基于全局考虑,停止一些正常服务,释放资源。
- 限流:对打入服务的流量进行控制,使服务能够承担不超过自己能力的流量压力。
Spring Boot 整合 Sentinel
-
引入 Sentinel 场景启动器
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
-
根据引入的sentinel核心包,下载sentinel控制台。地址,启动 sentinel
java -jar sentinel-dashboard-1.8.0.jar --server.port=8888
访问控制台:http://127.0.0.1:8888 输入用户名/密码:sentinel/sentinel
-
配置控制台信息:
spring: cloud: sentinel: transport: dashboard: localhost:8888 port: 8719
这里的 spring.cloud.sentinel.transport.port 端口会在对应的机器上启动一个Http Server,该 Server 会与 Sentinel 控制台交互。比如 Sentinel 控制台添加一个限流规则,会把规则数据 push给这个 HttpServer接收,Http Server再将规则注册到 Sentinel中。
-
配置流控规则,如QPS
默认的流控规则是放在内存里面的,应用重启后就不存在了。
触发流控规则后,显示页面。
自定义流控返回数据,需要实现BlockExceptionHandler接口@Configuration public class SeckillSentinelConfig implements BlockExceptionHandler { @Override public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception { R error = R.error(BizCodeEnum.TOO_MANY_REQUEST.getCode(), BizCodeEnum.TOO_MANY_REQUEST.getMsg()); httpServletResponse.setCharacterEncoding("UTF-8"); httpServletResponse.setContentType("application/json"); httpServletResponse.getWriter().write(JSON.toJSONString(error)); } }
-
解决sentinel控制台实时监控没有数据问题,如下:
引入相关依赖,参考<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-transport-simple-http</artifactId> </dependency>
Sentinel 对 Feign 支持
- 开启 sentinel 对feign的支持
feign: sentinel: enabled: true
- 远程方法写法:
@FeignClient(value = "mall-seckill" , fallback = SeckillFeignServiceFallback.class) public interface SeckillFeignService { @GetMapping("/sku/seckill/{skuId}") R getSkuSeckillInfo(@PathVariable("skuId") Long skuId); } @Slf4j @Component public class SeckillFeignServiceFallback implements SeckillFeignService { @Override public R getSkuSeckillInfo(Long skuId) { log.info("熔断方法调用了"); return R.error(BizCodeEnum.TOO_MANY_REQUEST.getCode(), BizCodeEnum.TOO_MANY_REQUEST.getMsg()); } }
- 在 sentinel dashboard 页面指定降级策略
当降级规则被触发后,也会调用我们自定义的熔断方法。
自定义受保护资源
-
基于代码的方式自定义受保护资源
try (Entry entry = SphU.entry("seckillSkus")) { // 受保护的资源 }catch (BlockException e) { log.info("流量过大,触发自定义降级规则", e.getMessage()); }
seckillSkus 是受保护的资源名称。请求该资源后,可以在sentinel控制台,看到该资源
在控制台页面,添加流控规则,触发流控规则后,即会出现如下输出:
-
基于注解的方式,自定义受保护的资源 @SentinelResource
public List<SecKillSkuRedisTo> blockHandler(BlockException e) { log.error("原方法getCurrentSeckillSkus被限流了"); return null; } // 返回当前时间可以产于的秒杀商品的信息 @SentinelResource(value = "getCurrentSeckillSkus", blockHandler = "blockHandler") @Override public List<SecKillSkuRedisTo> getCurrentSeckillSkus() { }
在被限流的资源方法上,标注@SentinelResource,并且可以指定名字,还可以指定被限流后的回调方法,用 **blockHandler **参数指定。其中 回调方法的返回值要与原资源方法一致。
Sentinel 与 网关的整合
- 引入依赖
注意,这里的版本要与 spring-cloud-starter-alibaba-sentinel 版本保持一致。<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId> <version>1.8.0</version> </dependency>
- 网关这里显示的菜单,应该与其它微服务的菜单不一样。如:
如果没能出现 API管理菜单,那需要在启动网关的启动类的main方法里,加入一行代码:
System.setProperty("csp.sentinel.app.type", "1");
重启网关服务,并重启 sentinel控制台。
网关限流,可以参考 https://github.com/alibaba/Sentinel/tree/master/sentinel-demo