講師:劉 超 / 網易雲 解決方案總架構師

編輯:小君君

編者按:如今,微服務模型已經逐漸成為軟體解決方案中的翹楚。它不僅可以通過定製化單個組件解決部分功能性問題,也可以通過組合不同的組件解決總體架構問題。憑藉這種多元化的解決方案,微服務架構已經成為高並發架構的首選方案。本文將基於網易雲在微服務上的研究與實操,向大家分享在不同場景下落地微服務的實踐經驗。

在網易內部,無論是考拉、雲音樂、嚴選,還是雲課堂,它們都有涉及微服務的實踐。我們的微服務框架除了完成一些基本事項(比如熔斷、限流、降級、彈性伸縮等),也開發了很多符合行業特性的定製化產品。這是因為我們發現傳統行業與互聯網行業的經營模式有著很大的不同。

微服務平臺總覽

整個微服務平臺的架構如上圖所示,這裡我先對這個架構圖做一個總體的介紹 (有下劃線的部分是整個架構中比較有特點的地方) 。圖的左上方是一個 CICD 平臺,該平臺可以實現從代碼檢出到自動部署的整個流程。左下方是自動化測試平臺,我們認為在整個 CICD 的過程中,測試是最關鍵的一部分。

架構圖的最下方是一個多集羣基礎設施架構(容器平臺)。這個容器平臺基於 Kubernetes,自帶滾動更新、彈性伸縮等功能。其中 OVS 與 Ceph 是這裡比較有特點的兩個組件。在 OVS 優化方面,我們基於 OVS 可以實現對流表的靈活配置。同時,它也可以兼容 Calico。

應用管理層

架構圖中的應用層管理是比較重要的一部分,主要分為三大組件。第一個組件是 API 網關,解決流量接入問題。第二個組件是微服務框架(NSF,Netease Service Framework),用於服務之間的治理和調用(如熔斷、限流、降級等都是 NSF 可以做到的)。第三個組件是 APM(應用層的性能監控與管理),在服務數目較多的情況下,這是一個必不可少的組件。

但是整個架構情況很複雜,這張圖片並沒有完全展開。為什麼會如此複雜?因為作為一個互聯網高並發的架構,它需要考慮很多問題,在此我把它們總結為 12 個重點項

  • 微服務化的基石:持續集成;
  • 接入層的設計;
  • 無狀態化、容器化;
  • 服務拆分、服務發現、服務編排;
  • 資料庫,分散式資料庫,分散式事務;
  • 緩存;
  • 消息隊列與非同步化;
  • 熔斷限流降級;
  • 配置中心;
  • 日誌中心;
  • 全鏈路壓測。

所以架構師想要用一個產品把以上項目全部覆蓋還是比較困難的。但是不同客戶的關注點並不一樣,我們可以根據客戶的需求點加以設計。針對不同場景的解決方案,我將會在下文中分享。

微服務治理平臺

上圖是微服務治理平臺的總體架構。在進行服務發現和服務治理時,我們利用一個 Java 的 Jar 包,在 Java 程序啟動時通過位元組碼注入的方式,攔截流量做治理。對於 Service Mesh 場景,我們利用 Envoy。

服務治理的控制中心可以做熔斷、限流、降級、路由等事情。每一臺機器上都有一個 Data Stream 進程用來收集實時數據,這些數據會通過實時消息隊列發送到監控平臺上。

在圖中,我們可以看到一些統一監控的數據,比如交易數據。當這些線下數據需要被處理時,它們會被直接發送到 Kafka 中再傳遞到 Storm 中進行在線處理,然後通過 Hadoop 進入 DDB(分散式資料庫)中進行日誌的分析和收集。

不同場景下的應用實踐

某城商行

首先,我分享一個城商行場景下的實踐案例。當時,客戶想把他們的業務推廣到全國,但是他們銀行下的每個業務都是單體應用。由於並不存在大量用戶在線購買理財產品的場景,原來的系統能夠承載的用戶數量十分有限,他們就啟動了一個專項業務來做微服務化的拆分,並且計劃只用兩個月的時間完成這個項目。我們將該客戶的痛點概括為以下兩個方面:持續集成與容器化。

  • 持續集成

