微服務(MicroServices)從發展到成熟,已經經歷了很長一段時間,它是一種架構概念,業界都在使用微服務去改造目前的單體服務,爲用戶提供更敏捷、更快速、更安全的服務,基於微服務概念而產生的框架和工具如雨後春筍般的發展起來了,Spring Cloud、Netflix、Dubbo、Consul、Eureka等服務註冊中心、服務調度框架都是我們非常熟悉的框架和工具。

在一個組織和企業內部,每個團隊依據各自業務的特點及人員的特點,都在使用着不同的服務框架和工具。對於一個組織或企業來說,每個團隊都使用不同的服務框架,就會增加人力學習成本、增加資源投入、增大故障發生機率、延長故障處理時間,不利於整個企業的技術發展,需要有一個統一的、穩定的、可維護的基礎框架來支撐每個業務的發展。

在網易傳媒技術內部,有的團隊使用Spring Cloud,有的團隊使用Dubbo,有的團隊使用Spring MVC,在語言棧上,傳媒技術大部分都使用Java語言棧,有部分團隊使用C++、Python等其他語言棧,如何使每個團隊的服務框架做到統一,而且對現有代碼不會造成大量修改,同時也要兼容不同語言棧。如何能平滑、全覆蓋、快速的進行微服務改造,是我們面對的比較大的挑戰,我將通過兩篇文章爲大家介紹在傳媒技術內部如何進行微服務改造的,本篇文章主要對微服務及目前開源組件做一些介紹,下一篇文章將闡述在傳媒內部如何進行微服務改造工作。 如果你想和更多微服務技術專家交流,可以加我微信liyingjiese,備註『加羣』。羣裏每週都有全球各大公司的最佳實踐以及行業最新動態

一、微服務介紹

在介紹微服務之前,先來了解下單體應用,單體應用就是將應用程序的所有功能都打包成一個獨立可運行的程序,可以是JAR、WAR、EAR或其他格式的包,在單體應用的時代,不涉及到分佈式部署,不涉及到擴容、持續集成等方面的問題,但隨着業務越來越複雜,對快速迭代的需求越來越多,團隊的不斷壯大,業務請求量越來越大,單體應用的缺點逐漸被暴漏出來,主要包括:

  1. 版本管理難、代碼維護難、技術債務越積越多:當項目規模越來越大,代碼越來越多,涉及到的版本也越來越多,版本的管理越來越複雜,代碼很容易產生衝突,隨着時間的推移,人員的更迭,增加了很多的技術債務
  2. 穩定性差:單個模塊出現的問題,會影響到整個應用,導致整個應用都無法提供服務
  3. 不夠靈活:對應用程序的任何細微修改都會涉及到應用的重新構建、重新部署,開發人員需要等到整個應用程序重新部署完成後才能看到變化。如果多個開發人員共同開發一個應用程序,那麼還要等待其他開發人員完成了各自的開發。這降低了團隊的靈活性和功能交付頻率。
  4. 不利於持續集成:單體應用一般比較大,構建和部署的時間都比較長,不利於頻繁打包、頻繁部署
  5. 受限於技術棧:單體應用只能使用統一的技術棧,而且要使用類似的工具,無法依據不同的場景選擇不同的技術棧

正是由於單體應用不能滿足業務快速發展、敏捷性、靈活性和可擴展性的需求,迫切需要一種更加快速高效的軟件交付方式。2014年,Martin Fowler在其博文中發表了“Microervices”一文,首先提到了“微服務”這個詞。簡單來說,微服務首先是一種架構風格,它將單體應用拆分爲更多的小型服務,這些小型服務在獨立的進程中運行,服務之間通過HTTP的RESTFul API進行通信,被拆成的每一個小型服務都具有如下特點:

  1. 單一職責,接口簡單:每個服務只負責整個應用單獨一部分功能,做到低耦合、高內聚
  2. 可以獨立部署、升級、擴展或替換:每個服務都可以獨立部署,不影響整個系統,從而使服務很容易升級、擴展或替換
  3. 可以使用多種語言:每個服務的實現細節與其他服務都沒有關係,團隊可以根據每個服務的的特點選擇最合適的開發語言、數據存儲、工具及方法
  4. 輕量級通信:服務之間的通信使用輕量級的REST進行通信,異步通信可以選擇MQ進行通信

