1. 程式人生 > >個推基於Docker和Kubernetes的微服務實踐

個推基於Docker和Kubernetes的微服務實踐

640


2016年伊始Docker無比興盛,如今Kubernetes萬人矚目。在這個無比需要創新與速度的時代,由容器、微服務、DevOps構成的雲原生席捲整個IT界。個推針對Web服務場景,基於OpenResty和Node.js搭建了微服務框架,提高了開發效率。在微服務的基礎上,我們結合Docker實現了容器化,並採用Consul進行服務註冊及發現。同時,面對日漸增多的微服務和配置,我們採用了Kubernetes來實現容器編排。

微服務化

640


微服務架構

640

微服務框架
微服務是將單一的應用程式拆分成多個微小的服務,各個小服務之間鬆耦合,高內聚,每個小的服務可以單獨進行開發,不依賴於具體的程式語言,也可以使用不同的資料儲存技術,各個服務可以獨立部署,擁有各自的程序,相互之間通過輕量化的機制進行通訊(如基於http的API介面),所有的服務共同實現具體的業務功能。

640

微服務客戶端與服務端通訊方式
客戶端與服務端通訊有2種方式,第一種是客戶端直接與各個微服務進行通訊,這樣的架構有4個缺點:
  1. 多次服務請求,效率低;

  2. 對外暴露服務介面;

  3. 介面協議無法統一;

  4. 客戶端程式碼複雜,服務端升級困難。


第二種方式是由API閘道器統一代理各個服務,對外提供統一的介面協議,該架構有3個優勢:
  1. 封裝服務介面細節,減少通訊次數;

  2. 統一通訊協議,減少客戶端程式碼耦合;

  3. 統一鑑權,流控,防攻擊。


但在該架構下,閘道器也有可能成為系統瓶頸。
640 服務註冊與發現方式
相應地,這2種架構也帶來了2種服務註冊發現的方式,第一種是客戶端通過向服務的註冊中心查詢微服務的地址與其通訊,第二種是增加統一的API閘道器來查詢。前者會增加客戶端的複雜度,開發成本高,後者操作會更加簡潔,因此我們在實踐的時候選擇了第二種架構方式。
微服務數量增加以後,服務之間的呼叫關係易產生耦合,甚至出現迴圈呼叫的情況,最好的應對方法是對服務進行分層,即將相互依賴的服務通過訊息佇列等技術進行非同步解耦,減少服務間的依賴。

640

服務分層
微服務的具體實踐
技術選型
在實踐中,我們的API Gateway使用的是OpenResty。OpenResty基於Nginx並擴充套件了對Lua的支援,可構建高併發的Web服務。我們通過HTTP介面實現客戶端通訊,資料基本封裝成JSON格式,服務間的通訊介面也是基於HTTP,並利用訊息佇列進行非同步解耦;至於服務註冊發現,我們使用的是Consul;我們選擇了Lua(擴充套件API Gateway的功能),Node.js(用於開發後端服務),Java(用於密集計算和與大資料通訊的場景)作為主要的開發語言。
具體實現過程
下圖為個推統一的服務框架,每個微服務都是運行於這個框架之下,WebLua整合在OpenResty上,對流量進行代理,WebNode和Javams分別是Node和Java服務的微服務架構。
640
統一的服務框架
首先是WebLua:

640

