微服務化改造

天府雲創發表於2018-01-12

1 寫在前面

背景

技術圈流行一句話,凡脫離業務談架構的,都是耍流氓。作為微服務改造系列的第一篇部落格,首先介紹一下實施這次技術改造的背景。

第一,我所在公司(簡稱XR)的後臺服務採用的主技術棧是Scala,雖然開發效率很高,但也帶來一系列的副作用。1.由於Scala語言強大的表達能力和豐富的函式式特性,很容易寫出俗稱“義大利麵條”式的程式碼,一個類檔案動輒上千行,程式碼的可讀性非常差,導致可維護性也很差。2.編譯Scala原始碼時首先需要將Scala原始碼轉換成Java原始碼然後再通過JVM進行編譯,加上隱式型別的存在進一步拖慢了編譯期間的型別推導,Scala的編譯速度比Java足足慢了一個數量級,這個差異在程式碼量少的時候還不明顯,但隨著程式碼量的上升,就成了團隊的一個nightmare,試想本地全量編譯一次需要10+分鐘。3.Scala小眾語言的標籤決定了Scala程式設計師的稀缺性,晦澀難懂的官方文件拔高了學習曲線,後果就是高昂的招聘成本和漫長的培養時間。以上這些副作用不但抵消了先期開發效率上的優勢,而且使得對新需求的響應能力越來越慢,技術負債也越壘越高。

第二,歷經2年多的產品迭代,整個後臺服務專案越來越龐大,已經成為一個典型意義上的單體應用(也就是Martin Fowler常說的monolithic application):1.各個業務模組犬牙交錯,重複程式碼隨處可見,補丁程式碼越打越多。2.任何一個改動都需要一次全量釋出,哪怕是修改一句文案。

第三,與微服務化改造同時進行的是容器化改造,如果不對上述單體應用進行拆分,很多容器化帶來的好處就會被削弱,甚至毫無意義,比如提高資源利用率(CPU型應用和記憶體型應用搭配部署),異構應用的環境隔離能力等。

限制

谷歌前研發總監Tiger曾經說過,一個系統的演化一般會經歷三個階段,首先是under-engineer,然後是over-engineer,最後才是right-engineer。考慮到參與此次微服務改造的人員有限(一人主導,多人配合),同時也是團隊第一次嘗試做這類系統性的改造,最後我們決定採取一條比較實用的改良式路線:
  1. 最小化對已有應用的侵入性
  2. 偏好主流的微服務框架
  3. 只做必要的微服務治理

第一條定下了此次改造的基調,降低了方案無法落地的風險,確保了專案的整體可行性。第二條讓我們站在巨人的肩膀上,不重複造輪子,聚焦在問題本身,而不是工具。第三條縮減專案範圍,避免過度工程,以戰養兵,不打無用之仗。

2 微服務簡介

3個關鍵詞

有關微服務的定義,最權威的版本莫屬微服務之父Martin Fowler在microservices一文中所述:

In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. -- James Lewis and Martin Fowler
注意其中有3個關鍵詞,small,independently deployable和automated deployment。small對應的就是微服務的微,很多初次接觸微服務的同學對微的理解往往會停留在實現層面,以為程式碼少就是微,但實際上,這裡的微更多的是體現在邏輯層面。微服務的一個重要設計原則是share as little as possible,什麼意思呢?就是說每個微服務應該設計成邊界清晰不重疊,資料獨享不共享,也就是我們常說的高內聚、低耦合。保證了small,才能做到independently deployable。而實現automated deployment的關鍵是DevOps文化,可參見Fowler另一篇談DevOps的文章。

需要提醒的是,隨著業務複雜度的上升,一個微服務可能需要拆分為更多更細粒度的微服務,比方說,一開始只是一個簡單的訂單服務,後面逐步拆分出清算,支付,結算,對賬等其他服務。

康威定律

與單體應用拆分為微服務的過程類似,隨著公司規模的不斷擴大,一個組織勢必會分化出多個更小的組織。根據康威定律,組織結構決定系統結構,因此,從這個層面來說,微服務也是一種必然。

康威定律(Conway’s Law):“Any organization that design a system (defined broadly) will produce a design whose structure is a copy of the organization’s communication structure. - Melvin Conway, 1968
01.png

取捨

從本質上來看,相對單體應用,微服務是以犧牲強一致性、提高部署複雜性為代價,換取更徹底的分散式特性,比如異構性和強隔離性。對應CAP理論,就是用Consistency換Partition。異構性比較容易理解,通過定義統一的API規範(一般採用REST風格),每個微服務團隊可以根據各自的能力矩陣選用最適合的技術棧,而不是所有人必須使用相同的技術棧。強隔離性指的是,對於一個典型的單體應用,隔離性最高只能體現到模組級別,由於共享同一個程式碼倉庫,模組的邊界往往比較模糊,需要人為定義很多規範來保證良好的隔離性,但無論如何強調,稍一疏忽,就會產生“越界”行為,時間愈長,維護隔離性的成本愈高。而到了微服務階段,自帶應用級別的隔離性,“越界”的成本大大提升,無需任何規範,架構本身就保證了隔離性。

另一方面,由於採用了分散式架構,微服務無法再簡單的通過資料庫事務來保證強一致性,而是通過訊息中介軟體或者某種事務補償機制來保證最終一致性,比如微信朋友圈的點贊,淘寶訂單的物流狀態。其次,在微服務階段,隨著應用數量的激增,一次釋出往往涉及多個應用,加上異構性帶來的部署方式的多樣性,對團隊的運維水平尤其是自動化水平提出了更高的要求,運維和開發的邊界進一步模糊。
02.png

領域知識

除了組織架構和技術取捨,領域知識是另一個非常重要的決策因素。對於不熟悉的業務領域,很難第一次就把各個微服務的邊界和介面定義正確,一旦開始開發,重構成本就會非常可觀。反過來說,當對領域知識有了一定的積累,再重構一個單體應用就會容易的多。

總結

綜上所述,雖然微服務看上去很美,但在決定採用微服務架構之前,不僅要仔細考量團隊的技術水平(包括知識結構,理論深度,經驗積累和技術氛圍),還應綜合考慮專案的時間範圍,領域知識的熟悉程度,以及所在組織的規模架構。除非這些前提條件都滿足,否則單體應用是更適合的選擇,就像Fowler建議的那樣。
03.png

3 微服務化總覽

04.png

上圖是XR微服務化第一階段的整體架構圖。可以看到,一些支撐微服務的必要元件都已包含其中:
  • 服務註冊中心:所有服務註冊到Consul叢集,整合Nginx實現負載均衡,使用Hystrix實現簡單的服務降級和熔斷機制
  • CI/CD:利用Jenkins Pipeline實現不停機發布
  • 日誌平臺:擴充套件ELK加上Redis快取
  • 配置中心:使用自研的Matrix系統,最小化對已有應用的侵入性,保證異構系統的相容性
  • 授權中心:基於Spring Security OAuth,同時支援SSO
  • 訊息中心:選用RabbitMQ作為訊息中介軟體
  • 監控平臺:利用Consul API獲取服務狀態,通過Zookeeper觸發告警

在微服務化系列的後續文章中,我會針對服務註冊、配置中心、授權中心和服務監控分別展開介紹實施過程中的一些細節和經驗。敬請期待。

參考

相關文章