做者:個推應用平臺基礎架構高級研發工程師 阿飛後端
在微服務架構中,不一樣的微服務能夠有不一樣的網絡地址,各個微服務之間經過互相調用完成用戶請求,客戶端可能經過調用N個微服務的接口完成一個用戶請求。所以,在客戶端和服務端之間增長一個API網關成爲多數微服務架構的必然選擇。api
在個推的微服務實踐中,API網關也起着相當重要的做用。一方面,API網關是個推微服務體系對外的惟一入口;另外一方面,API網關中實現了不少後端服務的共性需求,避免了重複建設。安全
個推微服務主要是基於Docker和Kubernetes進行實踐的。在整個微服務架構中,最底層的是個推私有部署的Kubernetes集羣,在集羣之上,部署了應用服務。網絡
個推的應用服務體系共分爲三層,最上一層是網關層,接着是業務層,最下面是基礎層服務。在部署應用服務時,咱們使用了Kubernetes的命名空間對不一樣產品線的產品進行隔離。除了應用服務外, Kubernetes集羣上還部署了Consul來實現配置的管理、Kube-DNS實現服務註冊與發現,以及一些輔助系統來進行應用和集羣的管理。session
下圖是個推微服務體系的架構圖。
架構
個推對API網關的功能需求主要有如下幾方面:負載均衡
要支持配置多個產品,爲不一樣的產品提供不一樣的端口;分佈式
動態路由;ide
URI的重寫;微服務
服務的註冊與發現;
負載均衡;
安全相關的需求,如session校驗等;
流量控制;
鏈路追蹤;
在對市面上已有的網關產品進行調研後,咱們的技術團隊發現,它們並不太適合應用於個推的微服務體系。第一,個推配置的管理都是基於Consul實現的,而大部分網關產品都須要基於一些DB存儲,來進行配置的管理;第二,大部分的網關產品提供的功能比較通用,也比較完善,這同時也下降了配置的複雜度以及靈活性;第三,大部分的網關產品很難直接融入到個推的微服務架構體系中。
最終,個推選擇使用了OperResty和Lua進行自研網關,在自研的過程當中,咱們也借鑑了其餘網關產品的一些設計,如Kong和Orange的插件機制等。
個推的API網關的插件設計以下圖所示。
OpenResty對請求的處理分爲多個階段。個推API網關的插件主要是在Set、Rewrite、Access、Header_filter、Body_filter、Log這六個階段作相應的處理,其中,每個插件均可以在一個或多個階段起到相應的做用。在一個請求到達API網關以後,網關會根據配置爲該請求選擇插件,而後根據每一個插件的規則,進一步過濾出匹配規則的插件,最後對插件進行實例化,對流量進行相應的處理。
咱們能夠經過舉例來理解這個過程,如上圖所示,localhost:8080/api/demo/test/hello這個請求到達網關後,網關會根據host和端口肯定產品信息,並提取出URI(/api/demo/test/hello),而後根據產品的具體配置,篩選出須要使用的插件——Rewrite_URI、Dyups和Auth,接下來根據每一個插件的規則配置進行過濾,過濾後,只有Rewrite_URI和Dyups兩個插件被選中。以後實例化這兩個插件,在各個階段對請求進行處理。請求被轉發到後端服務時,URI就被rewrite爲「/demo/test/hello」,upstream也被設置爲「prod1-svc1」。請求由後端服務處理以後,響應會經網關返回給客戶端,這就是整個插件的設計和工做的流程。爲了優化性能,咱們將插件的實例化延緩到了請求真正開始處理時,在此以前,網關會經過產品配置和規則,過濾掉不須要執行的插件。從圖中也能夠看出,每一個插件的規則配置都很簡單,而且沒有統一的格式,這也確保了插件配置的簡單靈活。
網關的配置均爲熱更新,經過Consul和Consul-Template來實現,配置在Consul上進行更新後,Consul-Template會將其實時地拉取下來,而後經過如下兩種方式進行更新。
(1)經過調用Update API,將配置更新到shared-dict中。
(2)更新配置文件,利用Reload OpenResty實現配置文件的更新。
動態路由主要涉及到三個方面:服務註冊、服務發現和請求轉發。
以下圖所示,服務的註冊和發現是基於Kubernetes的Service和Kube-DNS實現的,在Consul中,會維持一個服務的映射表,應用的每個微服務都對應Kubernetes上的一個Service,每建立一個Service都會在Consul上的服務映射表中添加一項(會被實時更新到網關的共享內存中)。網關每收到一個請求都會從服務映射表中查詢到具體的後端服務(即Kubernetes中的Service名),並進行動態路由。Kube-DNS能夠將Service的域名解析成Kubernetes內部的ClusterIP,而Service代理了多個Pod,會將流量均衡地轉發到不一樣的Pod上。
流量控制主要是經過一個名爲「Counter」的後端服務和網關中的流控插件實現的。Counter負責存儲請求的訪問次數和限值,而且支持按時間維度進行計數。流控插件負責攔截流量,調用Counter的接口進行超限查詢,若是Counter返回請求超限,網關就會直接拒絕訪問,實現限次的功能,再結合時間維度就能夠實現限頻的需求。同時流控插件經過輸出日誌信息到fluent-bit,由fluent-bit聚合計次來更新Counter中的計數。
整個微服務體系的鏈路追蹤是基於分佈式的鏈路追蹤系統Zipkin來實現的。經過在網關安裝Zipkin插件和在後端服務中引入Zipkin中間件,實現最終的鏈路追蹤功能。具體架構以下圖所示。
在A/B測試的實現中,有如下幾個關鍵點:
(1)全部的策略信息都配置在Consul上,並經過Consul-Template實時生效到各個微服務的內存中;
(2)每條策略均有指明,調用一個微服務時應調用A仍是B(默認爲A);
(3)網關中實現A/B插件,在請求到達網關時,經過A/B插件配置的規則,便可肯定請求適用的A/B策略;
(4)網關會將請求適用的A/B策略經過URL參數傳遞下去;
(5)每一個微服務經過傳遞下來的策略,選擇正確的服務進行訪問。
下圖給出了兩種場景下的調用鏈路。
以上就是個推微服務網關的設計和主要功能的實現。以後,個推的技術團隊會不斷提高API網關的彈性設計,使其可以在故障出現時,縮小故障的影響範圍;同時,咱們也會繼續將網關與DevOps平臺作進一步地結合,以確保網關在迭代更新時,可以有更多的自動化測試來保證質量,實現更快速地部署。