看上去微服務能夠解決軟件開發方面的很多問題,但同時,微服務也帶來了一些其他的問題,主要包括如下幾點

  1. 系統的複雜度增大,運維的複雜度增大:使用微服務架構,系統由多個獨立運行的微服務組成,本身是一個分佈式系統,服務之間的通信,服務的可靠性都需要考慮,這都增大了系統複雜度及運維複雜度。在數據庫方面,不像單應用只需要考慮一個數據庫即可,在微服務下,每個微服務有可能都連着不同的數據庫,就需要考慮分佈式事務。在部署方面,在微服務下,需要考慮服務的依賴和部署順序,這都增加了運維方面的複雜度
  2. 合理的拆分微服務:微服務的主要目的就是有效拆分應用,實現敏捷開發和部署。如何衡量服務的拆分力度是合理的,這對架構師及團隊提出了不小的考驗
  3. 測試的複雜度增大:在單體應用下,測試人員只需要部署一個應用就可以進行測試,但在微服務下,需要考慮整個服務的調用鏈路,服務之間的依賴關係,需要定位到出現錯誤的服務,這些都對測試人員造成了不小的挑戰

二、微服務基礎組件介紹

在實施微服務過程中,需要有一些基礎的組件和服務來支持微服務的實施,以下對一些基礎的服務和組件做一些介紹。

服務註冊中心

在整個微服務架構中,註冊中心是最基礎的核心服務之一,它記錄着服務和服務地址的映射關係,爲服務提供方提供註冊、註銷功能,爲服務消費方提供服務發現的功能。

1). CAP

在討論註冊中心之前,先了解一下CAP原則,它是指在一個分佈式系統中所擁有的三個特性:Consistency(一致性)、Availability(可用性)、Partition Tolerance(分區容錯性)。

  • 一致性:它要求在同一時刻點,分佈式系統中的所有數據備份都處於同一狀態。
  • 可用性:在系統集羣的一部分節點宕機後,系統依然能夠響應用戶的請求。
  • 分區容錯性:在網絡區間通信出現失敗,系統能夠容忍。

這三個分佈式特性中,不可能同時存在,需要依據實際業務需求進行取捨,目前存在的註冊中心實現中,有的實現了AP,有的實現了CP,我們接下來分別進行討論

2). Eureka

Eureka是由Netflix開源的服務註冊中心項目,基於Java語言開發,目前開源了1.X版本,2.X版本已經宣佈閉源。Eureka滿足了AP,採用了Server/Client模式進行設計。Server是註冊中心,爲Client提供服務註冊和發現的功能,維護着註冊到自身的Client相關的信息,提供接口給Client獲取服務註冊相關的信息。Client將自己的服務信息登記到Server上,並維護自己信息的一致性。

  • Eureka Server:提供服務的註冊和發現功能
  • Provider:將自身的服務註冊到Eureka Server中
  • Consumer:從Eureka Server中獲取想要的服務列表

Eureka的整體架構圖如下所示:

  • Eureka Server:服務註冊中心,保存着服務與服務實例之間的關係,提供註冊、下線、查詢等服務
  • Application Client:服務消費者角色,向服務註冊中心獲取服務實例列表,並遠程調用一個服務實例的接口
  • Application Service:服務提供者的角色,向Eureka Server註冊和更新自己的信息,同時能從Eureka Server的註冊表中獲取到其他服務的信息

Eureka保證了AP,沒有保證不同集羣之間的Server數據強一致性,僅通過數據拷貝的方式爭取註冊中心數據的最終一致性,雖然放棄數據強一致性但是換來了Server的可用性,降低了註冊的代價,提高了集羣運行的健壯性

3). Consul

