架構

第五人格周年庆时间:同程旅游微服務最佳實踐

本文首發胖波聊架構界,微信公眾號:xiaobo2as

本文概要

  • 導言
  • 微服務拆分的四個維度
  • 微服務應該如何維護版本
  • 如何從單體架構平滑過渡到微服務
  • 結語

一、導言

同程微服務從立項到實施推廣已經走過了整整兩個年頭,從最初的簡單粗糙到今天的精細完善,接入服務數量也實現了從1到10,000+的增長。

微服務開發團隊和大家一起踩過了無數的坑,最終打造了今天的DSF2.0平臺?;毓伺攬蛹鍬?,現整理一些爬坑心得體驗供大家參考,也斗膽提出一些最佳實踐以拋磚引玉。

下文將從開發者角度對微服務如何拆分, 版本管理和單體到微服務過渡等方面給出一些建議,  供大家斟酌。

二、微服務拆分的四個維度

從單體架構到微服務,拆分粒度很難把握。理論方法莫衷一是,我們推薦快刀斬亂麻按照如下四個維度做拆分:

團隊組織結構

發布升級頻率

邏輯調用頻率

數據讀寫分離

1.  團隊組織結構

按照康威定律的說法,組織結構一定會反映到系統架構上,同程是樹形結構+底層網狀結構,那么服務之間一定是每個系統的架構呈明顯的樹狀,但是系統之間會有多重的服務互訪。

微服務設計要充分考慮哪些是自用(inner),外部訪問(outer)和混用(mix)服務,并盡可以能將其遷移對應的服務組里。

2.  發布升級頻率

新老項目由于處于生命周期的不同階段,修改和發布頻率會有很大差別。應該盡量將處于生命周期中不同階段的接口分割,避免高頻更新服務和低頻更新服務捆綁,避免向穩定運行的服務組添加新業務接口,而是應該考慮在新的服務組中實現。

3.  調用頻率

服務組中的不同服務調用頻率會有巨大差別,而高頻調用肯定會占據更多的資源,會出現個別接口耗盡資源導致同組接口一起失敗(資源競爭),需要對高頻訪問的服務設置定制的運行策略,如分配更多的CPU核心數和內存, 調整部署使其盡可能靠近數據源等策略,但是如果將所有服務宿主都做成高配,會造成巨大的資源浪費事實上也沒有必要,所以應該將高低頻訪問的服務分割以使其能為獲得更好的性能和可靠性做針對性優化。

4.  數據讀寫分離

上一維度其實已經涵蓋了讀寫分離的一部分,但是為了突出讀寫分離的必要性,這里單獨列出。一般數據操作模式分為CQRS和CRUD兩種模式,各有優缺點。 

從操作是否對數據本身造成影響來看,可以粗略的分為讀寫兩類 , 一般來說寫操作的頻率會大大低于讀操作,寫操作經?;嵊懈細竦娜現な諶ɑ?,一般為內部(inner)調用。這些和讀操作都有巨大差異性, 因此建議流量較大或較為核心的服務應該做讀寫分離,分拆為兩個服務組發布。

最后分享一個粒度控制的小技巧,大多數情況出現在系統里的每個名詞都會在存儲層面擁有一席之地,對應一個獨立的數據表或庫,所以系統里出現的名詞都可能是一個潛在的微服務。 

三、微服務應該如何維護版本

微服務治理中維護一個有序,直觀的版本會給系統開發過程和服務依賴管理帶來巨大的便利,反之無版本或混亂的版本升級策略迷惑開發和設計人員并帶來意想不到的依賴問題。良好的微服務治理應該包含一整套完整的版本升級策略,根據我們長期的爬坑實踐我們推薦如下版本策略:

1.  使用標準語義化版本

具體參見 語義化版本 2.0.0  。使用標準的語義化版本能使大家保證對版本有統一的理解,應盡量避免自行定義版本語義。DSF 版本推薦使用SemVer 約定,略有不同的是DSF推薦四位版本號(1.2.3.4),前兩位作為主版本(1.2), SemVer版本一般為三位(x.y.z 對應:主版本號.次版本號.修訂號)。

2.  面向契約設計

當一個團隊選擇微服務作為服務化實施平臺時必須明確微服務化有一個較高的門檻,需要團隊自身已經是一個較為成熟運作體系,例如有實施前有完善的架構設計,團隊成員有明確的職責劃分,團隊成員對服務內聚和服務耦合有明確的認知。

上述的這些方面都會促成一個結果: 使設計開發的服務接口最終具有良好的抽象并體現出規劃性,最終能夠在服務實施前就能交付有良好兼容性的服務契約。實踐中體現為一個版本迭代新增、修改、刪除的任何部分都是經過慎重思考并體現在服務契約里,實際開發不輕易的修改和增添服務接口。 

3.  并行開發中版本的維護

微服務化對開發體系的一個重大影響就是開發實踐的并行化,微服務使開發者從單體架構的調用叢林擺脫出來,使開發者能夠把視野聚焦到調用鏈中其中一環上而不用過多關心上下游的具體實現。

需要付出的成本就是如何避免重復實現以及代碼Merge時的更高頻的沖突問題,有一個良好的版本管理習慣能夠解決絕大部分的Merge沖突問題。

