Spring Cloud Zuul網關 Filter、熔斷、重試、高可用的使用方式。

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

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

Zuul的核心

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

zuul-core.png

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

自定義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需要執行的具體操作}
}

自定義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;}}}

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

@Bean
public TokenFilter tokenFilter() {return new TokenFilter();
}

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

測試

我們依次啟動示例項目:spring-cloud-eurekaspring-cloud-producerspring-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();
}

實現類通過實現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();}
}

當服務出現異常時,打印相關異常信息,并返回"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。

Zuul高可用

zuul-case.png

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

示例代碼-github

示例代碼-碼云

參考:

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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/539489.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/539489.shtml
英文地址,請注明出處:http://en.pswp.cn/news/539489.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

oracle 9 插入日期,oracle date日期類型 精析

一、date1.date、sysdate格式說明展示date類型&#xff0c;展示格式既可以為&#xff1a;YYYY/MM/DD&#xff0c;也可以為YYYY/MM/DD HH24:MI:SS&#xff1b;其存儲格式只有一種&#xff1a;YYYY/MM/DD HH24:MI:SS展示格式一&#xff1a;當你只存年月日時&#xff0c;date實際存…

為什么使用NativeJdbcExtractor

原文&#xff1a;http://blog.csdn.net/hehexiaoyou/article/details/21019171---------------------------------------------------------------------------有時候必要會對數據庫clob、 blob數據型進行操作&#xff0c;再加上spring 環境不得不要啟用NativeJdbcExtractor 來…

CentOS 7.1下KVM的安裝與配置

由于沒有物理機可用&#xff0c;在自己的VMware Workation中CentOS 7搭建完成。 首先查看VMware Workation是否支持虛擬化&#xff0c;把紅框內打鉤即可。 虛擬化開啟并安裝CentOS系統&#xff0c;建議CentOS安裝64bit。我的環境用的是CentOS 7。進入系統&#xff0c;首先查看服…

軟件生成問候圖片_這些社交軟件你玩過幾個?

提到聊天軟件&#xff0c;我們的手機肯定安裝有微信QQ&#xff0c;不過微信QQ都是主打熟人社交&#xff0c;而下面幾個軟件都是陌生人社交。這些社交軟件&#xff0c;總有一款你安裝過。注意&#xff0c;非按排名介紹。第一款:陌陌陌陌是一款基于地理位置的開放式移動視頻社交應…

通過Sqoop實現Mysql / Oracle 與HDFS / Hbase互導數據

下文將重點說明通過Sqoop實現Mysql與HDFS互導數據&#xff0c;Mysql與Hbase,Oracle與Hbase的互導最后給出命令。一、Mysql與HDFS互導數據環境&#xff1a; 宿主機器操作系統為Win7&#xff0c;Mysql安裝在宿主機上&#xff0c;宿主機地址為192.168.66.963臺虛擬機操作系統為Ubu…

Android5.0新控件

谷歌在推出Android5.0的同時推出了一些新控件&#xff0c;Android5.0中最常用的新控件有下面5種。 1. CardView&#xff08;卡片視圖&#xff09; CardView顧名思義是卡片視圖&#xff0c;它繼承FrameLayout。它是一個帶圓角的背景和陰影FrameLayout。CardView被包裝為一種布局…

python中要使用導入全部的是什么符號-在python格式字符串中使用標點符號

