当前位置: 首页 > news >正文

Spring Cloud系列—Alibaba Sentinel熔断降级

上篇文章:

Spring Cloud系列— Alibaba Sentinel限流https://blog.csdn.net/sniper_fandc/article/details/149944260?fromshare=blogdetail&sharetype=blogdetail&sharerId=149944260&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link

目录

1 熔断策略

1.1 状态机

1.2 慢调用比例(SLOW_REQUEST_RATIO)

1.3 异常比例(ERROR_RATIO)

1.4 异常数(ERROR_COUNT)

2 降级

2.1 捕获异常

2.2 FallbackFactory


1 熔断策略

        当微服务系统中存在某个服务或接口故障,由于调用链路比较复杂,某个接口的故障可能就会导致整个系统不可用。因此需要对故障的接口或服务进行熔断降级,熔断降级主要是对弱依赖服务(不是系统运行的必须服务组件),常见三种策略:

1.1 状态机

        熔断是由断路机(熔断器)统计服务调用的慢调用比例、异常比例和异常数,如果超过阈值则进行熔断,拦截请求该服务的请求;否则放行请求该服务的请求。断路机是基于状态机来完成工作的:

        状态机有三种状态:OPEN、HALF_OPEN和CLOSED。

        CLOSED:所有请求都会通过断路机,通过的过程中统计慢调用比例、异常比例和异常数,如果失败率高于阈值就会转化为OPEN状态。

        OPEN:所有请求都会被断路机拦截,即服务被熔断。每隔一段时间转化为HALF_OPEN状态,并将一定的请求放入断路机。

        HALF_OPEN:OPEN状态每隔一段时间转化为HALF_OPEN状态,并根据放入的请求统计慢调用比例、异常比例和异常数,如果失败率高于阈值,则此时服务还得继续熔断,因此再次转化为OPEN状态;如果失败率低于阈值,则此时服务被视为可以正常访问,不需要进行熔断,因此转化为CLOSED状态。

