日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring Cloud Zuul网关 Filter、熔断、重试、高可用的使用方式

發布時間:2025/3/21 javascript 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Cloud Zuul网关 Filter、熔断、重试、高可用的使用方式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

時間過的很快,寫springcloud(十):服務網關zuul初級篇還在半年前,現在已經是2018年了,我們繼續探討Zuul更高級的使用方式。

上篇文章主要介紹了Zuul網關使用模式,以及自動轉發機制,但其實Zuul還有更多的應用場景,比如:鑒權、流量轉發、請求統計等等,這些功能都可以使用Zuul來實現。

Zuul的核心

Filter是Zuul的核心,用來實現對外服務的控制。Filter的生命周期有4個,分別是“PRE”、“ROUTING”、“POST”、“ERROR”,整個生命周期可以用下圖來表示。

Zuul大部分功能都是通過過濾器來實現的,這些過濾器類型對應于請求的典型生命周期。

  • PRE:?這種過濾器在請求被路由之前調用。我們可利用這種過濾器實現身份驗證、在集群中選擇請求的微服務、記錄調試信息等。
  • ROUTING:這種過濾器將請求路由到微服務。這種過濾器用于構建發送給微服務的請求,并使用Apache HttpClient或Netfilx Ribbon請求微服務。
  • POST:這種過濾器在路由到微服務以后執行。這種過濾器可用來為響應添加標準的HTTP Header、收集統計信息和指標、將響應從微服務發送給客戶端等。
  • ERROR:在其他階段發生錯誤時執行該過濾器。?
    除了默認的過濾器類型,Zuul還允許我們創建自定義的過濾器類型。例如,我們可以定制一種STATIC類型的過濾器,直接在Zuul中生成響應,而不將請求轉發到后端的微服務。

Zuul中默認實現的Filter

類型順序過濾器功能
pre-3ServletDetectionFilter標記處理Servlet的類型
pre-2Servlet30WrapperFilter包裝HttpServletRequest請求
pre-1FormBodyWrapperFilter包裝請求體
route1DebugFilter標記調試標志
route5PreDecorationFilter處理請求上下文供后續使用
route10RibbonRoutingFilterserviceId請求轉發
route100SimpleHostRoutingFilterurl請求轉發
route500SendForwardFilterforward請求轉發
post0SendErrorFilter處理有錯誤的請求響應
post1000SendResponseFilter處理正常的請求響應

禁用指定的Filter

可以在application.yml中配置需要禁用的filter,格式:

zuul:FormBodyWrapperFilter:pre:disable: true
  • 1
  • 2
  • 3
  • 4

自定義Filter

實現自定義Filter,需要繼承ZuulFilter的類,并覆蓋其中的4個方法。

public class MyFilter extends ZuulFilter {@OverrideString filterType() {return "pre"; //定義filter的類型,有pre、route、post、error四種}@Overrideint filterOrder() {return 10; //定義filter的順序,數字越小表示順序越高,越先執行}@Overrideboolean shouldFilter() {return true; //表示是否需要執行該filter,true表示執行,false表示不執行}@OverrideObject run() {return null; //filter需要執行的具體操作} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

自定義Filter示例

我們假設有這樣一個場景,因為服務網關應對的是外部的所有請求,為了避免產生安全隱患,我們需要對請求做一定的限制,比如請求中含有Token便讓請求繼續往下走,如果請求不帶Token就直接返回并給出提示。

首先自定義一個Filter,在run()方法中驗證參數是否含有Token。

public class TokenFilter extends ZuulFilter {private final Logger logger = LoggerFactory.getLogger(TokenFilter.class);@Overridepublic String filterType() {return "pre"; // 可以在請求被路由之前調用}@Overridepublic int filterOrder() {return 0; // filter執行順序,通過數字指定 ,優先級為0,數字越大,優先級越低}@Overridepublic boolean shouldFilter() {return true;// 是否執行該過濾器,此處為true,說明需要過濾}@Overridepublic Object run() {RequestContext ctx = RequestContext.getCurrentContext();HttpServletRequest request = ctx.getRequest();logger.info("--->>> TokenFilter {},{}", request.getMethod(), request.getRequestURL().toString());String token = request.getParameter("token");// 獲取請求的參數if (StringUtils.isNotBlank(token)) {ctx.setSendZuulResponse(true); //對請求進行路由ctx.setResponseStatusCode(200);ctx.set("isSuccess", true);return null;} else {ctx.setSendZuulResponse(false); //不對其進行路由ctx.setResponseStatusCode(400);ctx.setResponseBody("token is empty");ctx.set("isSuccess", false);return null;}}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

將TokenFilter加入到請求攔截隊列,在啟動類中添加以下代碼:

@Bean public TokenFilter tokenFilter() {return new TokenFilter(); }
  • 1
  • 2
  • 3
  • 4

這樣就將我們自定義好的Filter加入到了請求攔截中。

測試

我們依次啟動示例項目:spring-cloud-eureka、spring-cloud-producer、spring-cloud-zuul,這個三個項目均為上一篇示例項目,spring-cloud-zuul稍微進行改造。

訪問地址:http://localhost:8888/spring-cloud-producer/hello?name=neo,返回:token is empty ,請求被攔截返回。?
訪問地址:http://localhost:8888/spring-cloud-producer/hello?name=neo&token=xx,返回:hello neo,this is first messge,說明請求正常響應。

通過上面這例子我們可以看出,我們可以使用“PRE”類型的Filter做很多的驗證工作,在實際使用中我們可以結合shiro、oauth2.0等技術去做鑒權、驗證。

路由熔斷

當我們的后端服務出現異常的時候,我們不希望將異常拋出給最外層,期望服務可以自動進行一降級。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(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

實現類通過實現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。@Overridepublic String getRoute() {return "spring-cloud-producer";}public ClientHttpResponse fallbackResponse() {return new ClientHttpResponse() {@Overridepublic HttpStatus getStatusCode() throws IOException {return HttpStatus.OK;}@Overridepublic int getRawStatusCode() throws IOException {return 200;}@Overridepublic String getStatusText() throws IOException {return "OK";}@Overridepublic void close() {}@Overridepublic InputStream getBody() throws IOException {return new ByteArrayInputStream("The service is unavailable.".getBytes());}@Overridepublic HttpHeaders getHeaders() {HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON);return headers;}};}@Overridepublic ClientHttpResponse fallbackResponse(Throwable cause) {if (cause != null && cause.getCause() != null) {String reason = cause.getCause().getMessage();logger.info("Excption {}",reason);}return fallbackResponse();} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

當服務出現異常時,打印相關異常信息,并返回”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. ...
  • 1
  • 2
  • 3

根據返回結果可以看出: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>
  • 1
  • 2
  • 3
  • 4

開啟Zuul Retry

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

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

這樣我們就開啟了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"; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

重啟 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
  • 1
  • 2
  • 3

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

注意

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

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

Zuul高可用

我們實際使用Zuul的方式如上圖,不同的客戶端使用不同的負載將請求分發到后端的Zuul,Zuul在通過Eureka調用后端服務,最后對外輸出。因此為了保證Zuul的高可用性,前端可以同時啟動多個Zuul實例進行負載,在Zuul的前端使用Nginx或者F5進行負載轉發以達到高可用性。

示例代碼-github

示例代碼-碼云

參考:

Spring Cloud(七)服務網關 Zuul Filter 使用?
Spring Cloud技術分析(4)- spring cloud zuul?
Zuul 路由使用

總結

以上是生活随笔為你收集整理的Spring Cloud Zuul网关 Filter、熔断、重试、高可用的使用方式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。