這是因為您可以使用格式迷你語言來訪問對象的屬性.例如,我經常在自己的自定義類工作中使用它.假設我為每臺需要處理的計算機定義了一個類. class Computer(object): def __init__(self,IP): self.IP IP 而現在我想對整個計算機做一些事情 list_comps [Computer(name,"19…

oracle 讀懂10046視頻,10046、10053、實操記錄

10046是一個Oracle的內部事件(event)&#xff0c;通過設置這個事件可以得到Oracle內部執行系統解析、調用、等待、綁定變量等詳細的trace信息&#xff0c;即幫助我們解析一條/多條SQL、PL/SQL語句的運行狀態&#xff0c;這些狀態包括&#xff1a;Parse/Fetch/Execute三個階段中…

linux重定向文件被修改后,Linux服務器修改.htaccess文件實現301重定向

出于 SEO、PR 值傳遞、網址轉換的目的&#xff0c;在網站初建和網站遷移時我們都需要使用 301 重定向&#xff0c;通常包括域名對域名&#xff0c;目錄對目錄和一個獨立網址對另一個獨立網址的重定向。在虛擬主機上作 301 重定向&#xff0c;最常用的方法有2種&#xff1a;第一…

Druid使用起步—在javaWeb項目中配置監控

原文章&#xff1a;http://my.oschina.net/u/568779/blog/152813 ---------------------------------------------------- druid wiki 當我們在javaWEB項目中使用到druid來作為我們的連接池的時候&#xff0c;一定不會忘了添加監控功能。下面我們就來看一下&#xff0c;在一個…

[譯] 想幫助用戶做決定?你的APP可以這樣設計!

原文地址&#xff1a;Design your app for decision-making原文作者&#xff1a;Jeni譯文出自&#xff1a;掘金翻譯計劃本文永久鏈接&#xff1a;github.com/xitu/gold-m…譯者&#xff1a;PTHFLY校對者&#xff1a;ryouaki想幫助用戶做決定&#xff1f;你的APP可以這樣設計&am…

ip地址管理系統_門禁監控管理系統項目總結

門禁監控管理系統項目總結1、門禁管理設備(IFACE802) 16臺 ,都有獨立的網線到控制的房間。IP地址從 192.168.1.101--192.168.1.116。(地下一層 新家的最后一間是在附近的一個房間接的網線。一層的大門 有1臺控制器和IFACE802 部署了2根網線)2、門禁控制的IP地址 192.168.1.1173…

linux mount命令銜接,Linux mount命令詳解:掛載Linux系統外的文件

Linux mount命令詳解&#xff1a;掛載Linux系統外的文件《Linux掛載》一節講到&#xff0c;所有的硬件設備必須掛載之后才能使用&#xff0c;只不過&#xff0c;有些硬件設備(比如硬盤分區)在每次系統啟動時會自動掛載&#xff0c;而有些(比如 U 盤、光盤)則需要手動進行掛載。…

targetFilterLifecycle的作用

targetFilterLifecycle的作用&#xff0c;有需要的朋友可以參考下。 在web.xml中進行配置&#xff0c;對所有的URL請求進行過濾&#xff0c;就像"擊鼓傳花"一樣&#xff0c;鏈式處理。 配置分為兩種A和B。 A:普通配置 在web.xml中增加如下內容&#xff1a;<fi…

平板電腦可以插u盤嗎_有手機還需要平板電腦嗎 酷比魔方iplay30平板電腦評測

原標題&#xff1a;有手機還需要平板電腦嗎 酷比魔方iplay30平板電腦評測一、前言&#xff1a;前段時間我們一幫60歲左右的退休老頭、老太太到農家樂去玩&#xff0c;玩累了就開始喝茶&#xff0c;一坐下來&#xff0c;人人都把手機掏出來&#xff0c;看著他們看手機的姿勢&…

[8086匯編]利用棧翻轉內存數據

assume cs:codesegcodeseg segmentdw 1h, 2h, 3h, 4h, 5h, 6h, 7h, 8h, 9hdw 9 dup(?)start:; 設置棧段mov ax, csmov ss, ax; 36 9 * 2 * 2mov sp, 36sub bx, bxmov cx, 9 s_push:mov ax, cs:[bx]push axadd bx, 2loop s_pushsub bx, bxmov cx, 9 s_pop:pop cs:[bx]add bx, …

面向多媒體 linux 版本,基于MX Linux 的 AV Linux 新版發布,此AV非彼AV

原標題&#xff1a;基于MX Linux 的 AV Linux 新版發布&#xff0c;此AV非彼AV作者&#xff1a;Linux迷鏈接&#xff1a;https://www.linuxmi.com/av-linux-2020-11-23-mx-linux-19-3.html經過六個多月的開發&#xff0c;面向多媒體的AV Linux發行版已發行了新版本&#xff0c;…

Spring的PropertyPlaceholderConfigurer應用

1. PropertyPlaceholderConfigurer是個bean工廠后置處理器的實現&#xff0c;也就是 BeanFactoryPostProcessor接口的一個實現。PropertyPlaceholderConfigurer可以將上下文&#xff08;配置文 件&#xff09;中的屬性值放在另一個單獨的標準java Properties文件中去。在XML文件…

safari瀏覽器_吹爆蘋果自帶瀏覽器Safari,沒有比它更貼心的瀏覽器了!!

大家一定覺得蘋果的很多自帶軟件很難用對不對&#xff1f;嘻嘻&#xff0c;我覺得這正是蘋果的魅力所在&#xff0c;它的很多產品與我們的正常使用習慣思維之間存在著一堵看不見的墻&#xff0c;只有當你你花點時間去研究、去駕馭它&#xff0c;把那堵墻給它推倒&#xff0c;然…

正則表達式知識詳解(轉自晴天碧日)

一、什么是正則表達式&#xff1f; 1.定義&#xff1a; 正則表達式(regular expression)描述了一種字符串匹配的模式&#xff0c;可以用來檢查一個串是否含有某種子串、將匹配的子串做替換或者從某個串中取出符合某個條件的子串等。構造正則表達式的方法和創建數學表達式的方法…