“微服務”的概念興起於四五年前,近幾年尤其火熱,各大廠都在進行微服務化改造和微服務建設。最近一年來我們也參與了微服務化的改造大軍,這里寫下一些做微服務系統設計和開發時的切身感受。

01 微服務架構
說起微服務,不得不提那篇經典的文章,來自Martin Flower的《Microservices》,建議多讀幾遍。Martin Flower是敏捷開發方法創始人之一,《重構》《企業應用架構模式》作者,ThoughtWorks公司的首席科學家。微服務雖然不是在這篇文章中首次提出,但是它將發展多年的微服務架構進行了重要性總結,推動了微服務的流行。
Martin在文章中從多個方面詳細闡述了微服務的概念,首先作者對比單體應用的架構,一個單體應用處理請求的所有邏輯都運行在一個單獨的進程中,這種情況下,你可以在筆記本上開發、測試、部署都很簡單,還可以通過負載均衡進行橫向擴展,最后交付給運維團隊。單體應用非常成功,但是越來越多的人感覺不妥,尤其是在雲中部署的時候,任何微小的變更都要整體重新構建和部署,擴展的時候也需要整體擴展,不能進行部分擴展。這時候微服務架構風格就出現了,它提出將應用程序構建為一套服務,每個服務都可以獨立部署和擴展,運行在獨立的進程中,服務之間通過RPC調用進行通信。微服務的應用致力於松耦合和高內聚:采用單獨的業務邏輯封裝,接受請求、處理業務邏輯、返回響應,而且喜歡簡單的REST風格,而不喜歡復雜的協議,最終實現敏捷開發。

微服務不是什么框架,也不是什么系統,只是一種架構風格。我們所使用的DSF(華為)、DUBBO(阿里)、Spring Clould(pivotal)等框架,在介紹中都稱是分布式服務框架。這些分布式服務框架都是微服務架構必不可少的基礎能力,微服務一定是分布式的。分布式服務的概念比較模糊,只是解決了網站的高並發問題,很多細節問題是微服務幫其明確的。微服務更加強調敏捷和健壯,強調服務的粒度,一個服務只需完成一個單一的、獨立的功能,多個微服務組合完成相對復雜的業務系統,以滿足需求。而且微服務注重借助於各種中間件進行業務解耦和提高性能,以及提高服務的容錯性。
從上面的介紹中我們可以看出,微服務架構有很多優點。例如,服務的拆分將復雜問題簡單化;每個服務由專門的團隊開發,開發者可以自由選擇實現技術,提供API服務;每個微服務都可獨立部署,加快了部署速度;每個服務可獨立擴展以滿足需求。微服務不是免費的午餐,微服務架構也有缺點。微服務概念強調了服務的大小,但是服務變小不是最終目的,微服務的目的是有效地拆分應用,實現敏捷開發和部署;微服務應用都是分布式系統,需要通過RPC進程間通信完成服務調用,這樣大大增加了系統的復雜性,因此必須寫代碼處理由於網絡或者服務不可用等導致的調用失敗問題,雖然一般框架都支持相關配置,但是在這種情況下微服務顯得相對復雜些;在微服務架構的應用中,建議不同的服務使用不同的數據庫,這種情況下,一個交易一般會調用多個服務,同時需要修改多個數據庫,由於CAP理論和其它的一些因素,並不能實時地保證數據的一致性,因此不得不使用最終一致性的方法,從而對開發者提出了更高的要求和挑戰;測試一個微服務架構的應用也是很復雜的任務,首先需要啟動和它相關的所有服務(至少需要這些服務的stubs)。最后還是要強調一下,不要低估了微服務架構帶來的復雜性,下面介紹一下我們如何應對這樣的復雜性。
微服務架構給我們帶來方便的同時,也引入一定的系統復雜性,最近幾年隨着基礎設施自動化技術的發展,比如雲平台、容器技術,再加上自動化測試與持續集成,減少了構建、發布、運維微服務的復雜性。因此我們的微服務團隊應該依賴基礎設施自動化技術構建軟件,下圖說明這種構建的流程:

在構建微服務軟件時使用的分布式服務框架也擁有很多特性,這些特性提供了很多復雜問題的解決方案,比如異步調用、超時失敗策略、故障隔離、健康檢查、流量控制以及自定義路由等,這些特性大大減輕了開發者處理邏輯的負擔,還有一些高性能、高可用的保障都增加了我們構建微服務的信心。而且經過多年的微服務實踐者的摸索,也總結出了很多輔助運維系統,比如統一日志收集(ELK)、服務管理、服務監控和服務治理等,大大減輕了運維的工作,而且能讓我們對復雜的微服務系統做到心中有數。
總之,微服務架構入坑容易,坑了呆得舒服難。各種基礎設施和配套系統必須跟得上,還得有一個具有微服務特性的團隊,才能真正駕馭得了微服務。
兩個值得深入的話題:
1.微服務與持續集成
2.微服務與測試
02 微服務團隊
上一節中說到更適合構建微服務應用的微服務團隊,什么時微服務團隊?說一個比較現實的問題,當我們做服務拆分的時候,通常管理都會集中在技術層面,涉及到UI團隊、服務端業務邏輯團隊、數據庫團隊、測試團隊和運維團隊。當采用這種標准對團隊進行划分時,即使時小小的變更都將導致跨團隊項目協作,從而消耗時間和預算審批。這就是 Conway's Law :
設計一個系統的任何組織(廣義上)都會產生這樣一種設計,其結構是組織交流結構的復制。
——Melvyn Conway, 1967
Melvyn Conway 的意思是設計一個系統的團隊結構將決定了一個軟件系統的結構,將人員划分為 UI 團隊,中間件團隊,DBA 團隊,那么相應地,軟件系統也就會自然地被划分為 UI 界面,中間件系統,數據庫。而一個高效的微服務團隊會針對這種情況進行改善,微服務團隊需要是一個全棧的團隊,跨職能的團隊,應該包含整個項目周期的所有技能,前后端開發、UI設計、測試、構建部署、上線與運維都是必須技能。
微服務團隊除了熟練的業務邏輯開發之外,還需要有DevOps能力、服務的快速構建、良好的團隊文化:
- 首先DevOps能力是保證持續交付和應對復雜運維問題的動力之源,運維人員不懂開發人員的服務設計和調用流程,開發人員不懂產品環境和整體配置結構,開發和運維的融合才能更好的應對微服務架構。正如下面這句話所說的,“你構建,你運維”。
You build it, you own it. – Amazon CTO
因此,需要打造DevOps文化,將運維作為需求提前注入到開發流程中。

