服务熔断是一种应对分布式系统中服务雪崩效应的保护机制。当某个服务的失败率达到一定阈值时,Hystrix 会自动开启熔断器,在一段时间内停止对该服务的所有请求,直接返回预设的降级响应,从而避免故障服务对整个系统的影响进一步扩大。
注意,熔断器一旦启动,则会停止调用具体服务逻辑,通过 fallback 快速返回托底数据,保证服务链的完整。
熔断器有自动恢复机制,如:当熔断启动后,每隔 5 秒,尝试将新的请求发送给应用服务器,如果服务可正常执行并返回结果,则关闭熔断器,服务恢复。如果仍旧调用失败,则继续返回托底数据,熔断器持续开启状态。如下图:
注意:服务降级是出错了返回托底数据,而熔断是出错后,如果开启了熔断将会在一定时间内不再访问应用服务,而是返回托底数据。
简单来说,服务降级指服务出现错误时,直接返回托底数据(依然调用目标服务)。服务熔断指错误请求量达到一个阈值时,不再调用目标服务(避免给目标服务造成压力)。
服务熔断:通常是基于服务的失败率等指标来触发的。当服务的失败次数在一定时间内达到或超过设定的阈值时,熔断器会自动打开,阻断对该服务的请求。
服务降级:一般是由于系统的整体负载过高、资源紧张或者服务出现部分故障等原因,为了保障核心业务的正常运行,主动地对一些非核心功能或服务进行降级处理,降低系统的资源消耗和压力。
服务熔断:主要目的是防止故障服务对整个系统造成雪崩效应,避免因一个服务的故障而导致整个系统的瘫痪,从而保护系统的整体稳定性和可用性。
服务降级:重点在于在系统面临压力或故障时,优先保障核心业务的正常运行,同时尽可能地为用户提供部分可用的功能或服务,以牺牲非核心功能的完整性或性能为代价,来换取系统的整体稳定性和核心业务的可用性。
服务熔断:是在服务调用出现大量失败后,为了避免故障的进一步扩散而立即执行的一种保护机制,它会在短时间内快速切断对故障服务的所有请求,直接返回降级响应。
服务降级:可以在系统运行过程中,根据系统的负载情况、资源使用情况等因素,提前或动态地对非核心服务进行降级处理,也可以在服务调用出现异常时作为一种兜底的处理方式,但它并不一定是因为服务的失败率达到了熔断的阈值才执行。
服务熔断:具有自动恢复机制,当熔断器进入半开状态后,会根据一定的规则放行少量请求来测试服务是否恢复正常,如果服务恢复则自动关闭熔断器,恢复正常的服务调用;如果服务仍然不可用,则继续保持熔断状态。
服务降级:一般需要等到系统的负载降低、资源充足或者故障服务修复后,再根据具体情况手动或自动地恢复被降级的服务或功能,恢复的时机和条件相对更加灵活和多样化,不像熔断那样有固定的半开状态和自动重试机制。
第一步:使用 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 请求。如下图:
通过上图可知,成功触发了熔断功能。点击查看Netflix Hystrix 常用属性