實施微服務,咱們須要哪些基礎框架

服務註冊、發現、負載均衡和健康檢查

和單塊(Monolithic)架構不一樣,微服務架構是由一系列職責單一的細粒度服務構成的分佈式網狀結構,服務之間經過輕量機制進行通訊,這時候必然引入一個服務註冊發現問題,也就是說服務提供方要註冊通告服務地址,服務的調用方要能發現目標服務,同時服務提供方通常以集羣方式提供服務,也就引入了負載均衡和健康檢查問題。根據負載均衡LB所在位置的不一樣,目前主要的服務註冊、發現和負載均衡方案有三種:前端

第一種是集中式LB方案,以下圖Fig 1,在服務消費者和服務提供者之間有一個獨立的LB,LB一般是專門的硬件設備如F5,或者基於軟件如LVS,HAproxy等實現。LB上有全部服務的地址映射表,一般由運維配置註冊,當服務消費方調用某個目標服務時,它向LB發起請求,由LB以某種策略(好比Round-Robin)作負載均衡後將請求轉發到目標服務。LB通常具有健康檢查能力,能自動摘除不健康的服務實例。服務消費方如何發現LB呢?一般的作法是經過DNS,運維人員爲服務配置一個DNS域名,這個域名指向LB。數據庫

Fig 1, 集中式LB方案後端

集中式LB方案實現簡單,在LB上也容易作集中式的訪問控制,這一方案目前仍是業界主流。集中式LB的主要問題是單點問題,全部服務調用流量都通過LB,當服務數量和調用量大的時候,LB容易成爲瓶頸,且一旦LB發生故障對整個系統的影響是災難性的。另外,LB在服務消費方和服務提供方之間增長了一跳(hop),有必定性能開銷。設計模式

第二種是進程內LB方案,針對集中式LB的不足,進程內LB方案將LB的功能以庫的形式集成到服務消費方進程裏頭,該方案也被稱爲軟負載(Soft Load Balancing)或者客戶端負載方案,下圖Fig 2展現了這種方案的工做原理。這一方案須要一個服務註冊表(Service Registry)配合支持服務自注冊和自發現,服務提供方啓動時,首先將服務地址註冊到服務註冊表(同時按期報心跳到服務註冊表以代表服務的存活狀態,至關於健康檢查),服務消費方要訪問某個服務時,它經過內置的LB組件向服務註冊表查詢(同時緩存並按期刷新)目標服務地址列表,而後以某種負載均衡策略選擇一個目標服務地址,最後向目標服務發起請求。這一方案對服務註冊表的可用性(Availability)要求很高,通常採用能知足高可用分佈式一致的組件(例如Zookeeper, Consul, Etcd等)來實現。瀏覽器

Fig 2, 進程內LB方案緩存

進程內LB方案是一種分佈式方案,LB和服務發現能力被分散到每個服務消費者的進程內部,同時服務消費方和服務提供方之間是直接調用,沒有額外開銷,性能比較好。可是,該方案以客戶庫(Client Library)的方式集成到服務調用方進程裏頭,若是企業內有多種不一樣的語言棧,就要配合開發多種不一樣的客戶端,有必定的研發和維護成本。另外,一旦客戶端跟隨服務調用方發佈到生產環境中,後續若是要對客戶庫進行升級,勢必要求服務調用方修改代碼並從新發布,因此該方案的升級推廣有不小的阻力。安全

進程內LB的案例是Netflix的開源服務框架,對應的組件分別是:Eureka服務註冊表,Karyon服務端框架支持服務自注冊和健康檢查,Ribbon客戶端框架支持服務自發現和軟路由。另外,阿里開源的服務框架Dubbo也是採用相似機制。性能優化

第三種是主機獨立LB進程方案,該方案是針對第二種方案的不足而提出的一種折中方案,原理和第二種方案基本相似,不一樣之處是,他將LB和服務發現功能從進程內移出來,變成主機上的一個獨立進程,主機上的一個或者多個服務要訪問目標服務時,他們都經過同一主機上的獨立LB進程作服務發現和負載均衡,見下圖Fig 3。服務器

Fig 3 主機獨立LB進程方案網絡

該方案也是一種分佈式方案,沒有單點問題,一個LB進程掛了隻影響該主機上的服務調用方,服務調用方和LB之間是進程內調用,性能好,同時,該方案還簡化了服務調用方,不須要爲不一樣語言開發客戶庫,LB的升級不須要服務調用方改代碼。該方案的不足是部署較複雜,環節多,出錯調試排查問題不方便。

