微服務介紹與實踐總結
近年來,微服務與DevOps等概念不斷熱炒。兩者實際上是緊密相聯,又相輔相成,Docker、Mesos、Kubernates等技術方案的快速崛起,為微服務提供了更堅實土壤,使其得以更順利地實施落地。 類似spirng-boot等技術的發展與大為傳播,更是直接促進了微服務成熟化發展。本文將從與對傳統單體架構服務與微服務的比較,介紹微服務,並在最後對DevOps與微服務聯繫做簡單介紹。
單體架構(Monolithic Architecture )
假設你要開發一個Web後台服務,大部份開發者一開始肯定向於將,所有功能實現放在一個服務進程內。例如JavaWeb的開發者,往往會產出一個War包,這就是代碼編譯後全部結果,只要丟到tomcat或者jetty容器就可以運行。這就是一典型的單體架構。當然單體架構不是簡單的代碼堆疊,單體架構對於開發者而言,同樣要求較好的模塊劃分與清晰的分層設計。
單體架構的好處明顯:- 物理架構簡單。往往都是單機搞定。
- IDE友好,一個project搞定。
- 易於布署。以JavaWeb為例,將War發布到tomcat或者jetty容器運行便可。
- 易於測試。不需要跨服務間聯調。
- 易於擴展。只需拷貝應用複本,多實例運行,並引入ngnix/ LVS之類load balance方案,做好負載均衡便可以了。
然而隨時間推移與業務需求的不斷加重,如果繼續延用單體架構開發,你的應用可能就會變得臃腫不堪,邏輯複雜,難以疏理。你的服務由原先的簡單清晰,變成了一頭難以馴服的怪獸。這時單體架構的就會帶你陷入一場災難:
- 代碼難以理解,導致修改困難。各種代碼邏輯盤根錯節,你漸漸發現任何敏捷開發的嘗試,都會失敗。特別是那些不注重設計與架構分層的,急於應付業務的開發者,加入各種定製邏輯,其實很可能是在為自己挖坑埋地雷,讓自己在後繼開發過程中瞻前顧後,寸步難移,加大項目風險。往往一次修改都可能會臨一次不小的重構。
- 服務啟動時間長。 隨著功能的增多與業務加重,越來越多數據載入、預處理工作在服務啟動的時間進行。這就會導致服務的啟動時長變長,甚至一次啟動要花費十幾分鐘。同樣在本地做測試時,每次測試會帶動繁重的載入處理操作,嚴重影響開發效率。
- 服務的穩定性被拉低。因為功能模塊逐漸增加、模塊問關聯邏輯愈加複雜,而任何模塊本身bug與它們交互時帶來的bug及出錯情況(例如內泄漏)都可能會把你整個服務搞掛。
- 多人協同開發困難,不便於團隊分工。單體架構服務往往更適合一個人去開發。正常情況下,單體架構服務在IDE中以一個project的形式存在,多人開發一個project時,每個人難以把整體掌握全局邏,存在風格衝突、引入技術重疊字、修改衝突等一系列問題。
- 硬體資源浪費。 往往在一個複雜的應用中,每個功能模塊對物理資源的需求是不同的,某個模塊可能是CPU密集型的,某個模塊是I/O密集型的,某個模塊將會造成越大的磁碟佔用等等。將么多模塊寫在一個服務中,為應對水桶效應,必然會為該服務提供全面滿足資源需求的伺服器。
- 引入新的技術框架、語言成為奢望。因為換用新的框架,會面臨極大的遷移成本,遷穩過程中故障概率也較高。而不做遷移的話,應用採用的技術棧越來越陳舊,難以跟上外界變化。
微服務 (Microservices Architecture)
為解決上述單體架構下的各種問題,微服務架構應運而生。與其構建一個臃腫龐大、難以馴服的怪獸,還不如及早將服務拆分。微服務的核心思想便是服務拆分與解耦,降低複雜性。微服務強調將功能合理拆解,儘可能保證每個服務的功能單一,按照單一責任原則(Single Responsibility Principle)明確角色。 將各個服務做輕,從而做到靈活、可復用,亦可根據各個服務自身資源需求,單獨布署,單獨作橫向擴展。
微服務的好處在於:- 每個微服務更小更輕。每個微服務的功能角色更清晰,代碼更易於閱讀與理解。就算人員變動,代碼交接,也不會有太大的困難。當然由於服務變輕,各個服務的啟動時間變得更短,單模塊測試與開發的效率得到有效提升。
- 每個微服務獨立布署,可以根據資源特點與實際需求,各自優化或做橫向擴展。不同的服務的特點不同,為cpu密集的服務分配更多的cpu資源,為I/O密集型的服務分配更多的I/O資源,為負載壓力較大的服務生成更多的實例. 如果結合使用Docker、mesos等技術,可以將實例的資源佔用從伺服器級別整機降到可動態分配的容器級別。
- 微服務的架構更適合團隊分工。按我們以往經驗,對於成熟的開發人員而言,一個服務歸於一個特定的開發人員,是比較合理的,避免了太多的溝通成本與開發修改衝突。微服務架構對單體服務完成拆分後,自然可以根據每個團隊成員不同的技能方向分配服務開發。甚至讓技術架構與技術團隊的組織架構相互貼近吻合,確保技術架構的穩定的同時,也提供團隊之間的良好合作方式。
- 允許在不同服務上嘗試使用不同的技術棧。由於每個服務較輕,所以對單個服務的技術框架的遷移成本並不大,也可以快速地嘗試試驗新的技術方案。如此,保證整體服務的技術水準與時俱進,不斷提升。
- 架構分層、具備服務級別的復用能力。經過合理的介面設計與功能劃分,很多基礎模塊不再專用的,而是成為一種可復用的通用服務。而對架構的分層,還可以做到不同級別的服務復用。
微服務不是萬能的,更不是適用於所有場景的。在對微服務的嘗試過程中,會發現某些場景下濫用或者錯誤設計下,也可能帶你陷入災難。
- 首先,微服務必然會帶為你帶來一些附加工作量與挑戰。與單體架構服務all in one 思路不同,隨著服務的拆分,服務開始形成多角色並各自獨立布署,這時自然需要提供可靠服務間通信機制。而為了讓服務能夠完成自治,具備服務註冊與發現功能的中間件開始引入。同時在微服務架構下如何保證不同服務間數據一致,也是我們在開發的常會遇到的挑戰。也就是說,微服務架構在為你的系統提供更強大的擴展潛力的同時,依賴的外部組件也越來越多,系統複雜度增大。
- 調試、bug定位鏈路拉長。隨著服務的拆分細化、服務分層層次增加,一次完整的請求,會涉及貫穿多個服務。開發者為了定位某個bug,經常會打開多個服務,同時查看後台日誌;而為了重現某個現個bug,需要在測試環境下同時把相關服務環境準備好。總的來說,在微服務下,如果你想追蹤某個完整的請求,你要花費的時間往往遠大於單體架構服務的,這跟你的服務拆分細度與分層層數有關。
- 維護成本加大。 這也是我們在微服務實踐中深切體會到的。一般而言,團隊中的每個開發人員負責2~3服務(不包含沒有變更需求的穩定服務)的開發與維護,已經相對飽合了。但如果拆分的過細,逐漸會發現,開發者更多的時間不是用於新功能的開發,而是服務的維護。大部份公司的對應用的部署,至少是區分線上測試和線上生產環境。而每一次的變動,就可會涉及服務的線下布署、測試、驗證、上線操作。當服務數量較少的時候還好,但當服務數量多達近十個時,你會發現開發的大多部時間都是在服務維護工作上,抽不出身來搞其他開發。特別在大公司,需要配合pe,對應用做各種安全升級,環境升級等操作,雖然是一次性,但服務數量一多,可能一周之內一個開發一大部份時間都耗在上面了。這就是一種的忙得要死,周報卻不知道咋寫的處境。
- 微服務相對單體服務有更高的系統架構能力要求。這裡就需要對每個角色有清晰的定義,從而可以合理地設計服務間庫介面,在介面的層面確定每個服務的能力範圍,如果介面太過通用,那你的服務的功能角色會變得不可控,如果介面設得過死板,服務會顯得不夠靈活。數據結構與二方庫的設計,也在一定程度上決定了,哪些數據是對哪些服務可見。服務分層設計,是對服務的復用能力的保障。
- 上線風險。服務一多,上線就會變得麻煩。到正式上線之時,你很可能需要制定一個合理的上線方案。往往上線一個新功能,修改了多個服務,為保證上線期間的服務可用,需要按照指定順序依次上線。 公共二方庫的改寫也要特別慎重,猶其是對二方庫中多個服務共享的數據結構的修改,很可能一次修改,某個服務上線後,結果發現其他服務不可用了。
DevOps與微服務
根據上述結論,你會發現微服務架構並不完美,其代價也不小,特別是運維成本。正是DevOps相關技術的發展,使得這種代價變得越來越小。DevOps的核心思想是開發測試與運維部署一體化,作為一種可選平台,使得測試、布暑、運維等環節的工作自動化。對於微服務,可以設想有一種PaaS雲服務,可以為應用開發者提種一種易用的方式用來微服務的布署與管理,包含服務的持續集成、服務升級、資源動態分配等功能。
從實現角度,舉一個我了解的例子。此處的DevOps方案可看作三層架構。首先以容器技術為底層,這裡有以Docker為代表的容器技術,做資源定義與隔離;第二層可採用Mesos,將硬體資源池化,作為統一的資源調度層; 第三層,是利用Kubernetes對微服務集群的管理。Kubernetes是一套開源容器編排系統,可以運行在mesos之上,它提供了一系列基本的功能,如應用的自動化部署,維護和擴展等。而Kubernetes與Mesos集成後,也可以實現Worker節點的自動擴展,所有Worker節點都是自動創建的,不需要用戶手動干預。總結
微服務現在已經十分火熱。但經上述比較分析可知,在業務邏輯簡單,資源有限的情況下並不一定適合微服務架構架,至少不應將服務拆分過細。而在應用微服務之後,必將引入更多的系統複雜性與維護工作,DevOps相關技術的引入可以減少不少這樣的工作量與護成本。
20170129首發於http://3dobe.com 微服務介紹與實踐總結 - Dobe
推薦閱讀:
※微服務落地第三課-Spring Cloud Config Client搭建
※「演講復盤」技術沙龍(滬江網4月) - 我所遇見的微服務演進這十年