Consul是由HashiCorp基於Go語言開發的支持多數據中心分佈式高可用的服務發佈和註冊服務軟件,保證了CP(採用Raft算法保證服務的一致性),且支持多種健康檢查方式,保證服務提供方的服務是可用

Consul主要支持以下特性:

  • 服務註冊與發現:Consul做爲服務註冊中心,提供服務的註冊、註銷、服務發現的功能,可以通過Rest Api的方式訪問這些接口
  • 健康檢查:Consul提供健康檢查功能,服務提供方將健康檢查地址註冊到Consul,Consul在指定時間進行健康檢查,並標記有問題的服務實例
  • KV存儲:Consul除了提供服務註冊中心外,還提供KV存儲的功能,可以將服務實例的一些特殊屬性值通過KV的形式存儲到Consul中
  • 多數據中心:Consul提供多數據中心的支持,數據中心之間通過“Gossip“協議

4). ZooKeeper

ZooKeeper是由Google最早開源的分佈式協調服務,最早是和Hadoop、Hbase同時發佈,做爲Hadoop、Hbase的重要組件,提供了數據/發佈訂閱、負載均衡、分佈式同步等功能。

Zookeeper保證了CP,具體由以下幾部分組成:

  • Leader-Server:Leader負責進行投票的發起和決議,更新系統中的數據狀態,每個集羣只有一個Leader-Server
  • Server:Server中存在Follower和Observer兩種類型,其中Follower接受客戶端的請求並返回結果(事務請求將轉發給Leader處理),並在選舉過程中參與投票,Observer與Follower功能一致,但是不參與投票過程,它的存在是爲了提高系統的讀取速度
  • Client:請求發起方,Server和Client之間可以通過長連接的方式進行交互

服務註冊中心有很多的可選工具,需要依據各自的業務及要求進行選擇,傳媒依據自己的業務特點,使用了Consul做爲服務註冊中心,後期將做詳細介紹。

服務的註冊與調用

微服務由一些職責單一的細粒度服務組成分佈式網狀結構,服務之間通過輕量級協議進行通信。服務提供方需要註冊服務,通知消費方,服務消費方需要找到服務提供方實例地址,並進行消費,服務註冊中心還需要檢查服務提供方的實例的健康狀態。

我們將服務消費主要分爲以下三類:

集中式:在服務提供者和服務消費者之間通過負載均衡進行轉發,這個負載均衡比較常見的有硬負載(如F5,現在比較少見),軟負載(LVS、HAProxy等軟件),負載均衡上保存所有服務的地址映射表,這些地址映射表通常由運維人員進行註冊,當服務消費方消費服務時,向負載均衡發出請求,負載均衡依據相應策略(比如:輪詢,隨機等策略)將請求轉發到目標服務,從而實現服務的調用。負載均衡一般都有健康檢查機制,會定期摘除不健康的服務實例。

集中式的優點及缺點如下:

  • 優點:實現簡單,也容易做集中式的訪問控制,目前這種方式還是主流
  • 缺點:最主要的問題就是單點問題,所有的流量都經過負載均衡,當請求量比較大的時候,負載均衡就成爲了瓶頸。如果負載均衡發生故障,那對於整個系統的訪問是災難性的。負載均衡在服務調用方和服務提供方之間增加了一層,有一定的性能開銷

進程內:將負載均衡以二方包的形式提供給服務消費者和服務提供者,負載均衡在服務消費者及服務提供者的進程中運行,這種方式在很多Java的RPC框架中見到,比如:Dubbo、Ribbon、Motan等。

進程的優點及缺點如下:

  • 優點:服務直接調用,沒有額外開銷,性能比較好,也沒有點單故障的問題
  • 缺點:對於不同的語言棧需要開發不同的二方包,維護及開發成本極高。涉及到二方包的升級及變更,都會導致應用的重新部署,這對升級和推廣都造成了比較大的阻力

獨立進程:前面兩種方案都存在一些弊端,爲了解決前面兩種的問題,提出了一個獨立進程負載均衡方案,這個方案是對前兩種方案的不足提出的一種折中方案,將第二種方案做了優化,將進程內的負載均衡移了出來,變成了一個獨立進程,服務消費方消費服務時,都通過本機的服務代理進行訪問。

