目錄
1. 什麼是Zuul?
Zuul是從設備、網站到應用程序後端的所有請求的前門。作爲邊緣服務應用程序,Zuul旨在實現動態路由,監控,彈性和安全性。
Zuul使用了各種不同類型的過濾器,這使我們能夠快速靈活地將功能應用於邊緣服務。這些過濾器幫助我們執行以下功能:
- 安全認證-識別每個資源的身份驗證要求,並拒絕不滿足要求的請求。
- 日誌監控-跟蹤某些數據和統計信息,以便爲我們提供準確的生產視圖。
- 路由轉發-根據需要將請求動態路由到不同的後端羣集。
- 壓力測試-逐漸增加到羣集的流量以評估性能。
- 限流-爲每種類型的請求分配容量,並丟棄超出限制的請求。
- 熔斷-直接在邊緣構建一些響應,而不是將其轉發到內部集羣
Zuul 在 Netflix 的應用場景:
2. Zuul深入剖析
Zuul 是基於 Servlet 開發的,通過 Zuul 的核心構架圖可以看出 Zuul 是由很多的過濾器組成的。
2.1 過濾器
Filter是Zuul的核心,用來實現對外服務的控制。Filter的生命週期有4個,分別是“PRE”、“ROUTING”、“POST”、“ERROR”,整個生命週期可以用下圖來表示。
Zuul大部分功能都是通過過濾器來實現的。Zuul中定義了四種標準過濾器類型,這些過濾器類型對應於請求的典型生命週期。
- PRE:這種過濾器在請求被路由之前調用。我們可利用這種過濾器實現身份驗證、在集羣中選擇請求的微服務、記錄調試信息等。
- ROUTING:這種過濾器將請求路由到微服務。這種過濾器用於構建發送給微服務的請求,並使用Apache HttpClient或Netfilx Ribbon請求微服務。
- POST:這種過濾器在路由到微服務以後執行。這種過濾器可用來爲響應添加標準的HTTP Header、收集統計信息和指標、將響應從微服務發送給客戶端等。
- ERROR:在其他階段發生錯誤時執行該過濾器。
除了默認的過濾器類型,Zuul還允許我們創建自定義的過濾器類型。例如,我們可以定製一種STATIC類型的過濾器,直接在Zuul中生成響應,而不將請求轉發到後端的微服務。
2.2 源碼理解
- Zuul 是如何將各個 Filter 的處理結果連接起來的?
答:通過 RequestContext 對象,使用 ThreadLocal。
關鍵源碼:
public class RequestContext extends ConcurrentHashMap<String, Object> {
protected static final ThreadLocal<? extends RequestContext> threadLocal = new ThreadLocal<RequestContext>() {
@Override
protected RequestContext initialValue() {
try {
return contextClass.newInstance();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
};
public static RequestContext getCurrentContext() {
if (testContext != null) return testContext;
RequestContext context = threadLocal.get();
return context;
}
public StringBuilder getFilterExecutionSummary() {
if (get("executedFilters") == null) {
putIfAbsent("executedFilters", new StringBuilder());
}
return (StringBuilder) get("executedFilters");
}
public void unset() {
threadLocal.remove();
}
}
3. Zuul應用場景
紅綠部署、開發者測試分支、埋點測試、壓力測試、調試路由、金絲雀測試、粘性金絲雀、失敗注入測試、降級測試、跨區域高可用、防爬防攻擊、健康檢查和屏蔽壞節點。
以下是我在學習過程中的幾個思考。
3.1 Zuul如何實現路由轉發?
通過實現 Filter 來實現:
過濾器樣例:
public class MyFilter extends ZuulFilter {
@Override
String filterType() {
return "pre"; //定義filter的類型,有pre、route、post、error四種
}
@Override
int filterOrder() {
return 10; //定義filter的順序,數字越小表示順序越高,越先執行
}
@Override
boolean shouldFilter() {
return true; //表示是否需要執行該filter,true表示執行,false表示不執行
}
@Override
Object run() {
return null; //filter需要執行的具體操作
}
}
3.2 Zuul如何實現限流熔斷?
實現一個過濾器,run()方法爲空。
3.3 Zuul如何進行壓力測試
實現一個壓力測試的過濾器,路由指定到某個服務。
4. Zuul2.0概述
Zuul 1.0是基於 Servlet 來實現的,是一種 BIO 網絡通信模式。
這種模式優點是:模型簡單、開發調試運維簡單。
缺點是:線程上下文切換會有開銷,並且存在連接數限制。
基於1.0版本,Zuul 推出了 2.0版本,在網絡通信模型進行了優化(還有其他)。
採用 AIO 的模式,相比於1.0版本,在線程開銷上減小了,也能夠接入更多的連接數。
但是缺點是:編程模型變複雜的同時也提高了開發運複雜度,並且更重要的一點是基於 ThreadLocal 實現的 RequestContext 無法工作了。
對比2個版本,2.0的升級帶來了20%的性能提升,Zuul 1.0可以承受百億級別的流量,2.0則達到千億級。相對而言,2.0並沒有帶來很大的性能提升,並且1.0版本已經可以滿足大多業務需要,此外也可以通過使用 AsyncServlet 對1.0進行優化。因此選擇1.0版本會更合適些。
參考資料
- https://github.com/Netflix/zuul/wiki/How-We-Use-Zuul-At-Netflix
- 楊波極客專欄《微服務架構實戰160講》
- http://www.ityouknow.com/springcloud/2018/01/20/spring-cloud-zuul.html