在分布式环境中,不可避免地会有许多服务依赖项中的某些服务失败而导致雪崩效应,Hystrix是一个库,可通过添加等待时间容限和容错逻辑来帮助您控制这些分布式服务之间的交互,Hystrix通过隔离服务之间的访问点,停止服务之间的级联故障并提供后备选项来实现此目的,所有这些都可以提高系统的整体稳定性。
在微服务架构中,一个请求需要调用多个服务是非常常见的。若一个服务在请求另一个服务中,出现大量的请求时,容器的线程资源就会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,造成连锁反应,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。
雪崩的根本原因来源于服务之间的强依赖,可以提前做好评估服务容错,解决方案大概可以分为以下几种:
请求缓存:支持将一个请求与返回结果做缓存处理;
请求合并:将相同的请求进行合并然后调用处理接口;
服务隔离:限制调用分布式服务的资源,某一个调用的服务出现问题不会影响其他服务调用;
服务熔断:牺牲局部服务,保全整体系统稳定性的措施;
服务降级:服务熔断以后,客户端调用自己本地方法返回缺省值。
需要准备两个服务,一个服务可以调用另一个服务
安装Redis
需要添加如下两个依赖 redis和对象池依赖
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis
implementation("org.springframework.boot:spring-boot-starter-data-redis:2.7.1")
// https://mvnrepository.com/artifact/org.apache.commons/commons-pool2
implementation("org.apache.commons:commons-pool2:2.11.1")
需要在启动类加注解,在配置文件中修改,以及自定义redis的配置文件,最后,使用注解的方式,在接口上注解即可
// https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix
implementation("org.springframework.cloud:spring-cloud-starter-netflix-hystrix:2.2.10.RELEASE")
启动类需要加注解 @EnableCircuitBreaker 开启熔断注解
线程池隔离
通过每次都开启一个单独线程运行。它的隔离是通过线程池,即每个隔离粒度都是个线程池,互相不干扰。线程池隔离方式,等于多了一层的保护措施,可以通过hytrix直接设置,超时后直接返回
请求线程和调用Provider线程不是同一个线程,支持超时,支持熔断,支持同步和异步。资源消耗大,大量线程的上下文切换,排队,调度等,无法传递Http Header
信号量隔离
每次调用线程,当前请求通过计数信号量进行限制,当信号量大于最大请求数时,进行限制,调用fallback接口快速返回。信号量的调用是同步的,也就是说,每次调用都得阻塞调用方的线程,直到结果返回,这样就导致了无法对访问做超时(只能依靠调用协议超时,无法主动释放)
请求线程和调用Provider线程是同一个线程,不支持超时,支持熔断,同步调用,不支持异步,可以传递Http Header
服务熔断一般是指软件系统中,由于某些原因使得服务出现过载现象,为了防止造成整个系统故障,从而采用的一种保护措施,在很多地方称之为过载保护
添加依赖
// https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix
implementation("org.springframework.cloud:spring-cloud-starter-netflix-hystrix:2.2.10.RELEASE")
//声明需要服务熔错的方法
//服务熔断
@HystrixCommand(commandProperties = {
//10s内请求数大于10个就自动启动熔断器,当请求符合熔断条件触发fallbackMethod 默认20个
HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD,
value = "10"),
//请求错误率大于50%就自动熔断器,然后 for 循环发起重试请求,当请求符合熔断条件触发 fallbackMethod
HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE,
value = "50"),
//熔断多少秒后去重试请求 ,默认 5秒
HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS,
value = "5000"),
}, fallbackMethod = "selectProductByIdFallback")
override fun getOne(id:String): String {
return "这是商品One个$id"
}
服务不可用了,直接快速返回托底数据,先保留核心业务,保证服务的可用,后续慢慢再去将服务修正
触发条件:
方法抛出非 HystrixBadRequestException 异常
方法调用超时
熔断器开启拦截调用
线程池/队列/信号量跑满
需要添加依赖
// https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix
implementation("org.springframework.cloud:spring-cloud-starter-netflix-hystrix:2.2.10.RELEASE")
//声明需要服务容错的方法
//服务降级
@HystrixCommand(fallbackMethod = "selectProductByIdFallback")
override fun getTwo(id:String): String {
return "这是商品Two个"+orderService.selectTwo(id)
}
服务提供者添加 openfeign 依赖,openfeign 默认集成了 hystrix依赖,所以无需另外添加
server:
port: 9091
spring:
application:
name: service-consumer
eureka:
client:
register-with-eureka: false
registry-fetch-interval-seconds: 10
service-url:
service-url:
defaultZone: http://localhost:8761/eureka/
#Feign 开启 Hystrix 支持
feign:
hystrix:
enabled: true
import com.product_service.fallback.ProductServiceFallback
import org.springframework.cloud.openfeign.FeignClient
import org.springframework.stereotype.Service
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
@FeignClient("order-service", fallback = ProductServiceFallback::class)
@Service
interface OrderService {
@GetMapping("/order/two/{id}")
fun selectTwo(@PathVariable id : String): String
}
托底类
import com.product_service.service.OrderService
import org.springframework.stereotype.Component
@Component
class ProductServiceFallback : OrderService {
override fun selectTwo(id: String): String {
return "这是托底数据 id $id"
}
}