javascript
Spring Cloud Zuul的fallback优化
如何在Zuul中使用fallback功能
我們在項目中使用Spring cloud zuul的時候,有一種這樣的需求,就是當我們的zuul進行路由分發時,如果后端服務沒有啟動,或者調用超時,這時候我們希望Zuul提供一種降級功能,而不是將異常暴露出來。
在Dalston版本中,Spring cloud zuul提供這種降級功能,操作步驟如下:
- 在主函數上添加@EnbaleZuulProxy注解。
- 實現ZuulFallbackProvider接口。
對應ZuulFallbackProvider源碼如下:
| public interface ZuulFallbackProvider { /** * The route this fallback will be used for. * @return The route the fallback will be used for. */ public String getRoute(); /** * Provides a fallback response. * @return The fallback response. */ public ClientHttpResponse fallbackResponse(); } |
我們只要實現該接口,并實現public ClientHttpResponse fallbackResponse();方法,也就是說該方法會讓我定義一個ClientHttpResponse作為當異常出現時的返回內容。
通過源碼我們可知,Zuul提供三個配置文件,每一個配置文件代表用不同種方式進行請求的轉發:
- RestClientRibbonConfiguration
- OkHttpRibbonConfiguration
- HttpClientRibbonConfiguration(默認情況)
HttpClientRibbonConfiguration源碼如下(只體現涉及fallback模塊):
protected static class HttpClientRibbonConfiguration { (required = false) private Set<ZuulFallbackProvider> zuulFallbackProviders = Collections.emptySet(); public RibbonCommandFactory<?> ribbonCommandFactory( SpringClientFactory clientFactory, ZuulProperties zuulProperties ) { return new HttpClientRibbonCommandFactory( clientFactory, zuulProperties, zuulFallbackProviders ); } } |
通過源碼我們可以了解,Zuul將你自定義的fallbackprovider保存在一個Set集合中,并作為HttpClientRibbonCommandFactory構造器的參數。
當zuul在轉發請求時最終會利用AbstractRibbonCommand進行處理。通過源碼我們知道AbstractRibbonCommand繼承了HystrixCommand,所以真正轉發請求的業務邏輯是在重寫HystrixCommand類的run方法中進行的。
具體源碼如下:
protected ClientHttpResponse run() throws Exception { final RequestContext context = RequestContext.getCurrentContext(); RQ request = createRequest(); RS response = this.client.executeWithLoadBalancer(request, config); context.set("ribbonResponse", response); // Explicitly close the HttpResponse if the Hystrix command timed out to // release the underlying HTTP connection held by the response. // if (this.isResponseTimedOut()) { if (response != null) { response.close(); } } return new RibbonHttpResponse(response); } |
我們知道HystrixCommand提供getFallback()方法,這個方法的作用是當run()方法執行出現異常時,會自動調用getFallback()方法,從而完成降級功能。(HystrixCommand是Hystrix的知識,有興趣的同學可以參照官方git文檔)。
由于AbstractRibbonCommand繼承了HystrixCommand,它不僅重寫了run()方法,而且重寫了getFallback()方法,具體源碼如下:
protected ClientHttpResponse getFallback() { if(zuulFallbackProvider != null) { return zuulFallbackProvider.fallbackResponse(); } return super.getFallback(); } |
通過源碼我們知道,首先會去判斷是否存在自定義的zuulFallbackProvider,如果有,那么直接回調你自定義實現類的fallbackResponse()方法。如果不存在會走hystrix的fallback邏輯(有可能直接拋出異常)。
說到這里Zuul的降級原理大致就說完了,細心的朋友可以發現這樣的一個問題,就是雖然Zuul提供了降級的回調方法fallbackResponse(),但是這個方法是無參的,也就是說此時雖然你能夠給調用端返回一個消息,但是此時你并不知道發生了什么樣的異常(也就是說在這里你是獲取不到異常信息的)。
Edgware.RC1版本的改進
在Edgware.RC1版本中Spring cloud zuul針對于降級進行了升級,升級的內容主要是解決上面說到的當降級出現時,怎樣在降級方法中獲取具體的異常信息。
增加了一個接口FallbackProvider,這個接口繼承了現有的ZuulFallbackProvider接口,源碼如下:
| public interface FallbackProvider extends ZuulFallbackProvider { /** * Provides a fallback response based on the cause of the failed execution. * * @param cause cause of the main method failure * @return the fallback response */ ClientHttpResponse fallbackResponse(Throwable cause); } |
可以看到這個接口有一個方法,這個方法的參數是Throwable,也就是說此時是用能力獲取異常信息的。
接下來改造的內容在AbstractRibbonCommand類中,主要是對原有的getFallback()進行改造,同時增加了一個getFallbackResponse()方法。下面通過源碼具體了解下:
protected ClientHttpResponse getFallback() { if(zuulFallbackProvider != null) { return getFallbackResponse(); } return super.getFallback(); } |
可以看到從原來調用zuulFallbackProvider.fallbackResponse();轉而調用內部方法getFallbackResponse()。
getFallbackResponse()源碼如下:
| protected ClientHttpResponse getFallbackResponse() { if (zuulFallbackProvider instanceof FallbackProvider) { Throwable cause = getFailedExecutionException(); cause = cause == null ? getExecutionException() : cause; if (cause == null) { zuulFallbackProvider.fallbackResponse(); } else { return ((FallbackProvider) zuulFallbackProvider).fallbackResponse(cause); } } return zuulFallbackProvider.fallbackResponse(); } |
通過源碼可知,此時會根據Throwable是否存在來決定走哪種類型的降級方法(原來的還是帶有參數的)。
到此Zuul的實現降級的原理以及Edgware.RC1中的改進就介紹完了。
總結
以上是生活随笔為你收集整理的Spring Cloud Zuul的fallback优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 神经网络激活函数=生物转换器?
- 下一篇: 全链路压测平台(Quake)在美团中的实