我們認為微服務化不應該是一個運動化的過程,應該有一個測試平臺和一些測試用例的覆蓋。這樣可以保證在不斷拆合過程中,系統的功能集合是不變的。在大多數情況下,我們通過界面滑鼠點擊的方式來完成測試,但是有時這種測試方式是不能覆蓋所有場景的,而 API 測試往往能更好地解決這種問題。

同時,在測試平臺中,客戶的選擇也更多樣化,可以是單介面測試,也可以是場景化測試。例如,網上購物會涉及購物車、下單、支付等多種場景組合。這些組合的場景可以形成一個執行集,我們可以指定程序在每天晚上做定時測試。客戶也可以不斷積累自己的測試場景組合,做回歸測試。

如果客戶的系統能保證無論怎麼拆合都可以每天進行定時測試,那麼在全部測試通過後,整個業務的功能就可以正常交付了。這樣也可以避免出現 bug 後找不到源頭的問題。同時,相較於界面點擊測試,定時測試的效果也要更好一些,當前端人員調用一個未經測試的 API 時,通過界面點擊測試的系統可能會掛掉,但是定時測試的系統就不會存在這種問題。

另外,針對銀行的諮詢服務業務,我們建議按照一個持續集成的實施方案進行。業務上進行代碼分支管理(有 master 分支和 develop 的分支),然後部署所有環節,除了線上部署之外,其它部署都通過代碼末支合併觸發事件來做。這種方式可以保證對基礎設施的任何改變都通過代碼來完成。比如,單個的應用環境部署利用 Dockerfile 來解決,多個應用之間的關係用服務編排來解決,配置文件有配置中心,所有的東西都通過代碼來進行。

  • 容器化

上圖是我們的容器化平臺。那麼他們為什麼要做容器化呢?因為他們的運維人員只有兩個。只有三四個系統的時候,這兩個人的工作量並不大。但是在兩個月後,這三四個系統將會被拆分成 20 多個系統,他們就無法應對如此巨大的工作體繫了。所以業務容器化勢在必行。當時我們的建議是將容器 Dockerfile 分配給開發人員。因為開發人員知道自己修改了什麼,同時也降低了運維人員的工作量。

某物流企業

這個客戶比較關注這幾個點:

  • 服務的拆分和服務發現;
  • 資料庫的橫向擴展;
  • 熔斷限流降級;
  • 全鏈路的壓測。

如今物流和電商兩個行業的整個業務週期十分相似。電商大促物流就大促,電商低流量物流也低流量。物流大促的時候就會接到好多單子,短時間內無法處理完。因而他們的業務也需要進行拆分發現。微服務框架能很好地支撐大促這件事情。

在數據方面,資料庫層如果使用傳統關係資料庫,它就不一定能支撐全部的業務流量,這時候就需要使用類似 DDB 的分散式資料庫來實現。所有電商使用的熔斷、限流、降級等這些措施,物流也一定需要。同時,客戶需要通過壓測來估計系統能夠承載的最大量。

  • API 網關負責流量接入

這個客戶比較關心 API 網關的接入情況。API 網關可以提供統一的認證、鑒權、API 監控、熔斷、限流、降級等功能。這裡大家需要注意一點,熔斷、限流、降級在 API 網關與註冊中心都會進行一次。

這個客戶也存在一些特殊需求。比如灰度發布和 A/B 測試,如上圖所示 99% 的流量會去左邊,1% 的流量去右面。這就和有線上 A 和線上 B 的情況形似,可針對全國不同地區的客戶進行不同處理。

另外一個相對比較有特點的功能是流量鏡像。這個功能在 API 網關裏,當一個流量從鏡像中出來就將它打到一個預發環境中,這個預發環境會將所有的東西都部署一遍。而這個流量並不是真實的流量,只是通過網關複製過來的。

並且我們可以在 API 網關中開發一個插件。這個插件可以在 RESTful 介面的 HTTP 頭裡加任何東西。這樣流量不僅能發到預發環境外,也可以發到壓測環境中,客戶的壓測環境也是需要這種鏡像流量的。

