Netflix Hystrix 服务熔断

服务熔断是一种应对分布式系统中服务雪崩效应的保护机制。当某个服务的失败率达到一定阈值时,Hystrix 会自动开启熔断器,在一段时间内停止对该服务的所有请求,直接返回预设的降级响应,从而避免故障服务对整个系统的影响进一步扩大。

注意,熔断器一旦启动,则会停止调用具体服务逻辑,通过 fallback 快速返回托底数据,保证服务链的完整。

熔断器有自动恢复机制,如:当熔断启动后,每隔 5 秒,尝试将新的请求发送给应用服务器,如果服务可正常执行并返回结果,则关闭熔断器,服务恢复。如果仍旧调用失败,则继续返回托底数据,熔断器持续开启状态。如下图:

5b31fbab201176781cade222421b4e57_1731827156045-4a50719b-2a96-4222-8e37-8e94e15c4ace_x-oss-process=image%2Fformat%2Cwebp.png

注意:服务降级是出错了返回托底数据,而熔断是出错后,如果开启了熔断将会在一定时间内不再访问应用服务,而是返回托底数据。

服务熔断与降级的区别

简单来说,服务降级指服务出现错误时,直接返回托底数据(依然调用目标服务)。服务熔断指错误请求量达到一个阈值时,不再调用目标服务(避免给目标服务造成压力)。

触发条件不同

  • 服务熔断:通常是基于服务的失败率等指标来触发的。当服务的失败次数在一定时间内达到或超过设定的阈值时,熔断器会自动打开,阻断对该服务的请求。

  • 服务降级:一般是由于系统的整体负载过高、资源紧张或者服务出现部分故障等原因,为了保障核心业务的正常运行,主动地对一些非核心功能或服务进行降级处理,降低系统的资源消耗和压力。

目的略有差异

  • 服务熔断:主要目的是防止故障服务对整个系统造成雪崩效应,避免因一个服务的故障而导致整个系统的瘫痪,从而保护系统的整体稳定性和可用性。

  • 服务降级:重点在于在系统面临压力或故障时,优先保障核心业务的正常运行,同时尽可能地为用户提供部分可用的功能或服务,以牺牲非核心功能的完整性或性能为代价,来换取系统的整体稳定性和核心业务的可用性。

执行时机不同

  • 服务熔断:是在服务调用出现大量失败后,为了避免故障的进一步扩散而立即执行的一种保护机制,它会在短时间内快速切断对故障服务的所有请求,直接返回降级响应。

  • 服务降级:可以在系统运行过程中,根据系统的负载情况、资源使用情况等因素,提前或动态地对非核心服务进行降级处理,也可以在服务调用出现异常时作为一种兜底的处理方式,但它并不一定是因为服务的失败率达到了熔断的阈值才执行。

恢复机制不同

  • 服务熔断:具有自动恢复机制,当熔断器进入半开状态后,会根据一定的规则放行少量请求来测试服务是否恢复正常,如果服务恢复则自动关闭熔断器,恢复正常的服务调用;如果服务仍然不可用,则继续保持熔断状态。

  • 服务降级:一般需要等到系统的负载降低、资源充足或者故障服务修复后,再根据具体情况手动或自动地恢复被降级的服务或功能,恢复的时机和条件相对更加灵活和多样化,不像熔断那样有固定的半开状态和自动重试机制。

服务熔断示例

第一步:使用 Maven 引入 Hystrix 的依赖,请参考“Netflix Hystrix 入门实例

第二步:在 Spring Boot 项目的启动类上添加 @EnableCircuitBreaker 注解,开启 Hystrix 的断路器功能。

第三步:创建服务类,其中包含一个获取用户信息的方法,并使用 @HystrixCommand 注解来配置服务熔断和降级逻辑。代码如下:

package com.hxstrive.hystrix_demo.controller;

import com.hxstrive.hystrix_demo.dto.CommonReturn;
import com.hxstrive.hystrix_demo.entity.User;
import com.hxstrive.hystrix_demo.service.UserService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * Hystrix 熔断
 * @author hxstrive.com
 */
@RestController
@RequestMapping("/demo3")
public class Demo3Controller {

    @Autowired
    private UserService userService;

    @GetMapping("/getUserById")
    @HystrixCommand(fallbackMethod = "fallback",
        commandProperties = {
                // 配置熔断器的参数
                // 在一个滚动时间窗口内,请求的数量达到这个阈值时,Hystrix 才会开始去判断是否要开启熔断器
                @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "5"),
                // 属性定义了在满足 circuitBreaker.requestVolumeThreshold(即请求量达到一定阈值)的前提下,
                // 失败请求数量占总请求数量的百分比达到多少时,熔断器就会开启
                @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
                // 当熔断器开启之后,经过指定的这个时间(单位是毫秒),熔断器会进入半开状态。
                @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000")
    })
    public CommonReturn<User> getUserById(@RequestParam Long id) {
        // 更多参数可见 HystrixPropertiesManager 类
        return userService.getUserById(id);
    }

    /**
     * 降级方法,当服务熔断或出现异常时被调用
     */
    private CommonReturn<User> fallback(Long id) {
        return CommonReturn.fail("网络出现问题,调用 fallback 方法,id=" + id);
    }

}

第四步:开启详细日志,因为我们调用服务采用的 RestTemplate 工具类,配置如下:

logging:
  level:
    root: info
    org.springframework.web.client.RestTemplate: DEBUG

第五步:验证服务,先关闭 USER 服务,然后通过浏览器访问 http://localhost:8080/demo3/getUserById?id=1 地址,按 F5 键刷新页面,然后观察输出日志,你会发现,前五次刷新会发起 HTTP 请求,后续刷新不会发起 HTTP 请求。如下图:

77241c34c4992b446610feaa7fa0be1f_1731832818335-7a18412a-0320-4ea2-a1de-0cc4b9cb8141.gif

通过上图可知,成功触发了熔断功能。点击查看Netflix Hystrix 常用属性

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号