1. 程式人生 > >九、springcloud之服務網關zuul(二)

九、springcloud之服務網關zuul(二)

framework sta end 作用 3.4 配置文件 ssg 異常信息 set

一、路由熔斷

當我們的後端服務出現異常的時候,我們不希望將異常拋出給最外層,期望服務可以自動進行一降級。Zuul給我們提供了這樣的支持。當某個服務出現異常時,直接返回我們預設的信息。

我們通過自定義的fallback方法,並且將其指定給某個route來實現該route訪問出問題的熔斷處理。主要繼承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(); }

實現類通過實現getRoute方法,告訴Zuul它是負責哪個route定義的熔斷。而fallbackResponse方法則是告訴 Zuul 斷路出現時,它會提供一個什麽返回值來處理請求。

後來Spring又擴展了此類,豐富了返回方式,在返回的內容中添加了異常信息,因此最新版本建議直接繼承類FallbackProvider

以spring-cloud-producer服務為例,定制它的熔斷返回內容。

@Component
public class ProducerFallback implements FallbackProvider {
    private final Logger logger = LoggerFactory.getLogger(FallbackProvider.class);

    //指定要處理的 service。
    @Override
    
public String getRoute() { return "spring-cloud-producer"; } public ClientHttpResponse fallbackResponse() { return new ClientHttpResponse() { @Override public HttpStatus getStatusCode() throws IOException { return HttpStatus.OK; } @Override public int getRawStatusCode() throws IOException { return 200; } @Override public String getStatusText() throws IOException { return "OK"; } @Override public void close() { } @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream("The service is unavailable.".getBytes()); } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return headers; } }; } @Override public ClientHttpResponse fallbackResponse(Throwable cause) { if (cause != null && cause.getCause() != null) { String reason = cause.getCause().getMessage(); logger.info("Excption {}",reason); } return fallbackResponse(); } }

當服務出現異常時,打印相關異常信息,並返回”The service is unavailable.”。

啟動項目spring-cloud-producer-2,這時候服務中心會有兩個spring-cloud-producer項目,我們重啟Zuul項目。再手動關閉spring-cloud-producer-2項目,多次訪問地址:http://localhost:8888/spring-cloud-producer/hello?name=neo&token=xx,會交替返回:

hello neo,this is first messge
The service is unavailable.
...

根據返回結果可以看出:spring-cloud-producer-2項目已經啟用了熔斷,返回:The service is unavailable.

Zuul 目前只支持服務級別的熔斷,不支持具體到某個URL進行熔斷。

二、路由重試

有時候因為網絡或者其它原因,服務可能會暫時的不可用,這個時候我們希望可以再次對服務進行重試,Zuul也幫我們實現了此功能,需要結合Spring Retry 一起來實現。下面我們以上面的項目為例做演示。

添加Spring Retry依賴

首先在spring-cloud-zuul項目中添加Spring Retry依賴。

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

開啟Zuul Retry

再配置文件中配置啟用Zuul Retry

#是否開啟重試功能
zuul.retryable=true
#對當前服務的重試次數
ribbon.MaxAutoRetries=2
#切換相同Server的次數
ribbon.MaxAutoRetriesNextServer=0

這樣我們就開啟了Zuul的重試功能。

測試

我們對spring-cloud-producer-2進行改造,在hello方法中添加定時,並且在請求的一開始打印參數。

@RequestMapping("/hello")
public String index(@RequestParam String name) {
    logger.info("request two name is "+name);
    try{
        Thread.sleep(1000000);
    }catch ( Exception e){
        logger.error(" hello two error",e);
    }
    return "hello "+name+",this is two messge";
}

重啟 spring-cloud-producer-2和spring-cloud-zuul項目。

訪問地址:http://localhost:8888/spring-cloud-producer/hello?name=neo&token=xx,當頁面返回:The service is unavailable.時查看項目spring-cloud-producer-2後臺日誌如下:

2018-01-22 19:50:32.401  INFO 19488 --- [io-9001-exec-14] o.s.c.n.z.f.route.FallbackProvider       : request two name is neo
2018-01-22 19:50:33.402  INFO 19488 --- [io-9001-exec-15] o.s.c.n.z.f.route.FallbackProvider       : request two name is neo
2018-01-22 19:50:34.404  INFO 19488 --- [io-9001-exec-16] o.s.c.n.z.f.route.FallbackProvider       : request two name is neo

說明進行了三次的請求,也就是進行了兩次的重試。這樣也就驗證了我們的配置信息,完成了Zuul的重試功能。

註意

開啟重試在某些情況下是有問題的,比如當壓力過大,一個實例停止響應時,路由將流量轉到另一個實例,很有可能導致最終所有的實例全被壓垮。說到底,斷路器的其中一個作用就是防止故障或者壓力擴散。用了retry,斷路器就只有在該服務的所有實例都無法運作的情況下才能起作用。這種時候,斷路器的形式更像是提供一種友好的錯誤信息,或者假裝服務正常運行的假象給使用者。

不用retry,僅使用負載均衡和熔斷,就必須考慮到是否能夠接受單個服務實例關閉和eureka刷新服務列表之間帶來的短時間的熔斷。如果可以接受,就無需使用retry。

轉自:http://www.ityouknow.com/springcloud/2018/01/20/spring-cloud-zuul.html

九、springcloud之服務網關zuul(二)