同程旅遊微服務最佳實踐

技術瑣話發表於2019-05-20

同程旅遊微服務最佳實踐


本文首發胖波聊架構界,微信公眾號: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作為核心模組的獨佔版本,依賴該元件的模組必須大於v1.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將其暴露成微服務, 單體架構往往擁有龐大的服務介面梳理, 往往需要開多個監獄視窗。

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

同程旅遊微服務最佳實踐


五、結語


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

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

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31562044/viewspace-2644971/,如需轉載,請註明出處,否則將追究法律責任。

相關文章