熔断降级

简介: 熔断降级是防止服务雪崩的核心机制,通过Sentinel实现。熔断由客户端断路器统计异常或慢请求比例,超阈值后拦截请求;降级则返回默认数据保障体验。结合使用可快速失败、避免级联故障。

1.2.1. 方案介绍

熔断降级是解决服务集群雪崩问题的重要手段,包括熔断和降级两个方案。

熔断是由断路器统计服务调用的异常比例、慢请求比例,如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求;而当服务恢复时,断路器会放行访问该服务的请求。熔断发生在服务调用方即客户端

这么多报错(慢请求)是吧?行、都别玩了

降级是当遇到访问失败可以快速返回一些默认数据或者友好提示,用户体验会更好。熔断降级结合后是当线路断开后直接走降级线路避免再次去请求失败线路。降级方法需要在服务调用方即客户端实现。

这么多报错(慢请求)是吧?大哥你这样我就要挂了,小弟帮我顶顶(还有部分可以玩)

断路器控制熔断和放行的流程如下:

断路器包括三个状态:

  • closed:关闭状态【默认】,断路器放行所有请求,并开始统计异常比例、慢请求比例、异常数。超过阈值则切换到open状态
  • open:打开状态,服务调用被熔断,访问被熔断服务的所有请求会被拒绝,快速失败,直接走降级逻辑。Open状态5秒后会进入half-open状态
  • half-open:半开状态,放行一次请求,根据执行结果来判断接下来的操作。
  • 请求成功:则切换到closed状态
  • 请求失败:则切换到open状态

实现熔断降级做两件事:

  • 编写服务降级逻辑:就是服务调用失败后的处理逻辑,根据业务场景,可以抛出异常,也可以返回友好提示或默认数据。
  • 异常统计和熔断:统计服务提供方的异常比例,当比例过高表明该接口会影响到其它服务,应该拒绝调用该接口,而是直接走降级逻辑。这里我们用Sentinel完成。

1.2.2. Sentinel安装与集成

1.2.2.1 切换分支

将hmall-micro代码环境切换到dev_02分支。

注意:切换分支前要提交原当前分支的代码。

每位学生在dev_02分支练习完成后提交代码并切换回dev_01分支继续未完成的任务

工作中也经常这样来回切换分支,因为不同需求在不同分支里,我们经常都是并行开发

大家入职后,也可能同时负责3-4个项目,所以尽早习惯【多线程并行的开发模式】

1.2.2.2 安装Sentinel

实现服务保护的工具有很多,Spring Cloud Alibaba技术栈中Sentinel是实现服务保护的中间件。

Sentinel是阿里巴巴开源的一款服务保护框架,目前已经加入Spring Cloud Alibaba中。官方网站:

https://sentinelguard.io/zh-cn/

https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D

Sentinel 的使用可以分为两个部分:

  • 核心库(Jar包):不依赖任何框架/库,能够运行于Java8及以上的版本的运行时环境,同时对 Dubbo/Spring Cloud 等框架也有较好的支持。在项目中引入依赖即可实现服务限流、隔离、熔断等功能。
  • 控制台(Dashboard):Dashboard 主要负责管理推送规则、监控、管理机器信息等。

为了方便监控微服务,我们先把Sentinel的控制台搭建出来。

课前提供的虚拟机已经安装了sentinel,如下图:

使用课前提供的虚拟机需要设置sentinel容器的时区,如下:

先启动sentinel

docker start sentinel-dashboard

登录sentinel容器并设置时区

  • 进入容器:docker exec -it sentinel-dashboard /bin/bash
  • 执行命令:ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo Asia/Shanghai > /etc/timezon

设置完成效果如下 :

如果未使用课前提供的虚拟机,需要参考下边的内容安装sentinel:

1)下载jar包

下载地址:https://github.com/alibaba/Sentinel/releases

也可以直接使用课前资料提供的版本:

2)运行

将jar包拷贝到 虚拟机/data/soft/sentinel目录下重命名为sentinel-dashboard.jar

创建Dockerfile文件

FROM openjdk:11-jdk
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezo
ARG SENTINEL_VERSION=1.8.6
# copy sentinel jar
ADD ./sentinel-dashboard.jar /home/sentinel-dashboard.jar
RUN chmod -R +x /home/sentinel-dashboard.jar
ENTRYPOINT ["sh","-c","java -Dserver.port=8090 -Dcsp.sentinel.dashboard.server=localhost:8090 -Dproject.name=sentinel-dashboard -jar $JAVA_OPTS /home/sentinel-dashboard.jar"]

执行命令创建镜像:

docker build -t sentinel-dashboard .

创建并启动容器:

docker run  --name sentinel-dashboard -d -p 9090:8090 sentinel-dashboard:latest