WebLua微服務框架
在實踐過程中,個推使用Lua開發了Lua APP執行的微服務框架-WebLua,其封裝服務之間的通訊協議和訪問外部資源(如MySQL、Redis等)的方法和依賴,同時提供了應用插槽。我們可以將每一個APP看成一個功能模組,每個APP都需要插到WebLua中才能執行。WebLua可以方便地將模組進行組合,既可以一個APP執行一個微服務,也可以多個APP一起對外提供服務。如此,開發者只需關注業務APP開發,很大程度上提高了開發效率。上圖右側是具體的程式碼目錄結構,每個APP可分為Actions,Page,Data三層,Action層在請求處理前後進行攔截,可做某些特殊處理,如請求前進行許可權校驗等;Page層主要對請求的引數進行解析和校驗;Data層負責具體業務處理,同時提供了Shell指令碼,可實現APP打包和部署安裝。
640 WebNode微服務框架
上圖是我們Node服務的微服務框架-WebNode,最早基於Express和co實現,近期個推完成了基於Koa 2.0升級的框架。我們的業務主要是由Node.js和TypeScript進行開發,我們對業務進行拆分,獨立出一個個功能模組,每個獨立的功能模組單獨開發成一個APP,一個或多個APP一起安裝於WebNode框架之下,作為一個微服務統一對外服務。WebNode框架的實現和WebLua類似,也提供了插槽,方便APP進行安裝和組合。
Javams 是個推為了針對高併發場景下快速構建微服務而研發的框架,在 Spring Boot 的基礎上,包含了RPC框架、Trace、快取、健康檢查等元件,提供一站式服務。
API閘道器

640

在微服務架構中一個重要角色就是API閘道器,下面來做介紹。

640

使用API閘道器前後對比
從上面的對比圖中可以看到,左側是沒有API Gateway的,很多的模組如Auth,Logging等,這些程式碼都需要自己去實現,造成了模組的重複建設,同時侵入了服務,功能擴充套件比較困難;右側的圖是使用了API Gateway之後的架構圖,所有通用模組均在API Gateway實現,維護簡單,一處建設,各處受益。在這種情況下,對API Gateway也提出了更高要求——其功能必須可以很方便地擴充套件。
為了實現這樣的API閘道器,我們基於 OpenResty,借鑑了Kong和Orange的外掛機制,通過外掛來擴充套件API閘道器功能。

640

API閘道器的整體架構
從上面的API Gateway架構圖中可以看到,閘道器安裝諸多外掛,每個外掛會在請求的一個或多個階段發揮作用。外掛配置會在Consul上更新,實時生效,外掛規則可靈活配置。在操作中,我們為外掛開發者提供了更多自由選擇,開發者可以自己定義格式。


容器化

640

在微服務落地實踐時我們選擇了Docker,下面將詳細介紹個推基於Docker的實踐。
首先網路元件選擇的是Calico,服務註冊發現和配置管理選擇的是Consul。Consul-template可實時監測Consul配置和服務的變化。
640 個推映象體系
個推映象體系是以Centos為基礎系統映象,安裝OpenResty,Node.js,JDK,由此得到環境映象;在這個基礎上安裝微服務框架,獲得Gorp映象,再在這個Gorp的基礎上安裝具體應用服務,得到應用服務映象。

640

API閘道器中服務註冊和配置更新過程
在API閘道器中,服務註冊通過Consul-agent來實現,配置更新通過Consul-Template實現。Consul-Template主要更新3類配置,包括:
  • Services:代理的所有微服務的服務地址;

  • Products:簡言之即請求到微服務的對映表,如左上所示,所有請求都有統一個規範,從Host中可以獲取Prod,從URI中可以獲取APP,這2個資訊可將請求動態路由到具體服務;

  • Nging-Conf:產品的Nginx配置。


640

應用服務的服務註冊和配置更新過程
應用服務容器,服務註冊的方式跟API閘道器一致。首先,服務通過容器內部執行的Consul agent將服務註冊到Consul上,其次通過Consul-Template來監測觀察 Consul上配置的變化,並更新配置檔案。
OpenResty或者WebNode配置的更新是直接覆蓋相應的配置檔案,然後重啟對應的服務。
640 Docker叢集
上圖是個推基於Docker的叢集架構,從上面的整體架構圖中可看到,Docker叢集包括3個節點,整個微服務分為3層,最上層API Gateway,中間是業務層,最下層是一些多產品公用的基礎的微服務。


Kubernetes實踐

640