同時,在上線一個 API 時,客戶希望能夠定期維護、定期下線、定期上線。這時候就需要有一個維護開關。綜上所述 API 網關的配置尤為重要。

  • 文檔管理

文檔管理也是比較重要的一點。在物流企業中,不同業務團隊的數目比較多且相互之間需要溝通。我們可以這樣操作,在 API 網關上對文檔進行自動管理,使得文檔和運行時一致,自動生成 swagger 或者 markdown 文檔,再導入到 API 網關中。那麼用這個 API 的人只要打開文檔,就能知道介面如何調用,大大減少了相互之間的溝通成本。

  • 熔斷與容錯

大家都知道 SpringCloud 有熔斷、限流、降級的能力。但真正落地到企業中時,你就會發現,簡單的 SpringCloud 架構是無法滿足實際場下很多細節問題的解決需要的。例如使用 Dubbo 註冊介面,當一個進程有 10 個介面,10 個介面都會註冊上去,這樣的粒度太細,會給註冊中心造成很大的壓力。但是 SpringCloud 註冊的是實例,會導致 SpringCloud 的粒度太粗,這就要求我們要實現 SpringCloud 與 Dubbo 相結合。

結合後的框架既有服務又有類,也可以利用方法級別進行治理。SpringCloud 的默認錯誤是按 10 毫秒的錯誤率來進行熔斷。在真實場景中,這個粒度不一定符合客戶的業務場景,所以要靈活地配置每 M 毫秒 N 個請求百分之 P 的錯誤率,並且這個錯誤不僅僅是調用的錯誤,還有 RT 值,以及線程池。

  • 路由

路由中會有黑白名單的配置。在 API 網關上,會有一些黑白名單和許可權的控制,服務之間的調用本來是不應該存在這類控制的,因為服務之間是需要互信的。但是這個客戶的場景有所不同,有的介面會比較關鍵。比如支付介面是有調用許可權的,只有在固定網段或者在某幾個服務中才能調用。我們就需要對黑名單和白名單進行配置。這些需求也要在服務治理的中間框架中實現,而不是隻是網關。這也是一個相對傳統的企業特性,要實現對不同許可權比較細粒度的管理,原生的 SpringCloud 很難做到。

  • 負載均衡與參數分流

用 SpringCloud 或 Dubbo 做負載均衡的時候,僅僅利用 RoundRobin 演算法是不夠的。你需要針對 Cookie、Header 或者 Query String 的任何東西來匹配一個正則表達式去做一個比較細粒度的分流。比如說 A 用戶永遠訪問服務 A,VIP 用戶永遠連接某個服務,非 VIP 的永遠連接另一個服務。這時候就可以給 VIP 用戶提供更優先的服務與更多功能,參數分流也會比普通的負載均衡要細很多。

  • 測試環境管理

服務拆分後會有一件比較棘手的事情,就是拆分後的測試情況。例如,你原本有一個單體應用,A 組要測試,B 組要測試,C 組也要測試。每個組都搭建一個單獨的環境進行測試是沒有任何問題的,但是當拆成幾百個服務後,這件事就比較痛苦了。

每個測試小組不可能都去創建幾百個容器。我們就需要利用一個基準測試環境來對應代碼的 master 分支,然後讓 A 組開發一個 feature 修改其中的 5 個服務,B 組開發一個 feature 修改其中的 4 個服務。這樣 A 組只需要啟動 5 個服務,B 組只需要啟動 4 個服務。

然後我們再配置細流量分發規則,A 組的 5 個服務之間優先相互訪問,B 組的 4 個服務之間優先相互訪問。當要訪問的服務不在這 5 個之內時,流量可以去基準環境訪問。這樣每個組只要部署自己的差量服務就可以了。

  • 分散式資料庫

上圖是我們的一款成熟產品 DDB。在高並發場景下,如果連接的數量特別多,傳統關係資料庫是無法支持的。分散式資料庫 DDB 可以很好地解決這個問題。它可以非常好地做到橫向擴展,中間會有一個 Query Server 做分庫分表結果聚合。

