什么是Zuul?
Zuul is the front door for all requests from devices and web sites to the backend of the Netflix streaming application.As an edge service application, Zuul is built to enable dynamic routing, monitoring, resiliency and security. It also has the ability to route requests to multiple Amazon Auto Scaling Groups as appropriate. Zuul相當於是設備和網站到Netflix流應用程序后端的所有請求的前門 Zuul旨在實現動態路由,監控,彈性和安全性等 在微服務架構中常基於Zuul實現服務網關(API Gateway)服務器
在項目實踐中,使用jemeter多線程並發訪問微服務中的接口時候,在Zuul層出現異常、超時等,從而導致整個請求失敗。經過實踐,通過調整Zuul的參數、設計高可用架構等可提升TPS、QPS。
Zuul參數剖析
routes
zuul下的routes節點可配置路由轉發規則
zuul: routes: echo: path:/myusers/** serviceId:myusers-service stripPrefix:true myusers-service: ribbon:#負載 NIWSServerListClassName:com.netflix.loadbalancer.ConfigurationBasedServerList listOfServers:http://127.0.0.1:8083,http://127.0.0.1:8084 ConnectTimeout:1000 ReadTimeout:3000 MaxTotalHttpConnections:500 MaxConnectionsPerHost:100
eureka:
client:
enable: false
如上面的配置,HTTP請求中滿足 /myusers/** 規則轉發到myuser-service服務。結合ribbon,可支持myusers-service多實例的動態負載。實際項目中可集成eureka或者consul等自動獲取listOfServers(多實例服務hosts列表)。該配置項指定了服務生產端的真實地址(脫離Eureka使用配置listOfServers進行客戶端負載均衡調度
必須配置eureka.client.enabled=false,不然使用的還是Eureka),例如:http://
myusers/users/list
,在調用時會被替換為http://127.0.0.1:8083/users/list
或http://127.0.0.1:8084/users/list
semaphore
在spring cloud Zuul中有2種對路由的隔離機制,其默認的是信號量(semaphore)對路由做隔離,默認值是100,當一個路由請求的信號量高於100就返回500。
zuul: semaphore: max-semaphores: 5000 #設置全部路由最大信號量 routes: orchestration: service-id: orchestration resource-manager: service-id: resource-manager semaphore: max-semaphores: 5000 #針對單個服務的路由設置最大信號量
設置信號量,可在Zuul節點下對所有路由統一設置信號量(semaphore)大小,在實際項目中推薦為每個服務設置不同的信號量(semaphore)。
ribbon
SpringCloud中ribbon提供負載均衡能力,實際項目中后端不同服務都是多實例,因此從Zuul路由到某個服務也需要支持負載均衡。
ribbon: OkToRetryOnAllOperations:true #全部請求開啟重試機制 ReadTimeout: 6000 #請求處理超時時間 ConnectTimeout: 6000 #請求連接超時時間 MaxTotalHttpConnections: 1000 #最大http連接數 MaxConnectionsPerHost: 100 #每個host最大連接數 MaxAutoRetries: 10 #最大重試次數 MaxAutoRetriesNextServer: 10 #切換實例的重試次數
在高並發或者后端服務由於網絡等原因,導致請求某一瞬間發生故障,也許后端服務只是暫時不可達或者響應比較慢。通過調整響應時間以及重試次數提高請求成功率。
hystrix
hystrix(熔斷),當通過服務網關(基於Zuul實現)調用后端服務時候,難免會出現網絡、響應超時等情況。通過hystrix可斷掉與后端服務的連接,防止拖垮網關服務器。也可以通過hystrix實現服務降級,當發生異常時候,通過fallback處理熔斷(比如:返回一些用戶能看懂的錯誤提示等)。
關於hystrix的參數很多,這里列舉一些常用的參數 更多參數,閱讀:https://github.com/Netflix/Hys ... ation hystrix: threadpool: default: coreSize: 1000 #線程池數量 command: default: execution: isolation: thread: timeoutInMilliseconds: 60000 #發生熔斷的超時時間 strategy: SEMAPHORE #隔離策略 semaphore: max-semaphores: 2000 #信號量大小
高並發下常見Zuul異常
在高並發下,針對不同的系統架構、業務場景。需要自己調整Zuul各組件參數來滿足性能需求。我們在使用jemeter進行並發測試,發現Zuul(服務網關)層出現了一些異常信息,解決了這些異常信息,QPS,TPS都提高了不少。
無法獲取信號量(semaphore異常)
異常信息-1:
spring cloud zuul : could not acquire a semaphore for execution and no fallback available. 無法獲取信號量,系統默認每個路由的信號量為100,當后端一個實例且並發大於100就會經常出現 這個異常信息
調優配置-1:
zuul: semaphore: max-semaphores: 5000 可根據系統需要支持的並發數適當增加信號量的大小
超時
異常信息-2:
connect time out...
當並發訪問時,有些服務所在主機響應可能會比較慢,或者某些業務本身比較耗時
(比如上傳一個大文件的接口)。如果在Zuul層設置的超時時間小於足業務的耗時,
會導致正常的業務請求失敗。
調優配置-2:
ribbon: ReadTimeout: 6000 #請求處理超時時間 ConnectTimeout: 6000 #請求連接時間 根據業務可適當調大超時時間
熔斷
異常信息-3:
short-circuited and no fallback available 並發訪問時,后端某些服務發生熔斷
調優配置-3:
hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 60000 #發生熔斷的超時時間,調整熔斷超時時間,熔斷時間太短,些耗時的業務部不能work熔斷時太長,Zuul服務器可能會被拖垮。所以根據具體業務找到一個合適值。 ribbon: OkToRetryOnAllOperations:true #全部請求開啟重試機制 ReadTimeout: 6000 #請求處理超時時間 ConnectTimeout: 6000 #請求連接超時時間 MaxAutoRetries: 10 #最大重試次數 調整重試次數,實際項目中由於網絡或者資源不夠,偶爾會出現后端服務不能訪問,一次訪問失敗不能 代表后端服務就掛了。 因此開啟重試機制,調整重試次數。在一定時間內,重試幾次都失敗,我們才認為后端服務掛了。
Zuul高可用
我們知道無論在Linux或者windows下,一個進程支持的並發數是有限制的,在實際項目中,服務網關作為微服務架構的入口至關重要。Zuul結合服務發現、負載均衡等啟動多個實例做到高可用。如下圖:
如上圖,啟動多個Zuul實例,在Zuul前加一層負載(常用nginx做負載),每個實例承擔一些請求,整體支持高並發能力也會提高很多。
Zuul版本 - 1.x vs 2.x
截止目前Zuul發布了2個版本,在架構和實現方式以及支持並發的情況都有所不同。
Zuul-1.x
Filter是Zuul的核心,用來實現對外服務的控制。Filter的生命周期有4個,分別是“PRE”、“ROUTING”、“POST”、“ERROR“
1、PRE:過濾器在請求經過路由前被調用。利用這種過濾器可實現身份驗證。
2、ROUTING:過濾器將請求路由到微服務。這種過濾器用於構建發送給后端微服務的請求,使用
Apache HttpClient或Netfilx Ribbon請求微服務。
3、POST:過濾器在路由到微服務以后執行。這種過濾器可為響應添加標准的HTTP Header、收集統計信息和指標、將響應發送給客戶端。
4、ERROR:在其他階段發生錯誤時執行該過濾器
Zuul-2.x
2.x的Zuul基於netty處理請求,netty(高性能、異步事件驅動的NIO框架,提供了對TCP、UDP和文件傳輸的支持,Netty的所有IO操作都是異步非阻塞的)。相對於1.x版本,很明顯把同步改成了異步,把阻塞改成了非阻塞。據官方進行的並發測試,2.x相比1.x性能還是提升了不少。不過2.x相對1.x要復雜一些,如果需要支持很高的QPS、TPS,可以嘗試下2.x。
總結:
1、1.x 同步阻塞,編程模型簡單,社區成熟,通過調整參數能滿足生產性能需求
2、2.x 異步非阻塞,相對編程模型復雜,剛出來也許還有些坑(bug),追求更好性能可以嘗試
PS:當高並發情況下,服務網關服務器(Zuul)可通過以下方法提高支持並發的能力。
1、調整Zuul組件參數
2、支持Zuul高可用,多實例
3、選擇異步、非阻塞版本