七個關鍵問題的應對策略
1.如何合理拆分微服務
當一個系統服務化的時候,就會面臨一個問題:如何進行服務的劃分?怎麼確定服務的粒度?有沒有一些可以參考的業界通用規則?
實際上服務劃分的本質是對系統進行架構設計,服務的劃分粒度沒有絕對的過大或過小之說,不同階段的側重點和思考的角度也不盡相同。
創業初期的團隊,過分的追求微服務,爲了“微”而微,反而會導致業務邏輯過於分散,技術架構過於複雜,團隊基礎設施搭建能力弱,進而導致忽略了快速迭代交付產品的重要性,可能錯失了市場機會。所以,關於服務的劃分不是對錯的選擇題,而是需要綜合考慮各種外界的因素,所作出的一個最適合的決策,這些外界因素通常包括業務、技術債、開發、運維、測試這
五個方面:
-
業務所處領域的市場性質:對市場比較敏感的項目,創業初期粒度應該儘量劃分的粗一些,先提供充足的彈藥去佔領市場,然後再去考慮對系統進行重構和優化;
-
與原有系統之間的關係:對於歷史遺留的系統,需要做好新舊系統之間的邊界劃分,避免過於激進、過大幅度的改造,應該採取小步快跑的方式,有節奏的對老系統進行服務化改造;
-
開發團隊的成熟度:服務化帶來的技術風險應該提前進行評估,要考慮團隊的承受度,用合適的人做適合的事,考慮團隊需要有包括敏捷,包括 Devops,包括基礎設施,運維和測試的自動化等基礎能力;
-
基礎設施的搭建能力:在進行細粒度的服務劃分時,要考慮團隊是否有足夠的能力來支撐大量服務實例運行的運維複雜度,是否可以做好分佈式的日誌追蹤和服務的監控;
-
測試團隊的測試執行效率:過於細粒度的服務劃分,如果測試團隊不能通過自動化測試、自動迴歸、壓力測試、極限測試等手段來提高測試執行效率,必然會帶來測試工作量的大幅度上升,進而影響整個項目的上線週期;
如果沒有特別強烈的大規模水平擴展需求,拆分就沒有必要,反而把問題搞複雜了。進行服務化的拆分時,通常會先按照業務子系統先進行一次劃分,根據業務邏輯和數據的關係劃分爲若干個子系統,然後再考慮子系統內部是否可以再次進行拆分。至於拆分的基本原則,我推薦:
-
高內聚低耦合:這個已經提了很多了,簡單說一下,就是要把強相關的部分,總是會一起改動的部分,聚合到一起,相關性不大的部分拆開,可以參考 DDD 中的一些辦法。
-
粗粒度服務:服務的粒度要稍微的抽象和粗粒度一些,因爲服務是基於業務場景的抽象和設計,不能做成是直接把數據庫的增刪改查暴露出來成接口和方法,而是應該隱藏這些細節,考慮清楚從業務和客戶角度來看,哪些步驟和過程,是必須封裝起來的,細節隱藏掉,然後對外提供的就是粗粒度的服務,而在單體系統的時候,我們可以直接調用這些細節,無需過多考慮。
2.遺留系統應該如何改造
對舊系統進行改造,可以分爲幾個步驟:拆分前準備階段,設計拆分改造方案,實施拆分計劃。下面是我的一些經驗之談。
1)拆分之前先梳理系統關係和接口
其中準備階段主要是梳理清楚了依賴關係和接口,就可以思考如何來拆,第一刀切在哪兒裏,即能達到快速把一個複雜單體系統變成兩個更小系統的目標,又能對系統的現有業務影響最小。要儘量避免構建出一個分佈式的單體應用,一個包含了一大堆互相之間緊耦合的服務,卻又必須部署在一起的所謂分佈式系統。沒分析清楚就強行拆,可能就一不小心剪斷了大動脈,立馬搞出來一個 A 類大故障,後患無窮。
2)不同階段拆分要點不同,每個階段的關注點要聚焦
拆分本身可以分成三個階段,核心業務和非業務部分的拆分、核心業務的調整設計、核心業務內部的拆分。
第一階段將核心業務瘦身,把非核心的部分切開,減少需要處理的系統大小;
第二階段。重新按照微服務設計核心業務部分;
第三階段把核心業務部分重構設計落地。
拆分的方式也有三個:代碼拆分、部署拆分、數據拆分。
代碼直接體現了依賴關係,拆完就可以單獨打包部署。但是有時候,我們可以通過控制一些提供服務的開關,使用同一份代碼和打包的程序,部署多組進程,每組提供不同的服務,這就是部署拆分,比如同一份代碼,我們部署了 3 組機器,A 組 5 臺提供訂單服務,B 組 2 臺提供用戶服務,C 組 2 臺提供任務調度處理任務。數據拆分最複雜,涉及到代碼的調整,SQL 和事務的分析和重構,數據庫表的拆分甚至數據遷移,數據結構的調整和數據遷移則一般意味着需要停機維護。這三個方式,可以在適當的條件下選擇先做哪個操作合適。
另外,每個階段需要聚焦到一兩個具體的目標,否則目標太多反而很難把一件事兒做通透。例如某個系統的微服務拆分,制定瞭如下的幾個目標:
-
性能指標(吞吐和延遲):核心交易吞吐提升一倍以上(TPS:1000->10000),A 業務延遲降低一半(Latency:250ms->125ms),B 業務延遲降低一半(Latency:70ms->35ms)。
-
穩定性指標(可用性,故障恢復時間):可用性>=99.99%,A 類故障恢復時間<=15 分鐘,季度次數<=1 次。
-
質量指標:編寫完善的產品需求文檔、設計文檔、部署運維文檔,核心交易部分代碼 90%以上單測覆蓋率和 100%的自動化測試用例和場景覆蓋,實現可持續的性能測試基準環境和長期持續性能優化機制。
-
擴展性指標:完成代碼、部署、運行時和數據多個維度的合理拆分,對於核心系統重構後的各塊業務和交易模塊、以及對應的各個數據存儲,都可以隨時通過增加機器資源實現伸縮擴展。
-
可維護性指標:建立全面完善的監控指標、特別是全鏈路的實時性能指標數據,覆蓋所有關鍵業務和狀態,縮短監控報警響應處置時間,配合運維團隊實現容量規劃和管理,出現問題時可以在一分鐘內拉起系統或者回滾到上一個可用版本(啓動時間<=1 分鐘)。
-
易用性指標,通過重構實現新的 API 接口既合理又簡單,極大的滿足各個層面用戶的使用和需要,客戶滿意度持續上升。
-
業務支持指標:對於新的業務需求功能開發,在保障質量的前提下,開發效率提升一倍,開發資源和週期降低一半。
-
核心人員指標:培養 10 名以上熟悉核心交易業務和新系統的一線技術人員,形成結構合理的核心研發人才梯隊。
結果可想而知了,目前太多了,反而沒有目標。最後第一階段只選擇了穩定性作爲最重要的指標,先穩住系統,然後再在後面的階段裏選擇其他指標,逐步實現各個目標。
3)快速迭代,找到突破口,持續產出
大家都知道,敏捷開發之所以流行,就是因爲小步快跑,快速迭代,實現對業務變化和新需求的第一時間響應,這對快速發展變化的外部市場,以及 KPI 壓力非常大的業務部門非常重要。研發團隊在系統改造過程也可以通過快速的階段性產出,來證明團隊的技術能力和推進水平,增進互相的背靠背信任關係,爲長期的順暢合作打下堅實基礎。這方面,很多研發團隊都想試圖憋大招,搞個大項目,反而慢慢失去各個利益方的耐心,最終把合作關係搞僵,吃了大虧。
4)大膽假設,小心求證,穩步上線
凡事不破不立,拆分改造過程,我們每一次改動的地方,可能有多個不同的方案和路徑,具體選擇哪一個最合適,這需要我們放開思路,大膽假設,充分吸收各方面的意見和想法,然後小心謹慎的去測試,甚至在線上做驗證,保障萬無一失後,最後上線。
5)保障質量,不斷重構和改善現有設計和代碼
所有的事物都有產生,發展,衰退和消亡的過程。長期來看,軟件系統的代碼質量肯定是會一直下降的,就像是人的身體健康,到了一定的程度,就會難以爲繼,需要重構或者重做。而不斷的重構,改善現有的設計集合代碼,就像是一直在保養身體,可以減緩衰老,保證健康,增加壽命。
6)取得領導和業務方的支持,過程和決策透明化
拆分改造看起來,沒有給系統帶來明確的可見收益,比如沒有明顯改進了用戶體驗,也沒有給系統新增了一個業務功能,但是卻涉及到多方參與,付出勞動,這就必然會帶來很大的阻力,怎麼辦呢?
還是從《管理的常識》一書裏,我看到了一個很有道理的話:”如果無法推動問題背後的人解決問題,那說明對問題挖掘的還不夠深“。現代化的工作教會我們,雙贏/多贏是協作的唯一辦法,也是可以持續的辦法。
搞清楚怎麼才能推動各個合作方的支持,怎麼才能讓領導同意,如果我們現在提的意見,他們不同意,那麼他們關心的點是什麼,怎麼把他們關心的點,納入到這個工作範圍裏來,從而實現大家可以達成一致來合作。同時需要注意的是,信息一定要透明,決策要公開,讓大家都直接參與到這個過程,從而明確目標,一致前行。
總結成 48 字箴言的“微服務拆分核心價值觀”:
-
功能剝離、數據解耦
-
自然演進、逐步拆分
-
小步快跑、快速迭代
-
灰度發佈、謹慎試錯
-
提質量線、還技術債
-
各方一致,過程透明
理想中的系統拆分改造效果(實際上一般最後都雞飛狗跳):