架構風格:微服務
本文探討:
- 什麼是微服務
- 微服務的約束
- 微服務對架構屬性的影響
什麼是微服務
「微服務」是一種架構風格,也就是說,「微服務」是一組架構約束。
前面說到REST是一種複合式的架構風格,微服務也是!微服務的約束面更廣,它對開發過程和開發人員也進行了約束!
微服務的約束
MartinFlower在Microservices一文中,詳細闡述了微服務所需要具有的約束!
- Componentization via Services:基於服務的元件化
- Organized around Business Capabilities:圍繞業務能力進行組織
- Products not Projects:產品而不是專案
- Smart endpoints and dumb pipes:智慧終端和靜默管道
- Decentralized Governance:去中心化治理
- Decentralized Data Management:去中心化資料管理
- Infrastructure Automation:基礎設施自動化
- Design for failure:容錯性設計
- Evolutionary Design:進化式設計
實際上這些約束回答了架構設計所關心的幾個問題:
- 系統如何切分:圍繞業務能力進行組織,去中心化資料管理
- 模組之間如何通訊:基於服務的元件化,智慧終端和靜默管道
- 如何進行技術選型:去中心化治理
- 容錯性:容錯性設計
- 擴充套件性:產品而不是專案,進化式設計
- 可維護性:基礎設施自動化
下面一個個的說明!
系統如何切分?
在「架構風格:萬金油CS與分層」一文中,最後提到,一般情況下,當你不知道一個系統使用何種架構比較好時,可以先使用分層架構。分層架構就是將系統一層一層的切分,下層為上層提供服務。
每一層的邊界是什麼呢?是「系統功能」!展現、業務邏輯、資料儲存。你會發現,這種切分方式和業務本身沒有任何關係,所以才是「萬金油」!
另外,這種切分方法也將開發人員劃分成了前端、後端、DBA!這是目前主流的做法,好像也沒有出現什麼大問題!
如果你在大公司待過,你就會發現進行一個需求變更是多麼麻煩的一件事。即使一個很簡單的需求,都可能要所有團隊都參與進來。
導致這個問題的原因是什麼呢?是溝通成本!
專案管理演算法的複雜度是O(N 2),當人員變得越來越多時,溝通成本成倍增長:
- 5人團隊,需要溝通的渠道是 5*(5–1)/2 = 10
- 15人團隊,需要溝通的渠道是15*(15–1)/2 = 105
- 50人團隊,需要溝通的渠道是50*(50–1)/2 = 1,225
- 150人團隊,需要溝通的渠道是150*(150–1)/2 = 11,175
我們都知道「技術是為業務服務的」!如果一個架構和業務沒有關係,如何為業務服務呢?如果溝通要花費大量的時間,如何快速推進專案呢?
所以,微服務「圍繞業務能力進行組織」!
- 既包括了系統的切分
- 也包括了對人員的組織
因為康威定律提到:
"Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations." - Melvin Conway (1967).
在微服務中,每個模組(這裡的模組和我們平常所理解的模組有些區別,它的粒度更大,所以在微服務裡一般稱為是服務,下面均使用「服務」)都是一個完整的業務系統!包括了展現、業務邏輯和資料儲存!相應的,負責開發的人員需要具備開發這個服務所需要的所有技能!
也就是說,在微服務中服務的邊界是業務的邊界!
這很類似韓都衣舍的「以產品小組為核心的單品全程運營體系(IOSSP)」!將企業劃分為“小集體”,像自由自在重複分裂的“阿米巴”——以各個“阿米巴”為核心,自行制訂計劃,獨立核算,持續自主成長。以3人一組的產品組為例,這三個人分別是設計師、頁面製作、庫存管理員。這三人全權負責某一單品的頁面製作、款式設計、尺碼以及庫存深度的預估等工作。
對應到微服務中,即兩到三個人負責一個服務,這個服務包含了完整的業務流程,開發人員需要掌握開發這個服務所需要的完整的技能,包括UI、程式設計、DBA!
這裡的難點是:
- 一是要劃分好業務邊界,使得每個服務能夠高內聚、低耦合!
- 二是制定規範,利於各個服務之間的通訊
- 三是人員技能的要求更高
如何進行業務劃分,需要根據具體的業務來具體進行。這裡暫不展開。只提一點,就是要將事務考慮在內!
就是說在切分系統的時候,要考慮事務問題!我們都知道遠端事務是一個比較難處理的問題!兩階段提交、三階段提交都不能很好的解決分散式事務問題!Paxos演算法過於複雜,且效能較差。
所以微服務的建議是:
- 儘量保證事務在一個服務中執行
- 通過補償的方式來彌補事務操作的問題
服務如何通訊?
對於一般系統來說,我們都是使用的程序內通訊,即通過呼叫同一記憶體內的方法的方式進行通訊!公用的程式碼我們可以以「庫」的形式進行組織,避免程式碼重複!這種系統我們一般稱為「單體系統」!
「單體系統」的伸縮性不理想!比如說,雙11需要做個活動,瞬間使用者量大增!如果需要應對流量峰值,就需要對系統進行擴容。但是因為是單體系統,擴容只能整體擴容,而實際上需要擴容的只是那個活動頁面!這就導致了資源的浪費。另外一個問題就是,如果這個活動導致了系統崩潰,這將導致這個系統的所有功能都不能使用!
一種解決方案是進行「服務化」!即將需要多個系統公用的邏輯或TPS較高的模組獨立部署,通過程序間通訊的方式,進行服務呼叫。比如上面的活動模組,當活動模組以服務的方式對外服務後,需要擴容時,只需要擴容活動服務就可以了。同時,如果活動服務出現了問題,只會導致這個活動相關內容無法訪問,而不會影響系統的其它功能。今年雙11淘寶的地址服務就掛了,但是並不影響淘寶本身的訪問。
這裡所說的「服務化」是使用dubbo這類服務化框架進行的服務化,而不是使用ESB的SOA!
基於ESB的SOA主要是為了將企業中的各個系統連線起來!ESB像一根「聰明」的管道,用來連線各個「愚笨」的節點。為了整合不同系統,不同協議的服務,ESB做了很多事情:
- 訊息路由
- 編排
- 轉換
- 業務處理規則
這就導致ESB很重、很複雜。這也是基於ESB的SOA被人詬病的一個原因。
dubbo這類服務化框架主要解決的是執行時程式碼複用、系統伸縮性以及高效能問題!但是服務粒度相對較小,帶來的問題就是維護的成本相對較高!
而微服務可以說做了一些折中:
- 服務粒度較大,包含了一個完整的業務的展示、邏輯和儲存。相對的數量就較服務化少,維護相對較容易
- 以程序間通訊的方式提供服務。包括對外服務、以及其它服務。保證了伸縮性。
- 業務邏輯處理都在服務內部進行,通訊元件只提供單純的通訊功能。保證了簡單性。
這樣既擺脫了繁重的ESB,也降低了維護難度!
如何進行技術選型?
對於「如何進行技術選型」,微服務不強制開發平臺!因為「沒有銀彈」!微服務偏向於「適合的工具解決適合的問題」!
每個程式設計師都有自己喜歡的技術體系!有喜歡Java的、有喜歡.Net的、有喜歡C++的,還有喜歡Lisp的。。。。
那開發系統時需要選擇哪種技術體系呢?按微服務的觀點就是:哪種技術合適就用哪種技術吧!這個服務需要高併發,可以用Go來進行開發!這個服務需要快速推進,可以用PHP!這個服務需要穩定,可以用Java!看起來很完美!
而實際上內,這導致的是不可控!為什麼Java語言會被很多企業使用?其中一個原因就是可控!
舉個例子,國內公司的技術棧相對比較單一!比如,公司的主流語言是Java,.Net,PHP等,其它語言就只是輔助!一般不會有兩種、甚至三種主流語言!
假設一家公司的主流語言是Java!開發一個系統,可能需要10個人。那公司可以招5~6個一般的,2~3個不錯的,1個牛逼的!公司只要穩住那個牛逼的就行了!如果有人走了,只要其他人頂上就行了!
而如果每種服務都使用不同的語言,那一個系統使用了三個左右的語言,每種語言得有個熟練掌握的吧?每種語言,公司都得穩住個相對牛逼的吧?成本高不說,難度也大了不少!
容錯性
系統按照業務切分為一個個的服務,相對單體應用來說,執行的系統多了,系統整體不可用的機率降低了,但是單個服務出現問題的機率卻變大了!這就需要微服務系統需要有比單體應用更好的容錯性!
任何服務可能因為供應商的不可靠而故障,客戶端需要儘可能的優化這種場景的響應。與單體構架相比,這是一個缺點,因為它帶來額外的複雜性。這將讓微服務團隊時刻需要關注服務故障的情況下的使用者體驗。
由於服務可能隨時出現問題,所以快速故障檢測,甚至自動恢復就變更非常重要。微服務應用把實時的監控放在應用的各個階段中,檢測構架元素(每秒資料庫的接收的請求數)和業務相關的指標(每分鐘接收的訂單數)。監控系統可以提供一種早期故障告警系統,讓開發團隊跟進並調查。
這又無形中提高了對開發人員的技術要求!
擴充套件性
對於網際網路產品來說,這是個必選項!
以前在網上看到過一句話,大意是:「當你有一個想法的時候,世界上可能有1萬個人也有這個想法!其中1000個人已經開始做了!100個人已經做完了!10個人已經運營了!1個已經盈利了!」
也就是說,相同的產品千千萬。使用者為何就偏愛你這款?
你的系統需要有核心競爭力,來吸引新使用者!同時還需要不斷的加入新功能,保持使用者不流失!
可維護性
服務的數量增加了,維護的成本也就相應的增加了。除了上面提到的通過降低溝通成本來提高可維護性外,微服務還通過「基礎設施自動化」來降低維護難度!
基礎設施自動化有如下幾個原因:
- 由於微服務的服務較單體應用會多了很多,這就導致了部署微服務較部署單體應用來說要複雜得多。單純的靠運維來手動部署不現實
- 部署的服務較多,且是網狀通訊,導致了一個請求可能會呼叫多個服務,對於請求的追蹤不能像單體應用一樣,靠日誌來跟蹤。需要追蹤請求。
- 當請求異常時,或服務異常時,需要能自動的處理一些常見情況(也涉及上面的「容錯性」)