問題分析:了解Hystrix的功能,同時也能從Hystrix優秀的設計理念中得到架構設計方面的啟發。
答案:我在專案裡使用到,系統在Hystrix 的保護下,可以長期處於高可用的狀態,常用的功能有以下幾點:
Hystrix設計中提供了fail-fast(快速失敗)和快速復原機制。
Tip:不知道之前你是否了解過fail-fast機制,或是面試Java基礎的時候,HashMap 中的Iterator 迭代器,Iterator的設計就是fail-fast 的,**快速失敗(fail— fast)**是Java集合中的一種機制, 在用迭代器遍歷一個集合物件時,如果遍歷過程中對集合物件的內容進行了修改(增加、刪除、修改),則會拋出Concurrent Modification Exception 。
我第一次學習HashMap 並不是很懂fail-fast,覺得快速失敗只是應用在Java集合類別中,防止Java非執行緒安全集合的並發操作,學習使用Hystrix 後,原來快速失敗機制也可以應用在系統架構設計中,對無法及時處理的請求快速失敗(fail-fast),降低系統負載,而不是排隊。
Fallback 字面上就是遇到Fall就啟動back,了解到Fallback的機制後,我馬上在專案中用起來。
看真實範例:
@Override @Degrade(key = "getOrderByParamFromES", fallBackMethod = "getOrderByParamFromMysql") public OrderResult getOrderByParamFromES(OrderSearchParam param) { //走ES查询 ...... return OrderResult; } //fallBack后调用getOrderByParamFromMysql方法 public OrderResult getOrderByParamFromMysql(OrderSearchParam param) { //走mysql查询 ...... return OrderResult; }
程式碼解釋:
fallBackMethod = "getOrderByParamFromMysql"
#就是在ES查詢故障失敗後,系統自動降級調getOrderByParamFromMysql方法,走mysql查詢,正常情況下,getOrderByParamFromMysql是不會被呼叫的,除非Fall。
#請求會根據自己的key取得對應執行緒池中的執行緒執行,動態設定執行緒池參數,這樣自然地將不同的請求隔離開來,支援非同步來提高介面效能。不同請求直接不影響,例如service1請求緩慢,但是service2和service3還是可以正常運作,缺點就是執行緒切換影響效能。
一個請求中存取了service1、service2、service3,其中service1請求逾時,將導致整個信號量一直不釋放,其他請求一直無法接受。
對於延遲小的請求(例如存取快取或本地存取資料庫)來說,執行緒池帶來的開銷是非常高的,你可以考慮採用其他方法,例如非阻塞信號量(不支援逾時)來實現依賴服務的隔離。但絕大多數情況下,Netflix 更偏向於使用執行緒池來隔離依賴服務,因為其帶來的額外開銷可以接受,並且能支援包括逾時在內的所有功能。
問題分析:檢視實際使用經驗,根據執行緒本身的特點,執行緒逾時,如果不及時中斷,會浪費執行緒資源。
答:一般情況下我們會開啟超時中斷開關,目的是及時釋放執行緒資源。
透過hystrix.command.default.execution.isolation.thread.interruptOnTimeout = true 設定。
但是如果是寫入資料庫指令,或是記錄關鍵日誌指令的情況下,需要指令執行完畢情況,可關閉逾時中斷。
(面試官點頭滿意,相信我確實有Hystrix的維護經驗)
答案:要正確設定執行緒池的大小,需要分析所部署系統的CPU個數、記憶體大小、任務類型(計算密集、IO密集等),對於運算密集型任務,執行緒池大小和CPU個數相近通常能達到最佳使用率,對於IO密集型任務,執行緒池的最優大小的運算公式:執行緒池大小=CPU個數* (1 任務等待時間/ 任務處理時間)。
Hystrix源自Netflix API團隊於2011年開始的專案。 2012年,Hystrix不斷發展成熟,Netflix內部的許多團隊都採用了它。如今,每天在Netflix上透過Hystrix執行數百億個執行緒隔離和數千億個信號量隔離的呼叫。這極大地提高了正常運作時間和彈性。
在高並發存取下,系統所依賴的服務的穩定性對系統的影響非常大,依賴有很多不可控的因素,例如網路連線變慢,資源突然繁忙,暫時不可用,服務脫機等。我們要建構穩定、可靠的分散式系統,就必須要有這樣一套容錯方法。
熔断器机制:熔断器可以理解成保险丝,项目里使用Hystrix Command,当 Hystrix Command请求后,如果服务失败数量超过一定比例(比如默认50%),断路器自动熔断,该服务将进入熔断状态,后续请求都会进入fallback。
降级机制:通过fallbackMethod注解,当请求后端服务出现异常的时候, 为了避免影响到其他业务逻辑,可以使用fallback方法指定的方法快速返回,或启用“备胎方案”。
环境隔离:包括线程隔离和信号量隔离。
cache:Hystrix支持将一个请求结果缓存起来,下一个具有相同key的请求将直接从缓存中取出结果,减少请求开销。
通过一个demo快速理解Hystrix fallback 的使用
@Service public class OrderQueryService { /** * 订单查询接口 */ @HystrixCommand(fallbackMethod = "queryOrderBack") public List<Order> queryOrderFromRedis(String userId) { // todo reids查询逻辑 return orderlist; } /** * 订单查询接口失败降级方案 */ @SuppressWarnings("unused") private String queryOrderBack(String userId) { // todo 如,走ES查询逻辑 或者 直接提示用户“请稍后再试” // todo 通知维护人员处理故障 return ""; } }
代码解释:
程序正常时,查询订单服务是走queryOrderFromRedis方法的逻辑,当queryOrderFromRedis方法抛出异常,根据设定的异常比例,或者指定哪个异常,达到阈值触法fallback开关,程序切换到queryOrderBack,设置程序走ES查询逻辑 或者 直接提示用户“请稍后再试”,根据业务自行设置。
Failure Type | Exception class | Exception.cause | 触发fallback |
---|---|---|---|
FAILURE | HystrixRuntimeException | underlying exception (user-controlled) | YES |
SEMAPHORE_REJECTED | HystrixRuntimeException | j.l.RuntimeException | YES |
SHORT_CIRCUITED | HystrixRuntimeException | j.l.RuntimeException | YES |
THREAD_POOL_REJECTED | HystrixRuntimeException | j.u.c.RejectedExecutionException | YES |
TIMEOUT | HystrixRuntimeException | j.u.c.TimeoutException | YES |
FAILURE
:任意RuntimeException异常都可以激活fallback。
THREAD_POOL_REJECTED
:并发执行的任务数超过线程池和队列之和时,也就是Hystrix的线程隔离机制。
SEMAPHORE_REJECTED
:类似 THREAD_POOL_REJECTED ,当服务的并发数大于信号量阈值时将进入fallback。比如配置程序执行并发数不能大于3,由于信号量隔离下无论调用哪种命令执行方法,Hystrix都不会创建新线程执行run()/construct()
,所以调用程序需要自己创建多个线程来模拟并发调用execute()
,最后看到一旦并发线程>3,后续请求都进入fallback。
SHORT_CIRCUITED
:在一定时间内,用户请求超过一定的比例失败时,如超时,异常,线程并发达到限定最大值等,断路器都会打开;短路器打开后所有请求直接走fallback,可以通过。circuitBreakerErrorThresholdPercentage方法设置百分比,默认是50。
TIMEOUT
:即超时请求。
/* --------------统计相关------------------*/ // 统计滚动的时间窗口,默认:5000毫秒(取自circuitBreakerSleepWindowInMilliseconds) private final HystrixProperty metricsRollingStatisticalWindowInMilliseconds; // 统计窗口的Buckets的数量,默认:10个,每秒一个Buckets统计 private final HystrixProperty metricsRollingStatisticalWindowBuckets; // number of buckets in the statisticalWindow // 是否开启监控统计功能,默认:true private final HystrixProperty metricsRollingPercentileEnabled; /* --------------熔断器相关------------------*/ // 熔断器在整个统计时间内是否开启的阀值,默认20。也就是在metricsRollingStatisticalWindowInMilliseconds(默认10s)内至少请求20次,熔断器才发挥起作用 private final HystrixProperty circuitBreakerRequestVolumeThreshold; // 熔断时间窗口,默认:5秒.熔断器中断请求5秒后会进入半打开状态,放下一个请求进来重试,如果该请求成功就关闭熔断器,否则继续等待一个熔断时间窗口 private final HystrixProperty circuitBreakerSleepWindowInMilliseconds; //是否启用熔断器,默认true. 启动 private final HystrixProperty circuitBreakerEnabled; //默认:50%。当出错率超过50%后熔断器启动 private final HystrixProperty circuitBreakerErrorThresholdPercentage; //是否强制开启熔断器阻断所有请求,默认:false,不开启。置为true时,所有请求都将被拒绝,直接到fallback private final HystrixProperty circuitBreakerForceOpen; //是否允许熔断器忽略错误,默认false, 不开启 private final HystrixProperty circuitBreakerForceClosed; /* --------------信号量相关------------------*/ //使用信号量隔离时,命令调用最大的并发数,默认:10 private final HystrixProperty executionIsolationSemaphoreMaxConcurrentRequests; //使用信号量隔离时,命令fallback(降级)调用最大的并发数,默认:10 private final HystrixProperty fallbackIsolationSemaphoreMaxConcurrentRequests; /* --------------其他------------------*/ //使用命令调用隔离方式,默认:采用线程隔离,ExecutionIsolationStrategy.THREAD private final HystrixProperty executionIsolationStrategy; //使用线程隔离时,调用超时时间,默认:1秒 private final HystrixProperty executionIsolationThreadTimeoutInMilliseconds; //线程池的key,用于决定命令在哪个线程池执行 private final HystrixProperty executionIsolationThreadPoolKeyOverride; //是否开启fallback降级策略 默认:true private final HystrixProperty fallbackEnabled; // 使用线程隔离时,是否对命令执行超时的线程调用中断(Thread.interrupt())操作.默认:true private final HystrixProperty executionIsolationThreadInterruptOnTimeout; // 是否开启请求日志,默认:true private final HystrixProperty requestLogEnabled; //是否开启请求缓存,默认:true private final HystrixProperty requestCacheEnabled; // Whether request caching is enabled //请求合并是允许的最大请求数,默认: Integer.MAX_VALUE private final HystrixProperty maxRequestsInBatch; //批处理过程中每个命令延迟的时间,默认:10毫秒 private final HystrixProperty timerDelayInMilliseconds; //批处理过程中是否开启请求缓存,默认:开启 private final HystrixProperty requestCacheEnabled; /* 配置线程池大小,默认值10个 */ private final HystrixProperty corePoolSize; /* 配置线程值等待队列长度,默认值:-1 建议值:-1表示不等待直接拒绝,测试表明线程池使用直接决绝策略+ 合适大小的非回缩线程池效率最高.所以不建议修改此值。 当使用非回缩线程池时,queueSizeRejectionThreshold,keepAliveTimeMinutes 参数无效 */ private final HystrixProperty maxQueueSize;
其他常用限流降级组件
Sentinel
:阿里巴巴集团内部基础技术模块,覆盖了所有的核心场景。Sentinel 也因此积累了大量的流量归整场景以及生产实践。2018 年,Sentinel 开源,并持续演进。
Resilience4j
:也是一个轻量级的容错组件,其灵感来自于 Hystrix,但主要为 Java 8 和函数式编程所设计。轻量级体现在其只用 Vavr库(前身是 Javaslang),没有任何外部依赖。而 Hystrix 依赖了 Archaius ,Archaius 本身又依赖很多第三方包,例如 Guava、Apache Commons Configuration 等。
Sentinel | Hystrix | resilience4j | |
---|---|---|---|
隔离策略 | 信号量隔离(并发线程数限流) | 线程池隔离/信号量隔离 | 信号量隔离 |
熔断降级策略 | 基于响应时间、异常比率、异常数等 | 异常比率模式、超时熔断 | 基于异常比率、响应时间 |
实时统计实现 | 滑动窗口(LeapArray) | 滑动窗口(基于 RxJava) | Ring Bit Buffer |
动态规则配置 | 支持多种配置源 | 支持多种数据源 | 有限支持 |
扩展性 | 丰富的 SPI 扩展接口 | 插件的形式 | 接口的形式 |
基于注解的支持 | 支持 | 支持 | 支持 |
限流 | 基于 QPS,支持基于调用关系的限流 | 有限的支持 | Rate Limiter |
集群流量控制 | 支持 | 不支持 | 不支持 |
流量整形 | 支持预热模式、匀速排队模式等多种复杂场景 | 不支持 | 简单的 Rate Limiter 模式 |
系统自适应保护 | 支持 | 不支持 | 不支持 |
控制台 | 提供开箱即用的控制台,可配置规则、查看秒级监控、机器发现等 | 简单的监控查看 | 不提供控制台,可对接其它监控系统 |
多语言支持 | Java / C++ | Java | Java |
开源社区状态 | 活跃 | 停止维护 | 较活跃 |
以上是java的降級元件Hystrix有哪些功能的詳細內容。更多資訊請關注PHP中文網其他相關文章!