《微服務設計》閱讀筆記(四)集成

《微服務設計》,Building Microservices,作者Sam Newman,譯者崔力強、張駿,人民郵電出版社,2016年。

筆記中有些內容直接引用原書。

================================================================

第四章 集成

1. 尋找理想的集成技術

避免破壞性修改。例如,響應增加欄位不影響服務方。

保證API技術的無關性。微服務之間通信方式的技術無關性很重要。

使你的服務易於消費方使用。利於消費方使用任何技術來用你的服務。

隱藏內部實現細節。暴露內部實現會導致消費方去耦合內部實現,因此當修改內部實現時造成消費方不必要的修改。不要採用傾向於暴露內部細節的技術。

2. 為用戶創建介面

3. 共享資料庫。基於表的共享,會使得服務消費者看到內部實現,無法實現隱藏內部細節。另外,服務實現綁定了資料庫技術,導致服務消費者也必須要使用同樣的資料庫,無法帶來技術開放性。因此,避免使用共享資料庫。

4. 同步與非同步

同步通信的協作風格是請求/響應式,非同步通信的風格是基於事件。適合用非同步通信的場景:運行時間長的任務、低延時的任務、移動網路及設備。基於事件的系統依賴於接收事件的系統自己判斷該做什麼,其協作邏輯是分布在不同的協作者中,因此耦合度低。

5. 編排與協同

編排,依賴於某個中心來驅動流程。而協同依靠各個部分主動協作共同完成。編排的好處在於系統實現簡單,便於追蹤問題。缺點是中心控制節點承擔太多職責,其它服務淪為CRUD貧血服務。協同的優點在於能消除耦合。缺點是需要額外工作來監控流程,增加系統複雜度。另外,如果想用請求/相應風格的語義,又想避免耗時業務時的長等待,可以採用非同步請求加回調的方式。

6. 遠程過程調用

遠程過程調用(RPC)種類很多,一些依賴於介面定義(SOAP、Thrift、protocol buffers等),容易生成客戶端和服務端的樁代碼,用戶可以快速編程。但其代價大於快速啟動的好處。

技術的耦合。Java RMI,雙方必須使用Java。Thrift和protocol buffers支持不同語言,一定程度上減輕了該問題。有時候RPC技術對於互操作性有一定的限制。

本地調用和遠程調用並不相同。RPC面臨網路的不確定性,還要進行載荷消息的封裝和解封裝。用戶在使用時需要額外考慮網路帶來的問題,而當作本地調用時又會帶來考慮不全的問題。在進行RPC調用的錯誤處理時,顯然要麻煩的多。

脆弱性。以Java RMI為例,介面修改就要導致樁代碼的修改。

RPC很糟糕嗎。盡量避免使用RMI,轉為使用現代的RPC如protocol buffers或者Thrift。使用RPC時,不要對遠程調用過度抽象,以至於網路因素都被隱藏了;確保可以獨立升級服務端介面而不用客戶端強制升級;在客戶端中不要隱藏是在做網路調用這個事實。

7. REST

REST使得資源在服務內和在服務對外提供的形式可以不一樣,解耦了。建議看Richardson的成熟度模型(martinfowler.com/articl)。 REST沒有規定底層協議,常用的是HTTP,也可以使用其它協議如串口或USB。HTTP上實現REST簡單。

REST和HTTP。REST聲明了一組對資源的使用方法,HTTP中有方法能與其對應。HTTP有很多支撐工具和技術。比如Varnish是HTTP緩存代理,mod_proxy是負載均衡器,還有大量HTTP監控工具,還有安全認證機制和工具。

超媒體作為程序狀態的引擎。超媒體是一塊包含了其它內容鏈接的內容。客戶端與服務端應該通過超媒體進行交互。通過超媒體可以隱藏服務端內部的更改,將客戶端與服務端解耦。該方式的缺點是客戶端和服務端之間通信次數較多。但還是建議客戶端自行發現遍歷和發現API,因為這樣可以解耦,不要過早優化。

JSON、XML和其他。JSON簡單,內容更緊湊,比XML流行。但XML中有超鏈接來進行超媒體控制,JSON中沒有,於是JSON有不同的自定義方式,如HAL標準。XML工具有更好支撐,提取負載特定部分可以使用XPATH工具,挺多,CSS選擇器也可以用。JSON可以使用JSONPATH。

留心過多的約定。有些工具使用RESTFul Web服務框架把內部存儲暴露給消費者,並不好。

基於HTTP的REST的缺點。無法像RPC一樣幫助生成客戶端代碼。不要回到基於HTTP進行RPC的老路去構建共享庫。另外,性能上的問題:基於HTTP的REST支持多種格式,如JSON或二進位,比SOAP強,但沒法和Thrift這樣的二進位協議比。對於低延遲通信或較小尺寸的消息不是一個好選擇。不支持高級的序列化和反序列化。建議閱讀《REST實戰》這本書。

8. 實現基於事件的非同步協作方式

技術選擇。需要考慮微服務發布事件機制和消費者接收事件機制。RabbitMQ這樣的消息代理可以解決上述問題,是個好選擇。但盡量讓這種消息中間件簡單,邏輯放在自己的服務中,企業級服務匯流排是個不好的反例。在HTTP上,有ATOM這個符合REST規範的協議,可以用來提供資源聚合的發布服務。但是有消息中間件的話,還是建議使用消息中間件。

非同步架構的複雜性。事件驅動的非同步系統耦合度低,伸縮性好,但需要程序員轉換思維模式,而且複雜性更高。要考慮各個流程有很好的監督,並考慮使用關聯ID,它可以對跨進程請求進行追蹤。強烈推薦《企業集成模式》這本書。

9. 服務即狀態機。要把關鍵領域的生命周期顯式地用狀態機建模出來,避免出現貧血服務。