微服務雖然有很多好處,但也帶來了很多問題,其中一個就是運維複雜。以前運維只需要面對一個單體應用即可,現在可能面臨的是幾十甚至上百的微服務。在這種情況下,我們需要藉助Kubernetes來解決問題。Kubernetes是Google開源的一個容器編排工具,可用於協助管理容器。
一開始,我們將容器向Kubernetes叢集遷移時,沒做任何改變,只是採用Pod將所有的服務體系在Kubernetes叢集跑起來。但隨著深入使用Kubernetes,我們對微服務做了一些改變。
首先我們換成用Deployment的方式來部署服務,Deployment會保證服務時刻有一定的副本存活,提高了服務穩定性。
其次,我們使用了Service,它可以代理Pod實現負載的均衡。
Kube-DNS可以將Service名解析成具體的ClusterIP,並且當Service沒有刪除重建時,其ClusterIP不變,如此DNS解析的快取就不存在失效問題。基於Kube-DNS和Service的特性,後續我們改造了服務註冊發現體系。

640

服務部署方式
上圖是我們當前的服務部署方式,Pod用Deployment的方式建立,用Service來進行代理。
在實踐過程中,我們還遇到了另一個問題,即配置管理問題。
  1. 微服務化後配置檔案多而分散;

  2. 不同環境之間有很多不必要的差異,如資料庫名;

  3. 在很多不同環境中,相同的配置項暴露給測試和運維;

  4. 沒有版本控制,回滾比較麻煩;

  5. 基於Consul的Web UI無法對非法的輸入進行校驗。


針對這些問題我們做了以下調整:
  1. 統一不同環境間不必要的差異。

  2. 對配置檔案進行模板化,只暴露差異部分,同時可實現不同配置檔案集中配。

  3. 基於Consul開發配置中心,對產品配置集中管理;對輸入進行合法性校驗;增加版本控制,方便回滾。

640

配置中心流程圖

640

日誌服務框架
關於日誌服務,我們在應用容器中集成了Fluent-Bit,配置了2個輸入源,TCP和tail, 輸出也有2個,一個是Elasticsearch,所有的日誌都會上傳到ES通過Kibana展示查詢,另一個是日誌審計服務,有些需要進行審計的操作日誌會發送到日誌審計服務進行進一步的分析處理。
微服務數量增加以後,請求鏈路可能延長,開發者在追蹤問題和排查效能瓶頸時會很不方便,因此我們引入了Zipkin,其主要用於分散式鏈路追蹤,在API Gateway實現了一個外掛進行Span收集,後端服務則通過開源的中介軟體來實現。
640 個推微服務架構
上圖是我們目前的整體架構圖,最底層是Kubernetes叢集,上面部署了Kube-DNS,Consul用於服務註冊發現和配置管理,再者是我們分層的微服務體系,右側是一些輔助的管理系統。


總結

640

上述是個推基於Docker和Kubernetes的整個微服務實踐過程,我們在實踐微服務過程中做了九件重要的事情,即設計實現了自己的微服務框架、完成微服務的容器化部署、自研API閘道器、基於Consul服務註冊和配置管理、使用Kubernetes對容器進行編排、基於Service和Kube-DNS對服務註冊和發現體系進行改造、搭建了自己的配置中心、優化日誌服務和實現了Zipkin鏈路追蹤。
本文轉載自公眾號: 個推技術學院, 點選檢視原文


Kubernetes線下實戰培訓

640?


Kubernetes應用實戰培訓將於2018年12月21日在北京開課,3天時間帶你係統學習Kubernetes 本次培訓包括:容器特性、映象、網路;Docker特性、架構、元件、概念、Runtime;Docker安全;Docker實踐;Kubernetes架構、核心元件、基本功能;Kubernetes設計理念、架構設計、基本功能、常用物件、設計原則;Kubernetes的實踐、執行時、網路、外掛已經落地經驗;微服務架構、DevOps等,點選下方圖片檢視詳情。

640?