微服務化的道與術
微服務的目標是提高響應能力,降低複雜度,讓一切去中心化是微服務的最高宗旨。
背景
隨著研發團隊的專案工程的增加、程式碼量的膨脹、團隊人員的增長,傳統的單體架構的弊端越來越凸顯,嚴重影響了業務的快速創新和敏捷交付。隨行付在2015年底為了解決傳統單體架構面臨的挑戰,先後經歷了單體架構、系統模組拆分以及到現在的微服務化。
微服務架構並非銀彈,它的實施過程中會面臨很多的陷阱和挑戰、幾乎影響到整個軟體開發的生命週期,稍有不慎,會導致整個微服務改造的效果大打折扣,甚至失敗。
本公眾號接下來的一段時間會協同隨行付架構部、隨行付技術委員會等技術團隊,結合隨行付的一些實際經驗,論證微服務架構實施的道與術。
微服務原因
為什麼要做微服務化?可以從以下三個方面看為什麼搞微服務。
- 分而治之:減低複雜性
- 分而用之:提高可重用性
- 分而做之:提高開發效率
可以用變化的成本來衡量架構的好壞。而架構的目的是管理複雜性、易變性和不確定性,以確保系統在進化過程中,架構的變化不會對應用產生不必要的負面影響。保證業務和研發效率的敏捷、保證易變應用頻繁響應市場需求而中臺部分的影響儘可能的小。
10幾年前,一提到架構,大多數人都會認為,架構=效能+高可用。隨著現在的技術不斷更新(Docker、人工智慧、區塊鏈等技術)、各類開源軟體異軍突起、DevOps理念深得人心、敏捷開發成為主流開發模式等等,效能和高可用已經不再是那麼棘手的問題。應用如何可持續發展?產品如何能快速上線/快速迭代?可維護性、可擴充套件性、成本,開始慢慢成為很多架構師的關注點。而微服務架構的根本目的就是降低複雜性。
微服務前提
業務拆分
採納微服務架構首當其衝的問題就是根本沒有一個確定的、良好定義的演算法可以完成服務的拆分工作。像軟體開發本身,服務的拆分和定義更像是一門藝術。更糟糕的是,如果你對系統的服務拆分出現了偏差,你很有可能會構建出一個「分散式的單體應用」,一個包含了緊耦合服務的必須部署在一起的系統。這將會把單體架構和微服務架構兩者的弊端集於一身。
自動測試
微服務一個明顯的表象就是隨著服務的增多,如果繼續沿用傳統的測試模式就會遇到瓶頸,為了保證高效的迭代,儘量做到測試自動化。通過自動化讓測試也可以「一處編寫,處處執行」、讓迴歸測試日常化。
自動運維
當網際網路發展到今天,業務要保持對市場變化的一個高效響應,自動化運維就是提升交付速度的一個重要環節。微服務拆分之後,每個服務都可以獨立部署,不再是固定的時間段去升級,人肉運維已經成了阻礙進步的絆腳石了。
多維度監控
硬體環境、服務狀態、系統健康度、服務呼叫情況、異常的實時告警以及生產事故的事先預警等等。監控在實施微服務過程中至關重要。
道篇
微服務架構原則
技術棧統一
一定要使用成熟技術,充分考慮新技術帶來的價效比。所謂成熟不僅僅是指有良好的社群活躍度、穩定性、節約開發成本、提高開發效率。更多的是指在隨行付的技術普適度,說白了就是有多少人會,出了問題有多少人能hold住。
資料最終一致性
權衡好哪些服務是最終一致、哪些必須是強一致。而強一致的保障機制是什麼?框架層和應用層相互互補來共同保障資料一致性。
服務無狀態
對於無狀態服務,首先說一下什麼是狀態。如果一個數據需要被多個服務共享,才能完成一筆交易,那麼這個資料被稱為狀態。進而依賴這個「狀態」資料的服務被稱為有狀態服務,反之稱為無狀態服務。那麼這個無狀態服務原則並不是說在微服務架構裡就不允許存在狀態,表達的真實意思是要把有狀態的業務服務改變為無狀態的計算類服務,那麼狀態資料也就相應的遷移到對應的「有狀態資料服務」中。
場景說明:例如我們以前在本地記憶體中建立的資料快取、Session快取,到現在的微服務架構中就應該把這些資料遷移到分散式快取中儲存,讓業務服務變成一個無狀態的節點。遷移後,就可以做到按需動態伸縮,微服務應用在執行時動態增刪節點,就不再需要考慮快取資料如何同步的問題。
無狀態通訊,我們推薦使用Restful通訊風格,因為他有很多好處:
- 無狀態協議HTTP,具備先天優勢,擴充套件能力很強。
- JSON報文序列化,輕量簡單,人與機器均可讀,學習成本低,搜尋引擎友好。
- 語言無關,各大熱門語言都提供成熟的Restful API框架,相對其他的一些RPC框架生態更完善。
AKF拆分原則
AKF擴充套件立方體,《架構即未來》一書中提出的可擴充套件模型。理論上按照這三個擴充套件模式,可以將一個單體系統,進行無限擴充套件。
X 軸 :是水平復制。比如講單體系統多執行幾個例項,做個叢集加負載均衡的模式。
Z 軸 :是資料分割槽,比如按照使用者請求的地區進行資料分割槽,北京、上海、四川等多建幾個叢集。
Y 軸 :是微服務的拆分模式,就是基於不同的業務進行拆分。
舉例:比如打車APP,一個叢集撐不住時,分了多個叢集,後來使用者激增還是不夠用。分析後發現打車APP上主要使用者是乘客和車主,就將打車應用拆成了三個乘客服務、車主服務、支付服務。三個服務的業務特點各不相同,獨立維護,各自都可以再次按需擴充套件。
服務拆分原則
單一職責
根據業務能力拆分。瞭解過面向物件的人應該都聽說過「單一職責原則」,即每一個類都擁有一個職責。比如一個搬磚類,它既可以蓋房子,也可以用來拍人,這時搬磚就擁有了兩個職責,所以我們應該把類拆分為兩個。微服務也是一個道理,我們應該做到一個服務是用來做一件事情的。
鬆耦合、高內聚
緊密關聯的事物應該放在一起,每個服務是針對一個單一職責的業務能力的封裝,專注做好一件事情。(每次只有一個更改它的理由)。
DDD
領域驅動設計。我們怎麼按領域來劃分服務呢?對,我們可以按業務進行拆分,比如財務、訂單、倉庫等等。這樣我們的團隊也可以拆分開來分別負責不同的服務,這樣不僅專案清晰了,就連公司內部的組織結構權責分配也變得清晰了。
剛才從橫向來看我們可以按業務領域拆分,縱向的呢?我們可以按層次進行拆分,比如最底層的資料層、基礎設施層以及與業務無關的推送、郵件、簡訊等等。我們還可以按安全性、效能等需要特別關照的以及通用的功能進行抽離沉澱。
掌握了領域驅動設計不僅遵守了高內聚、鬆耦合還符合了單一職責原則,那還不趕緊拆起來?
演進式拆分
避免過早拆分。過早的劃分服務,可能發展一段時間之後,服務的邊界會和之前有所不同,導致很多跨服務的修改,代價越來越高,最終又變成了單塊系統。所以一開始我們應該按照較粗的粒度進行劃分,而是否拆分為更小的服務,應該由團隊組織結構決定,如果團隊對拆分後服務的維護成本更大了,那就應該放棄拆分更小的粒度。
服務開發原則
微服務的開發會面臨依賴滯後的問題。在單體架構時,大家需要什麼,往往喜歡自己寫什麼,這其實是沒有太嚴重的依賴問題。但是到了微服務時代,微服務是一個團隊或者一個小組提供的,這個時候一定沒有辦法在某一個時刻同時把所有的服務都提供出來,「需求實現滯後」是必然存在的。
例如:A要做一個商戶黑名單校驗,依賴服務提供者B。而B有其他更重要的任務,導致該服務的開發優先順序排的比較低,無法滿足A的交付時間點。A會面臨要麼等待,要麼自己實現一個服務。
一個好的實踐策略就是介面先行,基於契約,語言中立。服務提供者和消費者解耦,並行開發,提升產能。無論有多少個服務,首先需要把介面識別和定義出來,然後雙方基於介面進行契約驅動開發,利用Mock服務提供者和消費者,互相解耦,並行開發,實現依賴解耦。
採用契約驅動開發,如果需求不穩定或者經常變化,就會面臨一個介面契約頻繁變更的問題。對於服務提供者,不能因為擔心介面變更而遲遲不對外提供介面,對於消費者要擁抱變更,而不是抱怨和抵觸。要解決這個問題,一種比較好的實踐就是管理 + 技術雙管齊下:
-
程式碼通過Sonar掃描(隨行付Sonar中定製208條規則)
-
有80%以上的單元測試複雜度
-
允許介面變更,但是對變更的頻度要做嚴格管控
-
提供全線上的API文件服務(例如Swagger UI),將離線的API文件轉成全線上、互動式的API文件服務
-
API變更的主動通知機制,要讓所有消費該API的消費者能夠及時感知到API的變更
-
契約驅動測試,用於對相容性做迴歸測試
術篇
隨行付微服務平臺是以DevOps為理念,基於Spring Boot、Spring Cloud、React、React Native、容器技術、人工智慧等,面向微服務應用的PaaS平臺。實現基礎設施雲化、應用架構現代化和開發流程敏捷化。
平臺核心及功能介紹
Spring Cloud生態時序圖
如圖上所示,我們圍繞Spring Boot、Spring Cloud做了很多功能的擴充套件,讓Spring生態在隨行付能生長出更多的解決實際問題的「果實」,同樣並沒有盲目的造輪子。因文章篇幅,技術篇更多內容會在系列文章中著重介紹,會從各個中介軟體入手介紹隨行付金融