10. 響應式擴展(Reactive extensions, Rx)。它提供了一種機制,可以把多個調用結果組裝起來並在此基礎上執行操作。調用本身可以是阻塞或非阻塞的。當需要做一些基於多個服務調用的操作時,可以嘗試它,它讓代碼更加簡單。

11. 微服務世界中的DRY和代碼重用的危險。Don』t Repeat Yourself,DRY可以得到重用性比較好的代碼,可以創建一個共享庫。但這在微服務中會導致服務和消費者之間過度耦合。在微服務內部不要違反DRY,在跨服務的情況下可以適當違反DRY。

客戶端庫。客戶端庫可以對服務開發進行一些封裝,提升開發效率,避免重複的與服務交互的代碼。但當開發服務端API和客戶端API是同一撥人時,存在將服務邏輯引入客戶端的問題,帶來了耦合性的問題。如果要使用客戶端,讓它只處理底層傳輸協議(服務發現、故障處理等),不要加入服務邏輯。另外,客戶端庫可能會限制不同技術的使用。

12. 按引用訪問。如果對訪問的資源有本地緩存,要考慮資源的過期失效問題,確保同時有一個指向原始資源的引用。

13. 版本管理

儘可能推遲。避免過早將客戶端與服務端緊密綁定。客戶端要儘可能靈活消費服務響應,這符合Postel法則(系統中的每個模塊都應該「寬進嚴出」)。例如客戶端可以使用XPath從服務響應中提取需要的欄位,即使欄位位置改變也能正確讀取(容錯性讀取器)。

及早發現破壞性修改。建議使用消費者驅動的契約來及早定位對消費者產生的破壞性修改。

使用語義化的版本管理。語義化版本管理使得客戶端僅通過查看版本號就能知道是否能與之集成。版本好:MAJOR.MINOR.PATCH。MAJOR改變意味著包含向後不兼容的修改,客戶端就不能直接集成。MINOR變化意味著新功能增加,向後兼容,客戶端可以直接集成。PATCH變化意味著功能缺陷修復。

不同的介面共存。介面不可避免要修改時,保留老介面,提供新介面,二者共存。給消費者時間將老介面替換為新介面的使用,然後再刪除老介面。另外,可以通過將老介面的請求轉換為新介面的調用。不同版本共存時,可以在請求信息中增加版本標識,也可以在URI中增加版本標識。

同時使用多個版本的服務。為了支持老用戶,有時候會使用多個版本的服務共存(注意,這裡不是指服務介面,而是指服務本身)。短期內合理,但更應該考慮一個服務暴露兩套API,而不是兩個服務共存。

14. 用戶界面

走向數字化。通過微服務的不同組合為桌面應用、移動端設備、可穿戴設備提供不同的體驗。

約束。不同平台(桌面端、移動端)有不同的約束,屏幕解析度、通信方式、帶寬、電池電量、UI操作。

API組合。 不同平台的API可以使用API入口(gateway),多個底層的調用會被聚合成一個調用。

UI片段的組合。相比UI主動訪問所有API,再同步狀態到UI控制項上,更好的方法可能是服務直接暴露一部分UI,然後將這些組合到一起形成整體UI。可使用服務端模板的技術將這些片段組裝起來。優勢是修改服務的同時可以維護這些UI片段。

為前端服務的後端。服務端的聚合介面或API入口不要太厚重,要分成不同的後端,每個後端只為一個應用或用戶界面服務(BFF, Backends for Frontends)。

一種混合方式。片段組裝、BFF等可以權衡混合使用。

15. 與第三方軟體集成。

使用一些商業的第三方軟體會有如下問題:

缺乏控制。只有軟體的廠家才能控制其發展和進行技術決策。

定製化。定製化很昂貴。

義大利面式的集成。一團亂麻的服務集成。

推薦的集成方式:

在自己可控的平台進行定製化。推薦這麼做,可以使用自己的服務包住第三方的服務。

絞殺者模式(Strangler Application Pattern, martinfowler.com/bliki/),攔截對老系統的調用,把調用路由到現存的遺留代碼還是新寫的代碼,然後逐步替換老系統。一般使用一系列的微服務來攔截,而不是單一的單塊應用。

BrianZhang:《微服務設計》閱讀筆記(一)微服務zhuanlan.zhihu.com圖標BrianZhang:《微服務設計》閱讀筆記(二)演化式架構師zhuanlan.zhihu.com圖標BrianZhang:《微服務設計》閱讀筆記(三)如何建模服務zhuanlan.zhihu.com圖標BrianZhang:《微服務設計》閱讀筆記(五)分解單塊系統zhuanlan.zhihu.com圖標BrianZhang:《微服務設計》閱讀筆記(六)部署zhuanlan.zhihu.com圖標BrianZhang:《微服務設計》閱讀筆記(七)測試zhuanlan.zhihu.com圖標BrianZhang:《微服務設計》閱讀筆記(八) 監控zhuanlan.zhihu.com圖標BrianZhang:《微服務設計》閱讀筆記(九)安全zhuanlan.zhihu.com圖標BrianZhang:《微服務設計》閱讀筆記(十)康威定律和系統設計zhuanlan.zhihu.com圖標BrianZhang:《微服務設計》閱讀筆記(十一)規模化微服務zhuanlan.zhihu.com圖標BrianZhang:《微服務設計》閱讀筆記(十二完結篇)總結zhuanlan.zhihu.com圖標軟體開發之路zhuanlan.zhihu.com圖標
推薦閱讀:

如何應對線上故障
《Cloud Native Go》筆記(七)構建數據服務
《微服務設計》閱讀筆記(十二完結篇)總結
《微服務設計》閱讀筆記(六)部署

TAG:微服務架構 | 軟體開發 |