上一篇文章提到我們最近開了個新項目,目的是將新的業務放到新項目中,老項目單獨維護,再逐步遷移老項目到新項目里。但就在前端時間生產環境發生了一個事故,事故開始的異常是我們的業務發現前端h5頁面辦理很慢,這台服務器跑了三個省的辦理業務,同事在尋找問題的時候一口老血差點吐出來,所有的項目日志打在一個文件里,里面亂的程度無法用語言形容,因為太忙了的原因,這個事情被安了一個網絡不好的頭銜不了了之了,但是最氣的是周五晚上下班后越來越多的業務反應,大家沒有帶裝備,只能在群里猜測分析各種原因,不得已周六大家來到公司尋找這個問題,看了近幾天的日志發現是項目里一個統計的接口被頻繁調用導致我們的cpu跟內存跑滿了,拋開程序效率問題與sql效率的問題,發現是同一個ip一直在請求我們,一天刷了8萬多請求,這就不繼續吐槽了。程序完全沒有做任何容錯措施,先不說限流,就對於接口調用超時的情況我們就可以用到我們要說的hystrix。他的代碼托管在github上:
來自:https://github.com/Netflix/Hystrix/wiki
簡單的說他可以幫我們完成程序在出錯或者延遲的情況下對程序熔斷降級,假設我們老項目有這種機制,我們內存跟cpu跑滿的情況下,我就可以熔斷,將主邏輯降級,由我們輔邏輯來快速返回前端,這樣c端用戶體驗感就沒有那么差,我們也不會那么狼狽的去找問題。springcloud已經幫我們集成好了,我們只需要添加少量的注解跟配置就可以使用了。
一、使用
上一片文章最后我們用feign搭建好了一個項目,在pom文件添加配置:
改造之前寫過的controller:
我們發送20個請求,等前15個發送完成我們休息6秒,前15個請求我們演示熔斷器打開並降級的過程,后5個演示當服務端恢復正常的熔斷器關閉的情況:
繼續改造service,feign集成了hystrix,hystrix使用是通過方法來完成降級邏輯的,使用feign是通過接口的方式調用的,所以使用起來需要在
@FeignClient注解添加參數:
fallback標注了降級方法的類,創建降級類
配置文件添加配置feign集成hystrix在spring cloud早期的版本是默認開啟的,如果使用了feign就默認開啟了斷路器,所以后來的版本斷路器功能就默認關閉,
下面介紹幾個重要的參數配置:
1.hystrix.command.default.circuitBreaker.requestVolumeThreshold:用來設置快照時間窗內的請求下線,默認為20,在一個快照
時間窗內的收到請求沒有達到這個數量即使都失敗也不會觸發熔斷
2.hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds:用來是設置斷路器半開狀態的時間(斷路器在半開狀態
允許發送一條請求,如果請求成功斷路器關閉,失敗則繼續斷開等待下一次半開狀態)默認5000毫秒
3.hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds:用來設置請求超時時間
4.hystrix.command.default.circuitBreaker.errorThresholdPercentage:用來設置錯誤率,默認值50,在一個快照時間窗內超過了
請求下線,失敗率超過50%,斷路器打開
上面寫的配置為全局默認的配置,配置的優先級從低到高分別是:全局默認配值,全局屬性配置,實例默認值,實例配置屬性,列舉一個隔離策略配置
實例屬性配置需要將default改成你的就可以了,除此之外還有很多配置,分享一個鏈接:https://www.cnblogs.com/520playboy/p/8074347.html,spring cloud微服務實戰這本書里有更詳細的配置詳解ribbon.OkToRetryOnAllOperations
:對所有操作請求都進行重試ribbon.MaxAutoRetriesNextServer
:切換實例的重試次數ribbon.MaxAutoRetries
:對當前實例的重試次數
除了上面的配置我們還需要添加一個配置,目的是關閉feign的重試機制,原因是不想讓接口超時觸發重試機制。feign是通過整合ribbon來完成負載均衡,默認重試測試時5次,可以看feign包下的Retryer類,里面
的default方法。繼續,我們修改上篇文章的服務提供者的方法:

代碼完成:我們來訪問接口:http://localhost:8886/add
客戶端控制台:

服務端控制台:

通過兩端的打印信息可以看出來前總共調用20次,15次調用后等待了6秒繼續調用五次,服務端收到請求15次從入參能看出來第11次到第15次沒有請求到服務端,這個過程就演示了熔斷器的整個過程,我們通過配置文件
設置請求下限為10,而服務端的前10次請求都會調用超時,所以客戶端前10次請求都會觸發降級方法,最終熔斷,使得我們的請求快速返回,第16到第20次的時候由於線程休息了6秒,此時斷路器的半開時間早已經達到,所
以第16次請求的時候hystrix會放行一個請求,發現沒有超時,熔斷器關閉,后面的16-20請求就反會正常結果,程序又切回主邏輯。
演示一下ribbon使用hystrix,使用上一篇文章創建的項目,添加pom文件,創建一個service把邏輯放到service中:

在需要熔斷的方法添加@HystrixCommand注解,標注降級方法,修改controller方法,訪問:http://localhost:8884/add
二、工作流程
通過上面的例子我們簡單分析一下hystrix流程,我們先引用一張HystrixCircuitBreaker官方的流程圖:
第一步:HystrixCommand調用allowRequest方法判斷請求是否允許通過,如果熔斷器強制打開不允許放行,如果熔斷器強制關閉允許放行,circuitBreaker.forceOpen配置優先級比circuitBreaker.forceClosed優先級高
第二步:調用isopen方法判斷熔斷器是否打開,如果打開則判斷circuitBreaker.sleepWindowInMilliseconds進入半開模式的時間,如果距離上一次打開時間超過設置時間,將進入半開模式,放行一個請求,走第一步
第三步:熔斷器未打開,判斷一個請求窗內的請求下線circuitBreaker.requestVolumeThreshold,小於放行,否則判斷一個時間窗內的錯誤率小於circuitBreaker.errorThresholdPercentage,則放行,大於則打開熔斷器,走第二部
三、淺談源碼
我們從feign包下找到HystrixFeign類,里面有幾個方法,第一個創建HystrixInvocationHandler:
第二個方法初始化HystrixCommand的setterFactory工廠
HystrixInvocationHandler類里調用invoke(太長就不截圖了)方法重寫了降級方法,通過代理模式將hystrix包裝feign。通過toSetters方法給方法設置配置項
setterFactory里通過create方法生成配置項
groupKey是接口名稱,還有一個commandKey,繼續往下:
通過接口名跟方法名屬性名拼接生成commandKey,文章上面寫到幾個屬性的配置以hystrix.command.default.circuitBreaker.requestVolumeThreshold為例,我們這樣配置是設置了全局默認屬性配置,通過上面的分析我們可以改成這樣配置hystrix.command.AddService.circuitBreaker.requestVolumeThreshold,這就是上面提到的事例默認值配置,對應我們剛剛寫的類:
我們再來看看hystrix的配置類HystrixCommandProperties,它包含了大量配:
通過片段能看出來傳入一個前綴,然后拼接key加上后面的字符串然后為屬性賦值,這個key就是我們前面講到的configKey,沒有配置采用默認key。
文章前端時間就寫了,由於來了一個比較急的工作,忙的連着幾個通宵所以一直沒有發布,寫的時候也有遺漏,還請大家多多指教。