其它启动时可配置参数可参考官方文档:官网文档链接

3)访问

访问:http://192.168.101.68:9090/ 页面,就可以看到sentinel的控制台了:

需要输入账号和密码,默认都是:sentinel

登录后,即可看到控制台,默认会监控sentinel-dashboard服务本身:

本地运行sentinel

如果在测试时发现虚拟中的sentinel不能用,可以本地运行sentinel。

将sentinel的jar包放在任意非中文、不包含特殊字符的目录下,重命名为sentinel-dashboard.jar

然后运行如下命令启动控制台:

java -Dserver.port=8090 -Dcsp.sentinel.dashboard.server=localhost:8090 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

访问:http://localhost:8090/ 页面

1.2.2.3 项目集成Sentinel

在虚拟机启动sentinel【上面已经执行过,这里是再次提醒、确认一下】

docker start sentinel-dashboard

接下来,我们在项目中集成 sentinel,我们在哪个项目中集成 sentinel?

sentinel要完成熔断降级,熔断是在服务调用方,所以针对购物车服务请求商品服务实现熔断就需要在购物车服务集成 sentienl。

这里可能部分同学有疑问,问什么不是服务提供方呢?所以我们顺便推导一下,假设是提供方熔断:

(1)提供方是熔断了,但是上游调用方还是有大量请求,压力依然存在,只是加快了下游的响应速度,前提是牺牲了原有的业务逻辑实现,并不能保障整体微服务的可靠性

(2)调用方熔断,就是我根本不调用你下游(你此刻慢、报错多那我就先不调用你),而是返回一个默认逻辑,这个默认逻辑实现应该由接口提供方实现

我们在cart-service模块中整合sentinel,连接sentinel-dashboard控制台,步骤如下: 1)引入sentinel依赖

<!--sentinel-->
<dependency>
  <groupId>com.alibaba.cloud</groupId> 
  <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

2)配置控制台

修改application.yaml文件,添加下面内容:

spring:
  cloud:
    sentinel:
      transport:
        dashboard: 192.168.101.68:9090
        client-ip: 192.168.101.1
      http-method-specify: true # 开启请求方式前缀可根据http请求方法区分簇点链路

如果是在本机运行的sentinel要配置:

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8090
      http-method-specify: true # 开启请求方式前缀可根据http请求方法区分簇点链路

3)访问cart-service的任意端点

重启cart-service、item-service,然后访问查询购物车接口:swagger链接

sentinel的客户端就会将服务访问的信息提交到sentinel-dashboard控制台。并展示出统计信息:

点击簇点链路菜单,会看到下面的页面:

所谓簇点链路,就是单机调用链路,是一次请求进入服务后经过的每一个被Sentinel监控的资源。默认情况下,Sentinel会监控SpringMVC的每一个Endpoint(接口)。

因此,我们看到/carts这个接口路径就是其中一个簇点,我们可以对其进行限流、熔断、降级、隔离等保护措施,稍后会详细讲解。

1.2.3. 实现降级

1.2.3.1 开启sentinel

下边我们先编写降级逻辑,再实现服务熔断。

AI(Cursor)提示詞

帮我在已有工程里,对于itemclient实现降级策略,技术使用Sentinel,注意实现方案是implements FallbackFactory,降级类写在api的工程里,并最终在cart-service调用item-service时使用

首先配置Feign使用Sentinel:

在购物车服务application.yml中配置如下(默认已写好):

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

1.2.3.2 实现FallbackFactory接口

接下来给FeignClient编写失败后的降级逻辑有两种方式:

  • 方式一:FallbackClass,无法捕获到远程调用的异常

定义一个降级类实现FeignClient接口,并在@FeignClient注解中配置fallback 属性,如下:

@FeignClient(name="item-service",path = "/items",fallback = 降级类名.class)
  • 方式二:FallbackFactory,可以捕获远程调用的异常,我们一般选择这种方式

定义一个降级类实现FallbackFactory接口,并在@FeignClient注解中配置fallbackFactory属性

@FeignClient(name="item-service",path = "/items",fallbackFactory= 降级类名.class)

这里我们演示方式二的失败降级处理。

步骤一:在hm-api模块中给ItemClient定义降级处理类,实现FallbackFactory接口:

代码如下:

package com.hmall.api.item;
import com.hmall.api.item.dto.ItemDTO;
import com.hmall.common.utils.CollUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.List;
@Slf4j
@Component
public class ItemClientFallbackFactory implements FallbackFactory<ItemClient> {
    @Override
    public ItemClient create(Throwable cause) {
        return new ItemClient() {
            @Override
            public List<ItemDTO> queryItemByIds(Collection<Long> ids) {
                log.error("远程调用ItemClient#queryItemByIds方法出现异常,参数:{}", ids, cause);
                cause.printStackTrace();
                // 查询购物车允许失败,查询失败,返回空集合
                return CollUtils.emptyList();
            }
            @Override
            public void deductStock(List<OrderDetailDTO> items) {
                log.error("远程调用ItemClient#deductStock扣减库存失败,参数:{}",items,cause);
            }
        };
    }
}