該方案的典型案例是Airbnb的SmartStack服務發現框架,對應組件分別是:Zookeeper做爲服務註冊表,Nerve獨立進程負責服務註冊和健康檢查,Synapse/HAproxy獨立進程負責服務發現和負載均衡。Google最新推出的基於容器的PaaS平臺Kubernetes,其內部服務發現採用相似的機制。

服務前端路由

微服務除了內部相互之間調用和通訊以外,最終要以某種方式暴露出去,才能讓外界系統(例如客戶的瀏覽器、移動設備等等)訪問到,這就涉及服務的前端路由,對應的組件是服務網關(Service Gateway),見圖Fig 4,網關是鏈接企業內部和外部系統的一道門,有以下關鍵做用:

  1. 服務反向路由,網關要負責將外部請求反向路由到內部具體的微服務,這樣雖然企業內部是複雜的分佈式微服務結構,可是外部系統從網關上看到的就像是一個統一的完整服務,網關屏蔽了後臺服務的複雜性,同時也屏蔽了後臺服務的升級和變化。

  2. 安全認證和防爬蟲,全部外部請求必須通過網關,網關能夠集中對訪問進行安全控制,好比用戶認證和受權,同時還能夠分析訪問模式實現防爬蟲功能,網關是鏈接企業內外系統的安全之門。

  3. 限流和容錯,在流量高峯期,網關能夠限制流量,保護後臺系統不被大流量沖垮,在內部系統出現故障時,網關能夠集中作容錯,保持外部良好的用戶體驗。

  4. 監控,網關能夠集中監控訪問量,調用延遲,錯誤計數和訪問模式,爲後端的性能優化或者擴容提供數據支持。

  5. 日誌,網關能夠收集全部的訪問日誌,進入後臺系統作進一步分析。

Fig 4, 服務網關

除以上基本能力外,網關還能夠實現線上引流,線上壓測,線上調試(Surgical debugging),金絲雀測試(Canary Testing),數據中心雙活(Active-Active HA)等高級功能。

網關一般工做在7層,有必定的計算邏輯,通常以集羣方式部署,前置LB進行負載均衡。

開源的網關組件有Netflix的Zuul,特色是動態可熱部署的過濾器(filter)機制,其它如HAproxy,Nginx等均可以擴展做爲網關使用。

在介紹過服務註冊表和網關等組件以後,咱們能夠經過一個簡化的微服務架構圖(Fig 5)來更加直觀地展現整個微服務體系內的服務註冊發現和路由機制,該圖假定採用進程內LB服務發現和負載均衡機制。在下圖Fig 5的微服務架構中,服務簡化爲兩層,後端通用服務(也稱中間層服務Middle Tier Service)和前端服務(也稱邊緣服務Edge Service,前端服務的做用是對後端服務作必要的聚合和裁剪後暴露給外部不一樣的設備,如PC,Pad或者Phone)。後端服務啓動時會將地址信息註冊到服務註冊表,前端服務經過查詢服務註冊表就能夠發現而後調用後端服務;前端服務啓動時也會將地址信息註冊到服務註冊表,這樣網關經過查詢服務註冊表就能夠將請求路由到目標前端服務,這樣整個微服務體系的服務自注冊自發現和軟路由就經過服務註冊表和網關串聯起來了。若是以面向對象設計模式的視角來看,網關相似Proxy代理或者Façade門面模式,而服務註冊表和服務自注冊自發現相似IoC依賴注入模式,微服務能夠理解爲基於網關代理和註冊表IoC構建的分佈式系統。

Fig 5, 簡化的微服務架構圖

服務容錯

當企業微服務化之後,服務之間會有錯綜複雜的依賴關係,例如,一個前端請求通常會依賴於多個後端服務,技術上稱爲1 -> N扇出(見圖Fig 6)。在實際生產環境中,服務每每不是百分百可靠,服務可能會出錯或者產生延遲,若是一個應用不能對其依賴的故障進行容錯和隔離,那麼該應用自己就處在被拖垮的風險中。在一個高流量的網站中,某個單一後端一旦發生延遲,可能在數秒內致使全部應用資源(線程,隊列等)被耗盡,形成所謂的雪崩效應(Cascading Failure,見圖Fig 7),嚴重時可致整個網站癱瘓。