我們推薦在面向契約設計的基礎上進一步延伸,通過團隊內溝通確定不對外暴露的核心部分由誰來負責并約定在特定的版本實現,而負責使用該核心??櫚鈉淥⒄咴詬冒姹舊系菰靄姹?。 

被其他組件依賴較且可能頻繁改動的內核代碼獨占一個特定的版本區間(例如:v1.2.3.0~1.2.3.10作為核心??櫚畝勒及姹?,依賴該組件的??楸匭氪笥趘1.2.3.10),能很好隔離并行開發帶來的版本沖突問題。

因為引用核心組件的上層實現彼此沒有太多聯系,總是能夠很好處理Merge帶來的沖突問題。

4.  版本的兼容性

能根據版本號判斷服務是否向后兼容是服務依賴管理的一個很重要的方面,大多數時候做一個使服務不在向后兼容的決定是很難的事,但是不斷的向后兼容的結果往往是服務體量不可控制的增長和系統復雜度的非線性上升。

開發者需要慎重思考并在合適的時間做出服務不再向后兼容的決定,良好的版本策略能將服務是否向后兼容明確的表達出,顯式的告訴調用方這是一個不兼容的升級更新, 請務必確保仔細閱讀的新的契約文檔并做了足夠的測試。

對DSF來說不兼容升級是很醒目的,只需觀察服務組的大版本號(版本號的前兩位,如v1.2.3.4,大版本號為1.2)是否增加,任何服務契約修改都被認為是不兼容的升級,包括刪除接口、修改接口名稱/參數等,都必須升級大版本號, 而修改小版本號(版本號的后兩位,如v1.2.3.4,小版本號為3.4)則代表兼容性升級,如新增了服務接口,代碼邏輯優化和Bug fix但是未修改服務契約。

四、如何從單體架構平滑過渡到微服務

一旦決定在開發實踐引入微服務架構,如何將積累下來的龐大的巨無霸系統潤物細無聲的的過渡到微服務架構將是一個巨大的挑戰。

推倒重來激進革命路線是要不得的,架構師們最想通過微服務化取代的部分往往是公司的主要盈利核心,改造難度不亞于飛行中更換引擎。從業界公開的信息來看還沒有哪家做到了完美升級, 更多的可能無外乎兩種:

第一種改造后茍延殘喘,研發疲于奔命; 

另一種則是改造中就直接休克。  

因此為使微服務能順利的應用,架構師從不應該幻想一蹴而就,無數次的碰壁后我們給出如下的爬坑建議:

1.  培訓先行

工作技術人都很善于把面臨的問題變成技術問題,然后在自己最擅長的領域里取解決掉。這就造成一個悖論:能用技術解決的問題就不是問題,真正的問題在受限的情景下僅靠技術是解決不了的,實施微服務最大的攔路虎也不是技術本身。

從我們的實踐來看,最大的問題不是如何做好微服務,而是就微服務應該是什么達成一個一致的看法。

正所謂林子大了什么鳥都有,對于微服務100個人可能就有100種理解,這個不是說我們都是用dubbo或者都是用spring boot就能解決的。

我們的推薦做法就是實施前通過多數人參與的大討論和培訓,讓多數人能達成一致的認識,微服務是什么,微服務不是什么? 運用在哪些場景是適合,應用在哪些場景里是不適合的? 結果不要跑的太偏就行, 和編碼規范中命名規范一樣,使用那種命名方法不重要,重要的是大家都使用同一種命名方法。

2.  絞殺者模式

絞殺者模式指對于無法通過修繕者模式改進的系統通過在系統外重新構建新功能的方式逐步剝離重構,對功能服務逐個絞殺。

好處是不影響原來的環境,一旦條件成熟就能快速切換。

不好的方面則是可能需要有一段時間同時維護兩套系統,付出額外的開發維護成本。

3.  監獄模式

還有一種同程內部稱之為監獄模式的做法,允許一些短期無力改動的系統通過監獄窗口(MicroProxy)接入微服務平臺并委托Proxy將其暴露成微服務, 單體架構往往擁有龐大的服務接口梳理, 往往需要開多個監獄窗口。

每個監獄窗口都會被包裝分割成微服務,條件成熟了能很方便的替換成原生微服務,稱為刑滿釋放。

五、結語

市面上微服務的理論和討論鋪天蓋地,其中不乏侃侃而談的大塊文章,深入閱讀確常常發現大都是新瓶裝舊酒或者拼湊篇幅之作。特點是在務虛處濃墨重彩,高談理論,于實踐處則一筆帶過,仔細探究則實無一物。

所以如果發現有些技術書籍晦澀難懂,滿篇的高大上,讀完頭腦發脹,確無所進益可能不是您水平不夠,更可能是作者故弄玄虛。最近讀書有感,書于此,博君一曬。 

我還沒有學會寫個人說明!

梆梆安全:做以結果為導向的安全服務商

上一篇

etcd 在超大規模數據場景下的性能優化

下一篇

你也可能喜歡

同程旅游微服務最佳實踐

長按儲存圖像,分享給朋友

ITPUB 每周精要將以郵件的形式發放至您的郵箱


微信掃一掃

微信掃一掃