1.2.3.3 配置fallbackFactory

步骤二:在hm-api模块中的ItemClient接口中使用ItemClientFallbackFactory

package com.hmall.api.item;
import com.hmall.api.item.dto.ItemDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Collection;
import java.util.List;
/**
 * @author Mr.M
 * @version 1.0
 * @description 商品服务Feign接口
 * @date 2024/8/3 16:21
 */
@FeignClient(name="item-service",path = "/items",fallbackFactory = ItemClientFallbackFactory.class)
public interface ItemClient {
    @GetMapping
    List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);
    @PutMapping("/stock/deduct")
    public void deductStock(@RequestBody List<OrderDetailDTO> items);
}

1.2.3.4 注入降级Bean

步骤三:在cart-service启动类添加扫描包配置,扫描降级类并将bean注册到spring容器

1.2.3.5 降级测试

最后测试降级效果。

重启cart-service,并将item-service停止来模拟item-service服务不可用

请求查询购物车接口,cart-service远程调用item-service,由于item-service不可用,Feign执行ItemClientFallbackFactory 中定义的降级逻辑

在ItemClientFallbackFactory 中打断点,在ItemClientFallbackFactory 中捕获到了远程调用的异常,降级方法返回空List<ItemDTO>。

接口测试最终效果,购物车可以正常显示,但由于获取的商品信息为空这里newPrice显示为null。

启动 ItemServiceApplication,再次请求购物车接口,验证发现此时返回了 newPrice数据

1.2.3.6 小结

feign远程调用怎么实现降级?

  1. 我们使用的是OpenFeign实现微服务之间的远程调用,使用Sentinel实现熔断降级。
  2. 首先配置sentinel,引入sentinel的依赖,配置sentinel的地址
  3. 服务调用方开启feign使用sentinel
  4. 服务调用方编写feign接口并编写降级逻辑,具体方法是编写降级类实现FallbackFactory接口,并在FeignClient注解中配置fallbackFactory。

降级逻辑到底谁实现?假设A调用B,希望当接口异常(异常比例、慢请求达到阈值)做降级时候能兜底

调用方:我来决定你默认返回什么

提供方:我告诉你,默认返回什么

【到底谁实现,需要靠业务来定,个人开发经验:建议提供方做实现(你不要干预一个提供接口的人默认做什么事情,这是别人的领域,也可以保证职责清晰)】

  1. 服务调用方当无法正常调用服务提供方接口时会走降级逻辑,并捕获到异常。

1.2.4. 服务熔断

1.2.4.1 配置熔断策略

根据熔断方案,sentinel会统计异常比例、慢请求比例、异常数等数据,达到阈值时断路器打开即发生熔断,熔断状态下会走降级路线保证快速响应。

下边在sentinel中配置熔断策略,找到查询商品信息的簇点链路

点击“熔断”,配置异常数,如下图:

2秒内最小请求数为2,异常数达到1发生熔断,熔断时长为20秒。

1.2.4.2 测试异常数

下边进行测试,继续停止item-service商品服务。

启动cart-service购物车服务,连续请求查询购物车接口(达到熔断条件)。

此时在购物车控制台报异常信息如下:

feign.FeignException$ServiceUnavailable: [503] during [GET] to [http://item-service/items?ids=100000006163] [ItemClient#queryItemByIds(Collection)]: [Load balancer does not contain an instance for the service item-service]

当异常数达到Sentinel配置将发生熔断,熔断时间20秒,此时cart-service控制台将不再输出异常信息,因为cart-service走了降级路线不再请求item-service

通过观察cart-service控制台日志可以发现,发生熔断后sentinel客户端抛出了com.alibaba.csp.sentinel.slots.block.degrade.DegradeException.

熔断时间(20秒)过后断路器成半开状态,再次请求购物车接口, 会尝试请求item-service一次,如果成功此时断路器关闭,如果仍失败断路器打开,关闭item-service日志发现输出一次java.lang.RuntimeException: 测试异常,此时断路器打开继续熔断

1.2.4.3 测试慢调用比例(自行测试)

下边测试另一种熔断策略:慢调用比例

删除原来的熔断策略

添加新的熔断策略。

这种是按照慢调用比例来做熔断,上述配置的含义是:

  • RT (Response Time接口响应时间),超过200毫秒的请求调用就是慢调用
  • 统计最近3000ms内的最少2次请求,如果慢调用比例大于等于50%,则触发熔断
  • 熔断持续时长20s

修改item-service的查询商品信息接口,添加线程休眠模拟处理时间,这样可以制造慢请求的效果。

重启item-service服务

连续请求查询购物车接口,cart-service连续向item-service发生请求,由于每次请求item-service线程休眠1秒导致接口请求时长肯定大于200毫秒,最终发生了熔断。

参考测试“异常数”熔断策略去观察cart-service和item-service的日志来判断熔断发生的情况。

1.2.4.4 测试异常比例(自行测试)

请大家自行测试熔断策略: 异常比例

举例:

  • 统计最近3000ms内的最少2次请求,如果异常比例不低于0.5,则触发熔断
  • 熔断持续时长20s

1.2.4.5 面试题

你的项目中熔断降级怎么实现的?

相关文章
SpringCloud极简入门-Feign开启Hystrix
1.支付服务集成Hystrix 官方文档:https://cloud.spring.io/spring-cloud-static/Greenwich.SR5/single/spring-cloud.html#spring-cloud-feign-hystrix 支付服务 springcloud-pay-server-1040 之前集成了Feign,修改该工程集成Hystrix。我们除了要给Feign开启Hystrix以外还需要为Feign接口编写托底类。
547 0
|
机器人 新能源
免费MES/免费生产管理系统
 什么是MES系统呢?MES系统主要功能就是解决“如何生产”的问题。    通过实施MES系统,一站式解决您所困扰的所有生产制作流程问题。心动就点击下方评论区链接获取MES系统免费下载吧。
1046 0
|
运维 数据可视化 搜索推荐
低代码平台:10分钟从入门到原理
低代码平台:10分钟从入门到原理
1045 0
|
21天前
|
传感器 人工智能 架构师
2026实战蓝图:AI Agent全栈开发培训流程与AI Agent职业路线进阶指南
摘要: 2026年,大模型正式进入“行动元年”。AI Agent(智能体)已从的对话接口转变为具备自主逻辑、环境感知与复杂协作能力的数字员工。本文将深度拆解从LLM向Agent覆盖的技术基础逻辑,规划从初级开发者到Agent架构师的职业路径,并提供一套简单的工程化的培训方法论。
405 3
|
4月前
|
移动开发 JavaScript 安全
热更新:移动应用的“空中加油”技术-详解什么是热更新?-优雅草卓伊凡 卓伊凡的挑战
热更新:移动应用的“空中加油”技术-详解什么是热更新?-优雅草卓伊凡 卓伊凡的挑战
433 12
热更新:移动应用的“空中加油”技术-详解什么是热更新?-优雅草卓伊凡 卓伊凡的挑战
|
3月前
|
机器学习/深度学习 人工智能 API
构建AI智能体:二十四、RAG的高效召回方法论:提升RAG系统召回率的三大策略实践
本文探讨了检索增强生成(RAG)系统中的高效召回技术。RAG系统通过检索相关文档增强大语言模型的回答质量,但性能受制于垃圾进,垃圾出原则。为提高召回效果,文章重点分析了三种方法:Small-to-Big通过大小文本块映射兼顾检索精度与上下文丰富度;索引扩展(如HyDE)利用大模型生成假设文档来优化检索;双向改写弥合用户查询与文档表述的差异。这些方法从不同角度解决了RAG系统中的语义鸿沟、词汇不匹配等核心问题,可单独或组合使用。高效召回技术能显著提升RAG系统的回答质量和效率。
565 5
|
23天前
|
人工智能 搜索推荐 数据库
从零搭建RAG系统:原理剖析+代码实践,解锁大模型“记忆力”新姿势
RAG(检索增强生成)为大模型配备“外接大脑”,通过连接专属知识库,提升回答准确性。广泛应用于医疗、法律、客服等领域,兼具专业性与可解释性。本文详解其原理、实战步骤与优化技巧,助你快速构建个性化AI助手。
486 11
|
Web App开发 存储 前端开发
Chrome浏览器的跨域问题
Chrome浏览器的跨域问题
1008 128
|
NoSQL Java 数据处理
基于Redis海量数据场景分布式ID架构实践
【11月更文挑战第30天】在现代分布式系统中,生成全局唯一的ID是一个常见且重要的需求。在微服务架构中,各个服务可能需要生成唯一标识符,如用户ID、订单ID等。传统的自增ID已经无法满足在集群环境下保持唯一性的要求,而分布式ID解决方案能够确保即使在多个实例间也能生成全局唯一的标识符。本文将深入探讨如何利用Redis实现分布式ID生成,并通过Java语言展示多个示例,同时分析每个实践方案的优缺点。
530 8
|
消息中间件 中间件 Kafka
RocketMQ源码(二)消息消费的模式到底是Push还是Pull?
RocketMQ源码(二)消息消费的模式到底是Push还是Pull?
483 1