某視頻監控企業

這個客戶比較關注一些企業級的特性。首先是知識庫,我們剛剛說到 API 網關可以管理 API。服務之間的相互調用,也要統一管理 API。微服務的互相調用十分複雜,不同微服務團隊之間溝通也比較繁瑣,所以我們就需要將文檔和運行保持一致。

客戶另外關注的兩個地方是認證鑒權和審計。傳統行業有自己的流程,必須認證了才能調用,所以我們提供了一種在每次註冊發現調用時都可以認證鑒權的功能。在審計方面,對於各種許可權,各種作用域(分平臺、租戶、項目)我們都要規劃得清清楚楚。

在 IT 資產和 IT 能力復用方面,客戶的系統是自己開發一部分,外包開發一部分。原來他們的開發方式是開發完之後,外包商將源代碼打成 ZIP 包交付。當系統上線後,客戶發現哪怕像換行、添加列表這種簡單修改都會是一件很困難的事情。因為當時交付的 ZIP 包是無法編譯與修改的。所以即使是一個很小的改動,都需要讓外包商重新開發一遍。而不同外包商的標準也不一樣,如果兩個有重合的功能是分發給不同外包商做的,它們有時也無法復用。

但是如果通過持續集成的流程,上述問題就能被很好地解決。客戶可以要求外包公司在 CICD 流程上將做好的程序跑起來。一旦跑起來,程序在自動編譯後就可以自動部署了。

這樣的方式為客戶提供了很大的便利。客戶將來想改任何一個東西,都可以在 Git 裡邊查看情況並進行修改,然後再次啟動流程,打出 Docker 鏡像。這種方式很好地解決了工作效率以及成本問題。客戶不需要進行二次開發,只需少許的修改就可以了。

另外,每家外包公司的開發模式都不一樣,如果使用微服務框架並配置一個腳手架工程(一個統一的模板),大家都按這個模板來寫代碼,代碼結構就可控多了。並且每個服務要和文檔一起註冊到註冊中心中,當登到註冊中心時,任何人都能看到新註冊上來的應用提供了哪些介面。之後如果要復用這些功能,就可以選擇直接調用這些介面,而不是重新造輪子。這樣很多外包公司給你開發的東西就可以沉澱下來進行復用。

某銀行

這個大型銀行客戶需要微服務架構是因為他們在服務拆完後,分散式事務出現了問題。分散式事務其實有幾種方式解決。其中的一種就是在 DDB 中提交分佈事務 XA。如果跨多個 DDB 中間件保證事務性,就需要使用 TCC 模型。我們的中間件 DTS 可以做這件事。同時,我們有個 TMC 中間件,含有非同步消息模型(可以用事務消息的方式來完成)。這裡我舉兩個場景來說明問題。

  • 場景一:下單即減優惠券、減庫存

下單是事務的發起方,優惠券和庫存是事務的參與方,分支事務需要用事務 ID 做冪等,幾方調用都需要同時並行。一旦程序出現錯誤,就會有一些定時任務去重試和回滾。如果分支事務不在,這時候會有一個超時機制,在某一個時間之內,無論是判斷成功和判斷失敗都不做響應。但是在一個設定的時間之外,如果它還沒給出應答,最後就會判斷失敗。這就是一個 TCC 的場景,TCC 適用於立即應答的場景,就像下單是沒有「下單中」這個概念的,下單只有「成功」與「失敗」,並且立刻反饋給商家。

  • 場景二:交易消息非同步

比如,在轉賬的時候,會有一個狀態叫「轉帳中」,一旦有中間狀態,就不是一個完全同步的事務,可能需要 5 分鐘的延遲。這種消息需要通過一定的機制,保證它能夠到達對方,如果不能到達就需要重試。這種方式被稱為事務消息隊列。

結語

經過以上的分享,大家可以看出微服務的建設是非常複雜的,涉及的點非常多,但是沒有必要面面俱到,大家可以根據自己所處的階段和業務需求,有選擇性地部署架構。架構師只有通過適當的選擇與成熟的設計,才能真正解決企業部署過程中的各種痛點。


推薦閱讀:
相關文章