獨立進程優點及缺點如下:

  • 優點:是一個分佈式方案,一個進程故障隻影響該主機上的調用,對整體調用不受影響。服務消費方通過本機的代理進行消費,性能相對較好。沒有語言棧的約束,在升級或推廣中也會比較容易
  • 缺點:部署相對複雜,中間的環節比較多,排查問題不是很方便

目前在傳媒內部,使用的是第二和第三種方案的結合,對於Java語言棧,一般使用進程內方案,性能會比較好,對於其他語言,使用第三中方案,後期會詳細介紹。

服務容錯

在整個系統微服務化之後,服務與服務之間存在着錯綜複雜的調用關係,每個服務都不可能保證100%的可靠,服務可能會出現不可用的狀況,如果調用方所依賴的服務產生故障,不能快速進行容錯或隔離,那個這個應用就會存在拖垮整個應用的風險,如果多個調用方都產生不可用情況,就會產生雪崩,嚴重時整個系統將不能提供正常服務。

Hytrix是Netflix公司開源的服務容錯框架,它通過三個方面解決服務容錯相關的問題。

  • 隔離:限制調用服務的資源使用,一個服務出現故障不影響其他服務的調用,隔離有線程池隔離模式和信號量隔離模式
    • 線程池隔離模式:使用一個線程池來存儲當前的請求,線程池對請求作處理,設置任務返回處理超時時間,堆積的請求堆積入線程池隊列
    • 信號量隔離模式:使用一個原子計數器(或信號量)來記錄當前有多少個線程在運行,請求來先判斷計數器的數值,若超過設置的最大線程個數則丟棄改類型的新請求,若不超過則執行計數操作請求來計數器+1,請求返回計數器-1
  • 降級:資源不足,請求超時或熔斷後自動觸發降級,配合降級接口返回結果作爲兜底,也就是調用fallback,返回一個缺省值
  • 熔斷:當失敗率達到閾值,自動觸發熔斷,熔斷類似於我們家裏的電閘,當電流過載時,會觸發電閘斷電,保護家裏的電器設備一樣,當訪問量過載時,熔斷就會觸發,保護我們的接口不會被拖垮

正常狀態下,熔斷器處於Closed狀態,如果調用超時或持續出錯,就會進入熔斷狀態(Open),後續所有請求都會被拒絕,一段時間後,保護器會嘗試進入半熔斷狀態(Half-Open),允許少量請求進來嘗試,如果調用仍然失敗,則回到熔斷狀態,如果調用成功,則回到電路閉合狀態

網關

在微服務場景下,一個系統有可能被拆爲多個微服務,每個微服務又暴漏了若干API(以Restful形式暴漏),管理起來非常的不方便,接入也非常的麻煩,在外網訪問每個服務的時候,需要有一個API網關提供統一的入口,將流量轉發給對應的後端取得數據後再一次返回,除此,還需要增加限流、熔斷、鑑權等通用功能。

統一網關有如下優點:

  • 統一API入口、隔離後端:客戶端統一使用網關的入口地址,不需要和後端服務一個個進行交互
  • 認證鑑權:網關提供統一的認證,鑑權服務
  • 負載均衡:網關提供負載均衡算法
  • 降低後端開發對API安全性的考慮:安全統一由網關考慮,後端無需考慮安全
  • 緩存:可以提高接口響應速度
  • 日誌:提供統一的接口訪問日誌
  • 統計:基於接口層面的統計分析
  • 服務降級、流量控制:網關可以做到熔斷、降級等功能
  • 安全、防刷:網關提供統一的安全機制

目前開源網關方案有很多,我們列舉了如下幾個網關產品:

目前在網易傳媒使用Kong做爲統一網關。

以上對微服務做了一些比較全面的介紹,下一篇會結合網易傳媒的實際情況,如何在傳媒內部做到微服務框架的落地與推廣的。

原文鏈接: https://mp.weixin.qq.com/s/MlCOh3SFibreIIT63AJJHQ

相關文章