-
其次保持服務的持續演進,使服務能夠快速、低成本地被拆分和合並,以快速響應業務的變化。
-
同時要保持團隊和架構的對齊,微服務看似是技術層面的變革,但它對團隊結構和組織文化有很強的要求和影響,識別和構建匹配架構的團隊是解決問題的加速器。微服務團隊的另一個關鍵點是持續改進、持續學習和反饋,只有保持這樣一個文化氛圍,微服務架構才能持續發展下去,保持新鮮的生命力,進而實現我們的初衷。
專業的微服務團隊,為微服務保駕護航。
03 項目的微服務設計實踐
我們在各種基礎設施不健全的情況下,匆忙進入了微服務改造的深淵。原來的單體應用按照功能拆分成了下面的結構:

拆分之后,模塊突然變多了。將內部業務邏輯和原子功能拆分出來,實現了部分功能的復用,並且對外的接口按類型區分到不同的模塊中去了,方便了使用,但是增加了管理的難度。
從上面我們對微服務架構的了解,一個微服務系統會有大量的服務組成,服務之間的層次關系依然是存在的,但是調用順序上的要求會有所降低,只要滿足嚴格的上層調用下層即可,在某些簡單的業務功能上允許跨層調用。

上圖是三種架構(集中式、分布式、微服務架構)的形象化展示。可以看到微服務的一個狀態,乍看起來有些混亂,如果還按照以前的管理方式維護項目的話,工作量會成指數級增長,人力所無法勝任的工作。
這時候就需要依賴一些分布式服務框架,並建立一些輔助運維系統:
- 首先服務之間遠程調用,服務的注冊和發現機制必須有好的分布式服務框架(類似dubbo)支持,方便做服務之間的調用配置管理。
- 部署的服務進程增加以后,對應的日志文件也會增多,這時再使用ssh到服務器上查看日志,這個工作量也是可想而知的。我們對業務日志做了規范化約束,然后使用ELK技術棧搭建了日志集中化管理系統。
- 為了能夠對線上的所有服務有個全局的把控,我們根據注冊中心的數據搭建了服務的管理系統,展示各個維度的統計數據,例如,每個主機上多少個應用,每個應用提供了多少個服務,同時又消費了多少個服務等等。還有一些針對服務的約束規則的告警信息,例如某個應用消費的服務,卻沒有服務提供者等。還有一個整體的應用之間的依賴關系圖。
- 為了優化系統結構和排查問題,搭建了服務的監控系統,這個是依賴分布式服務框架打印的預統計日志的,通過這些日志分析得到一個整體的服務監控功能,例如每個服務的響應時間、錯誤率等。還有調用鏈跟蹤功能,排查問題時使用它來跟蹤請求信息。
- 服務治理功能用來及時地對線上項目做一些調整,例如限流、降級、負載均衡、超時、路由、隔離容錯等。
有了以上這些系統輔助,我們的微服務化改造之路平坦了許多。
在進行微服務化改造的時候,接口的設計上遇到了一個問題,服務之間的調用是通過私有協議進行的RPC調用,這種調用中如何描述服務響應成功之外的其他異常情況?
1.采用Exception類,定義各種異常類來描述異常情況。
2.采用錯誤碼+錯誤描述。
其中方案1采用的Exception類,是我們平時java中定義進程內部接口最常見的方法,這種方法的優點是,能夠使調用接口的一方的代碼更簡潔,通過try...catch來處理,如果不需要處理的話,在方法上聲明直接向上拋出即可。缺點是跨語言開發解析難度大增,而且日志中異常堆棧很多。方案2采用錯誤碼的形式恰恰相反,缺點就是每次調用都要判讀是否調用成功,增加代碼中的if語句。
針對這個問題,希望各位實踐分布式服務或者微服務的大神給出你們的實踐方案,瘋狂討論起來。
04 結束語
上述三節中講述了我們在構建微服務的經歷和一些感想,給其他准備實施微服務和正在實施微服務的團隊以參考,寫這篇文章的另一個目的就是希望能起到拋磚引玉的作用,希望能和其他團隊進一步交流。
