Hystrix简介
背景
在微服务架构的分布式系统中,众多微服务有复杂的依赖关系,这些依赖在某些情况下不可避免的会出现一些请求失败。当一个依赖由于延迟高出现阻塞,调用该依赖的服务线程就会发生排队阻塞。如果这个时候出现大量的业务流量打过来,就可能会出现服务器资源被消耗殆尽导致服务宕机。
大量请求阻塞在依赖服务导致服务宕机
对于上图的情况,每个请求都占用了系统的CPU、内存、网络等资源,如果当前服务业务请求量较高,那么所有的服务资源会被快速消耗完毕,直至应用挂掉。
对于这种情况,就需要有一个服务的保护机制——服务隔离和熔断机制,当依赖应用出现问题,不会导致下游服务出现阻塞而导致一些列的雪崩效应。
Hystrix主要功能
服务隔离
服务隔离是给每一个服务分配一定的资源,超过这个资源范围变会直接释放资源,并不会占用其他服务的资源,以达到保护其他服务的目的。
Hystrix 提供了线程和信号量两种隔离方式,以减少不同服务之间资源竞争带来的相互影响。
服务熔断
服务熔断是在高并发下,如果达到一定的极限,流量如果超过了阈值后,直接拒绝访问,从而保护当前服务。
服务降级
高并发场景下,防止某一个用户在一直等待情况,比如当超过一直的阈值时长情况,直接 fallback 返回一个相对友好的提示。
请求缓存
请求缓存保证在一次请求中多次调用同一个服务提供者接口,在 cacheKey 不变的情况下,后续调用结果都是第一次的缓存结果,而不是多次请求服务提供者,从而降低服务提供者处理重复请求的压力。
请求合并
Hystrix 的请求合并用于应对服务器的高并发场景,通过合并多个请求,减少线程的创建和使用,降低服务器请求压力,提高在高并发场景下服务的吞吐量和并发能力。
快速开始
Maven配置
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
项目启动类添加注解 @EnableCircuitBreaker
package com.venky.hystrix;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
@SpringBootApplication
@EnableCircuitBreaker
public class HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class, args);
}
}
方法上使用断路器注解
package com.venky;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 工单统计Service
*
* @author venky
* @date 2022/10/24
*/
@Service
@Slf4j
@DefaultProperties(groupKey = HystrixConfigProperties.TICKET_STAT_GROUP_KEY)
public class TicketStatCommand {
/**
* 业务服务http客户端
*/
@Autowired
private TicketClient ticketClient;
/**
* 工单统计查询
*
* @param request
* @return
* @throws Exception
*/
@HystrixCommand(fallbackMethod = "getTicketStatisticsResponseFallback",
commandKey = "getTicketStatisticsResponse")
public TicketStatisticsResponse getTicketStatisticsResponse(TicketStatisticsRequest request) throws Exception {
return ticketClient.getResponseModel(request);
}
/**
* 工单统计查询回调接口
*
* @param request
* @param t
* @return
*/
private TicketStatisticsResponse getTicketStatisticsResponseFallback(TicketStatisticsRequest request, Throwable t) {
log.error("getTicketStatisticsResponseHystrix --> enterpriseId:{},clientId:{},queueIds:{}", request.getEnterpriseId(), request.getClientId(), request.getQueueIds(), t);
return null;
}
}
其中 @DefaultProperties
是为当前断路器指定全局默认的配置。
groupKey
指定当前断路器的所在组key, 用来统计、报告,默认取类名,可不配置。相同的组的断路器会共享同一个线程池。
commandKey
用来标识一个 Hystrix 命令,默认会取被注解的方法名。需要注意:Hystrix 里同一个键的唯一标识并不包括 groupKey,建议取一个独一二无的名字,防止多个方法之间因为键重复而互相影响。
fallbackMethod
方法执行时熔断、错误、超时时会执行的回退方法,需要保持此方法与 Hystrix 方法的签名和返回值一致。
如果需要指定其他全局默认属性,可以在配置文件中新增。
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=10000
hystrix.command.default.circuitBreaker.requestVolumeThreshold=20
circuitBreaker.requestVolumeThreshold
启用熔断器功能窗口时间内的最小请求数。此配置项的值需要根据接口的 QPS 进行计算,值太小会有误打开熔断器的可能,值太大超出了时间窗口内的总请求数,则熔断永远也不会被触发。建议设置为 QPS * 窗口秒数 * 60%
。
execution.isolation.thread.timeoutInMilliseconds
方法执行超时时间,默认值是 1000,即 1秒,此值根据业务场景配置。
给单个方法指定断路器参数。
hystrix.command.getTicketStatisticsResponse.execution.isolation.thread.timeoutInMilliseconds=10000
hystrix.command.getTicketStatisticsResponse.circuitBreaker.requestVolumeThreshold=20
以上方式是为了方便后续根据线上统计情况,可以动态调整配置参数,而无需改代码重启服务,方便后续调整。当然也可以直接在代码中添加。
/**
* 测试
*
* @return
*/
@HystrixCommand(fallbackMethod = "fallback",
groupKey = "test",
commandProperties = {
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
}
)
public String test() {
return "OK";
}
public String fallback(Throwable t) {
log.error("exception", t);
return "fail";
}
总结
以上是一个常用的线上断路器的使用方式案例,下一篇我们继续解析断路器的配置,让你对配置不再迷茫。
网友评论