一、feign超時配置失效
最近項目上遇見feign超時配置總是失效。導致feign調用超過2s之后就會超時,會進行自動重試,重復調用兩次服務,並且還是指定接口。這就更加奇怪。最后通過觀察以及源碼調試,發現問題所在。在這里先說下原因。
原因:同一個服務feign組件做了拆分,使用contextId對feign拆分后的feign做了聲明。配置超時配置的時候,不能再使用feign組件注解 @FeignClient里的name去做配置了,而應該是contextId里的名稱
示例代碼:
//A服務的基礎業務接口 @FeignClient(contextId = "AServer", name = "AServer", configuration = FeignConfiguration.class) public interface ABaseServer { } //A服務的個性化業務接口 @FeignClient(contextId = "ASpecialServiceServer", name = "AServer", configuration = FeignConfiguration.class) public interface ASpecialServer { } //上面是對feign拆分后的聲明 //錯誤的yml配置 feign: client: config: #這里仍然使用了name作為超時配置,那么只有ABaseServer 里面聲明的接口才會使用以下的配置,因為恰巧ABaseServer的contextId名稱是AServer。 AServer: connectTimeout: 60000 readTimeout: 60000 //正確的yml配置,手段一:配置上以contextId為聲明來配置 feign: client: config: #基礎業務接口的超時配置 AServer: connectTimeout: 60000 readTimeout: 60000 #個性化業務接口的超時配置 ASpecialServiceServer: connectTimeout: 50000 readTimeout: 50000 //正確的yml配置,手段二:A服務全部使用default全局配置,Bserver單獨聲明,並不會使用全局配置 feign: client: config: default: connectTimeout: 60000 readTimeout: 60000 BServer: connectTimeout: 30000 readTimeout: 30000
feign內部集成了ribbon做為了負載均衡的組件,ribbon也有相關超時配置,feign的超時配置不當也會造成超時失效,關於如何配置可以參考之前的一篇博客:https://www.cnblogs.com/wa1l-E/p/13994240.html
這次feign的超時不生效,主要原因是,項目上做了一次feign的拆分,即A服務調用B服務的接口由於過多,接口從功能模塊和業務上做了feign組件的拆分,也就是spring容器中會有兩個feign針對同一個服務。
問題1:拆分后,springboot在啟動時,會報錯,原因是針對同一個服務有多個feign 實例,而spring容器又默認是單例加載。
解決這個問題有兩個方案:
1、
2、在feign注解定義上加上contextId來避免啟動報錯。示例代碼如下:
@FeignClient(name = "A", contextId = "ABaseServiceServer", configuration = FeignConfiguration.class) public interface AServer { } @FeignClient(name = "A", contextId = "ACustomServiceServer", configuration = FeignConfiguration.class) public interface AServer { }
都是同一個服務的feign組件,但是contextId不同,解決了問題。
項目上采用了第二種解決手段,但也正是因為對解決問題沒有做到追根刨底的精神,導致引入了feign超時失效的原因。
問題2:使用ContextId對feign做聲明后,導致部分接口超時失效。
結論:在開篇時,結論已經說過,這里就不再贅述。主要說下原因以及定位問題的過程和解決方法。
定位過程:發現該問題時,首先發現是部分接口失效,當然是測試並觀察,發現只有未使用contextId配置的feign組件的接口會超時。但是當時並不知道是contextId的聲明影響。所以果斷開撕源碼。定位問題
首先Feign有一個內部類Builder,聽名字就知道使用了建造者是設計模式,建造者適合創造屬性多變的對象, 而Feign恰好具備這種特性,使用建造者設計模式在適合不過了。
Builder類有一個屬性Options option這個Options類就是feign的超時配置聲明。如下圖:
再來看一下UML圖
可以看到真正的配置就是再容器初始話feign的時候,初始化 builder的時候使用的配置就是真正使用的配置。那么接下來就好辦了,使用我之前講過的源碼調試大法,開始調試,啟動服務,斷點開啟,最后一路追蹤,發現實例化的代碼如下:
不知道啟動后怎么調試找到相關代碼的同學可以參考另一篇博客:https://www.cnblogs.com/wa1l-E/p/14115042.html 還是一句話,動手多實踐。
97行見名其義:初始化Feign.builder,109行是關鍵代碼,看名字就知道,配置feign,那么builder的option一定是在這里初始化的,我們一路追進去看看
到了上面的方法中,我們發現了尤其重要的兩行代碼,看名字就知道使用configure配置屬性,那么在這里一定是使用配置去初始話Feign的超時相關配置,沒有的話會使用默認的配置。
這里的方法就不贅述了,有興趣的同學可以去斷點看看,最關鍵的另一個發現是 在獲取配置的時候,使用的是
contextId,這不由得和上面Feign注解 @FeignClient中聲明的contextId關聯起來,最后通過調試也發現,確實是這樣。contextId源碼注釋是bean的顯實聲明名稱,如果不配置默認使用beanName.到這里就發現問題了。
那么解決手段就簡單了
解決手段:
手段一:如果拆分后的接口不需要做特殊的超時配置區分,那么使用default全局配置既可,至於其他的feign客戶端,在做配置,便不會使用全局的配置。
手段二:如果拆分后的接口,超時配置是不一樣的,那么使用contextId做超時配置才是正確的。
最后建議實際使用手段二,粒度更細。
二、Hystrix配置實戰:
首先介紹一下上面Feign超時后,Hystrix配置后,會自動重試的原因,然后再介紹一下Hystrix的主要配置,搭建一個Hstrix-dashboard,然后通過一個接口的測試,通過dashBoard觀察Hystrix的配置的。
1、Hystrix的配置
熔斷配置:
#hystrix熔斷器配置:(接口發生異常,服務調用方直接做熔斷處理,返回提示,避免流量過大接口調用引起雪崩。)
#如果接口發生異常,那么會熔斷,熔斷開啟。后面的請求不會再去進行服務遠程調用,直接走熔斷 #下面配置策略是: 10s滾動窗口期內,大於等於1個線程 失敗率超過百分之50,則打開熔斷開關.負責關閉熔斷開關 #熔斷開關打開后,后續請求直接走熔斷,不會進行遠程調用 hystrix.command.default.circuitBreaker.requestVolumeThreshold=1 hystrix.command.default.metrics.rollingStats.timeInMilliseconds=10000 hystrix.command.default.circuitBreaker.errorThresholdPercentage=50 #在5s后,熔斷會進入 半開狀態,會放入一部分請求進行遠程調用,如果成功,則關閉熔斷.如果失敗,則繼續打開熔斷 hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=5000
降級配置:
#hystrix降級配置:(接口發生異常,服務調用方直接對接口進行降級處理,返回托底數據。和熔斷的區別是一個有托底數據,一個沒有。)
#超時打開,設置為70s,這里的超時時間必須大於Ribbon和feign的超時,因為小於Feign正常調用超時時間,直接會熔斷. hystrix.command.default.execution.timeout.enabled=true hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=70000
2、配置Hystrix-dashboard調試Hystrix熔斷和降級配置
- 搭建Hystrix-dashboard: 沒空的同學可以直接下載我之前搭建的: https://github.com/coffeebabeCGG/spring-cloud 這里就不贅述如何搭建了
- 啟動項目后,需要填如要監控的服務地址:http://ip:port/context-path/actuator/hystrix.stream
從下圖可以看到queryByPage接口的熔斷目前是關閉狀態。關於dashboard的詳細參數說明,下面給大家補一張圖。
最后:接口postMan的runtest批量調用接口測試,通過dashBoard觀察接口的熔斷情況,配置是否生效。就可以了解Hystrix的基本使用了。