Fig 6, 服務依賴

Fig 7, 高峯期單個服務延遲致雪崩效應

通過多年的探索和實踐,業界在分佈式服務容錯一塊探索出了一套有效的容錯模式和最佳實踐,主要包括:

Fig 8, 彈性電路保護狀態圖

  1. 電路熔斷器模式(Circuit Breaker Patten), 該模式的原理相似於家裏的電路熔斷器,若是家裏的電路發生短路,熔斷器可以主動熔斷電路,以免災難性損失。在分佈式系統中應用電路熔斷器模式後,當目標服務慢或者大量超時,調用方可以主動熔斷,以防止服務被進一步拖垮;若是狀況又好轉了,電路又能自動恢復,這就是所謂的彈性容錯,系統有自恢復能力。下圖Fig 8是一個典型的具有彈性恢復能力的電路保護器狀態圖,正常狀態下,電路處於關閉狀態(Closed),若是調用持續出錯或者超時,電路被打開進入熔斷狀態(Open),後續一段時間內的全部調用都會被拒絕(Fail Fast),一段時間之後,保護器會嘗試進入半熔斷狀態(Half-Open),容許少許請求進來嘗試,若是調用仍然失敗,則回到熔斷狀態,若是調用成功,則回到電路閉合狀態。

  2. 艙壁隔離模式(Bulkhead Isolation Pattern),顧名思義,該模式像艙壁同樣對資源或失敗單元進行隔離,若是一個船艙破了進水,只損失一個船艙,其它船艙能夠不受影響 。線程隔離(Thread Isolation)就是艙壁隔離模式的一個例子,假定一個應用程序A調用了Svc1/Svc2/Svc3三個服務,且部署A的容器一共有120個工做線程,採用線程隔離機制,能夠給對Svc1/Svc2/Svc3的調用各分配40個線程,當Svc2慢了,給Svc2分配的40個線程因慢而阻塞並最終耗盡,線程隔離能夠保證給Svc1/Svc3分配的80個線程能夠不受影響,若是沒有這種隔離機制,當Svc2慢的時候,120個工做線程會很快所有被對Svc2的調用吃光,整個應用程序會所有慢下來。

  3. 限流(Rate Limiting/Load Shedder),服務總有容量限制,沒有限流機制的服務很容易在突發流量(秒殺,雙十一)時被沖垮。限流一般指對服務限定併發訪問量,好比單位時間只容許100個併發調用,對超過這個限制的請求要拒絕並回退。

  4. 回退(fallback),在熔斷或者限流發生的時候,應用程序的後續處理邏輯是什麼?回退是系統的彈性恢復能力,常見的處理策略有,直接拋出異常,也稱快速失敗(Fail Fast),也能夠返回空值或缺省值,還能夠返回備份數據,若是主服務熔斷了,能夠從備份服務獲取數據。

Netflix將上述容錯模式和最佳實踐集成到一個稱爲Hystrix的開源組件中,凡是須要容錯的依賴點(服務,緩存,數據庫訪問等),開發人員只須要將調用封裝在Hystrix Command裏頭,則相關調用就自動置於Hystrix的彈性容錯保護之下。Hystrix組件已經在Netflix通過多年運維驗證,是Netflix微服務平臺穩定性和彈性的基石,正逐漸被社區接受爲標準容錯組件。

服務框架

微服務化之後,爲了讓業務開發人員專一於業務邏輯實現,避免冗餘和重複勞動,規範研發提高效率,必然要將一些公共關注點推到框架層面。服務框架(Fig 9)主要封裝公共關注點邏輯,包括:

Fig 9, 服務框架

  1. 服務註冊、發現、負載均衡和健康檢查,假定採用進程內LB方案,那麼服務自注冊通常統一作在服務器端框架中,健康檢查邏輯由具體業務服務定製,框架層提供調用健康檢查邏輯的機制,服務發現和負載均衡則集成在服務客戶端框架中。

  2. 監控日誌,框架一方面要記錄重要的框架層日誌、metrics和調用鏈數據,還要將日誌、metrics等接口暴露出來,讓業務層能根據須要記錄業務日誌數據。在運行環境中,全部日誌數據通常集中落地到企業後臺日誌系統,作進一步分析和處理。

  3. REST/RPC和序列化,框架層要支持將業務邏輯以HTTP/REST或者RPC方式暴露出來,HTTP/REST是當前主流API暴露方式,在性能要求高的場合則可採用Binary/RPC方式。針對當前多樣化的設備類型(瀏覽器、普通PC、無線設備等),框架層要支持可定製的序列化機制,例如,對瀏覽器,框架支持輸出Ajax友好的JSON消息格式,而對無線設備上的Native App,框架支持輸出性能高的Binary消息格式。

  4. 配置,除了支持普通配置文件方式的配置,框架層還可集成動態運行時配置,可以在運行時針對不一樣環境動態調整服務的參數和配置。

  5. 限流和容錯,框架集成限流容錯組件,可以在運行時自動限流和容錯,保護服務,若是進一步和動態配置相結合,還能夠實現動態限流和熔斷。

  6. 管理接口,框架集成管理接口,一方面能夠在線查看框架和服務內部狀態,同時還能夠動態調整內部狀態,對調試、監控和管理能提供快速反饋。Spring Boot微框架的Actuator模塊就是一個強大的管理接口。

  7. 統一錯誤處理,對於框架層和服務的內部異常,若是框架層可以統一處理並記錄日誌,對服務監控和快速問題定位有很大幫助。

  8. 安全,安全和訪問控制邏輯能夠在框架層統一進行封裝,可作成插件形式,具體業務服務根據須要加載相關安全插件。

  9. 文檔自動生成,文檔的書寫和同步一直是一個痛點,框架層若是能支持文檔的自動生成和同步,會給使用API的開發和測試人員帶來極大便利。Swagger是一種流行Restful API的文檔方案。

當前業界比較成熟的微服務框架有Netflix的Karyon/Ribbon,Spring的Spring Boot/Cloud,阿里的Dubbo等。

運行期配置管理

服務通常有不少依賴配置,例如訪問數據庫有鏈接字符串配置,鏈接池大小和鏈接超時配置,這些配置在不一樣環境(開發/測試/生產)通常不一樣,好比生產環境須要配鏈接池,而開發測試環境可能不配,另外有些參數配置在運行期可能還要動態調整,例如,運行時根據流量情況動態調整限流和熔斷閥值。目前比較常見的作法是搭建一個運行時配置中心支持微服務的動態配置,簡化架構以下圖(Fig 10):

Fig 10, 服務配置中心

動態配置存放在集中的配置服務器上,用戶經過管理界面配置和調整服務配置,具體服務經過按期拉(Scheduled Pull)的方式或者服務器推(Server-side Push)的方式更新動態配置,拉方式比較可靠,但會有延遲同時有無效網絡開銷(假設配置不常更新),服務器推方式能及時更新配置,可是實現較複雜,通常在服務和配置服務器之間要創建長鏈接。配置中心還要解決配置的版本控制和審計問題,對於大規模服務化環境,配置中心還要考慮分佈式和高可用問題。

配置中心比較成熟的開源方案有百度的Disconf,360的QConf,Spring的Cloud Config和阿里的Diamond等。

Netflix的微服務框架

Netflix是一家成功實踐微服務架構的互聯網公司,幾年前,Netflix就把它的幾乎整個微服務框架棧開源貢獻給了社區,這些框架和組件包括:

  1. Eureka: 服務註冊發現框架

  2. Zuul: 服務網關

  3. Karyon: 服務端框架

  4. Ribbon: 客戶端框架

  5. Hystrix: 服務容錯組件

  6. Archaius: 服務配置組件

  7. Servo: Metrics組件

  8. Blitz4j: 日誌組件

下圖Fig 11展現了基於這些組件構建的一個微服務框架體系,來自recipes-rss。

Fig 11, 基於Netflix開源組件的微服務框架

Netflix的開源框架組件已經在Netflix的大規模分佈式微服務環境中通過多年的生產實戰驗證,正逐步被社區接受爲構造微服務框架的標準組件。Pivotal去年推出的Spring Cloud開源產品,主要是基於對Netflix開源組件的進一步封裝,方便Spring開發人員構建微服務基礎框架。對於一些打算構建微服務框架體系的公司來講,充分利用或參考借鑑Netflix的開源微服務組件(或Spring Cloud),在此基礎上進行必要的企業定製,無疑是通向微服務架構的捷徑。

相關文章
相關標籤/搜索