1.2 慢调用比例(SLOW_REQUEST_RATIO)

        在统计时长内,请求数超过最小请求数,且慢调用(请求响应时间超过最大RT(最大响应时间))比例超过比例阈值,就进行熔断,暂停该资源一定时间(熔断时长)的访问。

        假设order-service服务调用product-service服务的接口,如果product-service服务的接口出现响应速度慢的情况,则会被认为是慢调用请求:

    @RequestMapping("/{productId}")public ProductInfo getProductById(@PathVariable("productId") Integer productId){try {long millis = new Random().nextInt(20)+50;Thread.sleep(millis);//模拟慢调用System.out.println("收到请求,Id:"+productId);return productService.selectProductById(productId);} catch (InterruptedException e) {throw new RuntimeException(e);}}

        将调用方的调用方法定义为资源,便于设置熔断规则:

    @SentinelResource("selectOrderById")public OrderInfo selectOrderById(Integer orderId) {OrderInfo orderInfo = orderMapper.selectOrderById(orderId);//OpenFeign远程调用方式ProductInfo productInfo = productInterface.getProductById(orderInfo.getProductId());orderInfo.setProductInfo(productInfo);return orderInfo;}

        针对资源设置熔断规则,10s内如果请求数超过5次,并且慢调用(响应时间超过50ms)比例超过0.5,则熔断5s:

        当重启服务后,快速手动多次发送请求,如果发送请求超过5次以上,就会出现熔断现象:

1.3 异常比例(ERROR_RATIO)

        在统计时长内,请求数超过最小请求数,且异常比例超过比例阈值,就进行熔断,暂停该资源一定时间(熔断时长)的访问。

        首先在被调用接口中分别设置慢调用和异常两种情况,由于(这里用到了服务降级,会在下面进行阐述)服务降级会针对异常也生效,因此想要观察熔断,就需要先调用慢调用接口(没有设置慢调用的熔断策略,因此不会熔断)会正常通行,再多次调用异常接口触发熔断,最后再调用慢调用接口也会被拦截:

    @RequestMapping("/{productId}")public ProductInfo getProductById(@PathVariable("productId") Integer productId) {if (productId == 1001) {//模拟慢响应try {Thread.sleep(60);} catch (InterruptedException e) {throw new RuntimeException(e);}} else if (productId == 1002) {// 模拟异常throw new RuntimeException("发生异常");}return productService.selectProductById(productId);}

        设置熔断策略为异常比例,10s请求数大于5次,异常比例超过50%就触发5s熔断:

        调用order/1接口,最终会远程调用product/1001接口,不会触发熔断:

        调用order/2接口,最终会远程调用product/1002接口,多次调用会触发熔断(异常比例超过50%):

        在触发熔断后,调用order/1接口,可以发现productInfo为NULL,说明触发熔断,并且服务降级:

1.4 异常数(ERROR_COUNT)

        在统计时长内,请求数超过最小请求数,且发生异常的数量超过设置的异常数,就进行熔断,暂停该资源一定时间(熔断时长)的访问。

        异常数与异常比例类似,只不过熔断判断标准变为超过数字而不是比例。

2 降级

        上述慢调用熔断时,用户会直接看到500内部异常这个响应,这对用户体验并不好。应该针对失败返回用户友好性的提示或默认结果,这就是降级。

        实现服务降级有两种方式:

        1.捕获异常,根据异常逻辑来进行降级。适用于通用场景。

        2.FallbackFactory,适合远程调用场景。

2.1 捕获异常

        由于访问的是/order/{orderId}接口,因此可以在调用时发生异常后返回一个NULL对象:

    @SentinelResource("order-param")@RequestMapping("/{orderId}")public OrderInfo getOrderById(@PathVariable("orderId") Integer orderId) {try {OrderInfo orderInfo = orderService.selectOrderById(orderId);return orderInfo;}catch (UndeclaredThrowableException e){System.out.println("获取订单发生异常,exception:"+e);;return new OrderInfo();}}

        此时在发生熔断,就不会直接在页面显示500内部异常,而是一个NULL对象:

2.2 FallbackFactory

        FallbackFactory是微服务架构中用于服务降级的接口,可以根据远程服务调用失败或异常信息,提供一个降级处理实例,该实例来代替原服务被调用。

        首先需要创建这个降级处理实例,该实例实现FallbackFactory并接受ProductInterface类型的泛型参数:

@Slf4jpublic class ProductFallbackFactory implements FallbackFactory<ProductInterface> {@Overridepublic ProductInterface create(Throwable cause) {return new ProductInterface() {//返回服务降级实例@Overridepublic ProductInfo getProductById(Integer productId) {log.error("查询商品信息异常");return new ProductInfo();}@Overridepublic String param1(Integer productId){return "发生错误";}@Overridepublic String param2(Integer productId,String name){return "发生错误";}@Overridepublic String object(ProductInfo productInfo){return "发生错误";}@Overridepublic String json(ProductInfo productInfo){return "发生错误";}};}}

        ProductInterface类型是OpenFeign远程调用的客户端(抽取),需要注意设置fallbackFactory来和服务降级实例关联:

@FeignClient(value = "product-service",path = "/product", fallbackFactory = ProductFallbackFactory.class)public interface ProductInterface {@RequestMapping("/{productId}")ProductInfo getProductById(@PathVariable("productId") Integer productId);@RequestMapping("/param1")String param1(@RequestParam("productId") Integer productId);@RequestMapping("/param2")String param2(@RequestParam("productId")Integer productId,@RequestParam("name")String name);@RequestMapping("/object")String object(@SpringQueryMap ProductInfo productInfo);@RequestMapping("/json")String json(@RequestBody ProductInfo productInfo);}

        然后还需要定义ProductFallbackFactory的Bean,由于该DefaultFeignConfiguration需要多个远程调用的接口使用,因此不添加五大注解交给Spring来管理,而是由调用方自行扫描注册该Bean:

//创建ProductFallbackFactory的Beanpublic class DefaultFeignConfiguration {@Beanpublic ProductFallbackFactory productFallbackFactory() {return new ProductFallbackFactory();}}

        调用方的启动类上需要配置OpenFeign客户端和FallbackFactory管理的服务降级实例的路径:

@EnableFeignClients(basePackages = {"com.demo.product.api2"},defaultConfiguration = DefaultFeignConfiguration.class)

        最后在配置文件中开启OpenFeign的Sentinel的功能:

feign:sentinel:enabled: true # 开启feign对sentinel的支持

        重启服务,观察服务降级:

        可以发现,开启OpenFeign的Sentinel功能后,远程调用的接口也出现在簇点链路中,针对远程调用设置熔断降级:

        此时在多次慢调用出发熔断后,不再是直接的500内部异常,而是远程调用的服务降级。并且该服务降级返回了NULL的productInfo对象(服务降级实例),并不是像异常处理那样处理粒度很粗。

        注意:FallbackFactory不仅对熔断生效对限流也生效,即如果触发限流,页面不再显示Blocked by Sentinel,而是返回服务降级实例。并且,服务降级还会对异常生效,即只要程序发生异常,就会走服务降级。因此发生服务降级现象,不一定是因为熔断,也可能是因为限流或异常。

下篇文章:

Spring Cloud系列—Alibaba Sentinel授权与规则管理及推送https://blog.csdn.net/sniper_fandc/article/details/149945898?fromshare=blogdetail&sharetype=blogdetail&sharerId=149945898&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link

http://www.dtcms.com/a/331717.html

相关文章:

  • 第一章 随机事件与概率
  • 前端性能优化移动端网页滚动卡顿与掉帧问题实战
  • 前端开发常见问题及解决方案全解析
  • 解剖HashMap的put流程 <一> (JDK 1.8)
  • 22.Linux samba服务
  • USB 3.0 link command 定义
  • 知识的本质
  • 数域筛法GNFS---C语言实现
  • 20道CSS相关前端面试题及答案
  • Elasticsearch:如何使用 Qwen3 来做向量搜索
  • css中container和media的用法和区别
  • SRWare Iron:隐私保护与高效浏览的完美结合
  • C++ mutex的实现源码分析
  • Xsens动作捕捉与AI驱动人形机器人训练革新
  • WVP和ZLM部署与接入NVR指南环境准备
  • 【React】hooks 中的闭包陷阱
  • 三轴云台之脉宽调制技术篇
  • Qt基本槽
  • 链游(GameFi)开发破局:如何平衡可玩性与经济模型可持续性?
  • GraphRAG:AI理解复杂知识的未知领域,开启探索之旅
  • 《Python函数:从入门到精通,一文掌握函数编程精髓》
  • MySQL主从原理
  • Linux 文件系统简介
  • 解析 TrueType/OpenType 格式的可变字体(Variable Font),提取其所有命名实例(Named Instances) 的名称信息
  • ESP32S3的LVGL配置参数解释、动画播放优化(更新中)
  • 4.1vue3的setup()
  • 《WebGL中FBO的底层运行逻辑》
  • 编程与数学 02-017 Python 面向对象编程 01课题、面向对象
  • 【会员专享数据】2000-2024年我国乡镇的逐日PM₁₀数据(Shp/Excel格式)
  • linux初始化配置