技術圈流行一句話,凡脫離業務談架構的,都是耍流氓。做爲微服務改造系列的第一篇博客,首先介紹一下實施此次技術改造的背景。html
第一,我所在公司(簡稱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。考慮到參與這次微服務改造的人員有限(一人主導,多人配合),同時也是團隊第一次嘗試作這類系統性的改造,最後咱們決定採起一條比較實用的改良式路線:微信
最小化對已有應用的侵入性架構
偏好主流的微服務框架app
只作必要的微服務治理負載均衡
第一條定下了這次改造的基調,下降了方案沒法落地的風險,確保了項目的總體可行性。第二條讓咱們站在巨人的肩膀上,不重複造輪子,聚焦在問題自己,而不是工具。第三條縮減項目範圍,避免過分工程,以戰養兵,不打無用之仗。框架
有關微服務的定義,最權威的版本莫屬微服務之父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
從本質上來看,相對單體應用,微服務是以犧牲強一致性、提升部署複雜性爲代價,換取更完全的分佈式特性,好比異構性和強隔離性。對應CAP理論,就是用Consistency換Partition。異構性比較容易理解,經過定義統一的API規範(通常採用REST風格),每一個微服務團隊能夠根據各自的能力矩陣選用最適合的技術棧,而不是全部人必須使用相同的技術棧。強隔離性指的是,對於一個典型的單體應用,隔離性最高只能體現到模塊級別,因爲共享同一個代碼倉庫,模塊的邊界每每比較模糊,須要人爲定義不少規範來保證良好的隔離性,但不管如何強調,稍一疏忽,就會產生「越界」行爲,時間愈長,維護隔離性的成本愈高。而到了微服務階段,自帶應用級別的隔離性,「越界」的成本大大提高,無需任何規範,架構自己就保證了隔離性。
另外一方面,因爲採用了分佈式架構,微服務沒法再簡單的經過數據庫事務來保證強一致性,而是經過消息中間件或者某種事務補償機制來保證最終一致性,好比微信朋友圈的點贊,淘寶訂單的物流狀態。其次,在微服務階段,隨着應用數量的激增,一次發佈每每涉及多個應用,加上異構性帶來的部署方式的多樣性,對團隊的運維水平尤爲是自動化水平提出了更高的要求,運維和開發的邊界進一步模糊。
除了組織架構和技術取捨,領域知識是另外一個很是重要的決策因素。對於不熟悉的業務領域,很難第一次就把各個微服務的邊界和接口定義正確,一旦開始開發,重構成本就會很是可觀。反過來講,當對領域知識有了必定的積累,再重構一個單體應用就會容易的多。
綜上所述,雖然微服務看上去很美,但在決定採用微服務架構以前,不只要仔細考量團隊的技術水平(包括知識結構,理論深度,經驗積累和技術氛圍),還應綜合考慮項目的時間範圍,領域知識的熟悉程度,以及所在組織的規模架構。除非這些前提條件都知足,不然單體應用是更適合的選擇,就像Fowler建議的那樣。
上圖是XR微服務化第一階段的總體架構圖。能夠看到,一些支撐微服務的必要組件都已包含其中:
服務註冊中心:全部服務註冊到Consul集羣,集成Nginx實現負載均衡,使用Hystrix實現簡單的服務降級和熔斷機制
CI/CD:利用Jenkins Pipeline實現不停機發布
日誌平臺:擴展ELK加上Redis緩存
配置中心:使用自研的Matrix系統,最小化對已有應用的侵入性,保證異構系統的兼容性
受權中心:基於Spring Security OAuth,同時支持SSO
消息中心:選用RabbitMQ做爲消息中間件
監控平臺:利用Consul API獲取服務狀態,經過Zookeeper觸發告警
在微服務化系列的後續文章中,我會針對服務註冊、配置中心、受權中心和服務監控分別展開介紹實施過程當中的一些細節和經驗。敬請期待。