工商銀行基於Dubbo構建金融微服務架構的實踐-服務發現篇

導讀:Dubbo 做爲分佈式微服務框架,衆多公司在實踐中基於 Dubbo 進行分佈式系統架構。重啓開源後,咱們不只看到 Dubbo 3.0 最新的 Roadmap 發佈,並且還看到阿里在自身電商開始推動 Dubbo 和內部 HSF 的融合,並在 雙11 上開始使用 Dubbo 3.0。本文是工商銀行基於 Dubbo 構建金融微服務架構的分享,主要講述了服務發現的應對策略和成果,後續將發佈工行大規模服務監控治理的實踐,以及從企業角度怎麼去對 Dubbo 二次開發等內容。歡迎關注。

背景及概覽

工行傳統的業務系統通常都是基於 JEE 的單體架構,面對金融業務線上化及多樣化的發展趨勢,傳統架構已經沒法知足業務的需求。所以從 2014 年開始,工行選擇了一個業務系統作服務化的嘗試,並驗證、評估、對比了當時的幾個分佈式服務框架,最終選擇了相對完善、而且國內已經有較多公司落地使用的 Dubbo。與此同時,工行還對 Dubbo 作了企業定製,幫助這個業務系統完成了服務化的落地,上線以後也收到了很是好的效果。緩存

2015 年,工行開始擴大服務架構的落地範圍,一方面幫助傳統業務系統進行架構轉型,另外一方面也逐漸沉澱了相似中臺的超大規模服務羣組,支撐業務系統快速服務的組合和複用。隨着經驗積累,工行也不斷對 Dubbo 進行迭代優化和企業定製,同時圍繞服務也逐步打造了完善的服務生態體系。網絡

2019 年,工行的微服務體系也正式升級爲工行開放平臺核心銀行系統的關鍵能力之一,助力工行 IT 架構實現真正的分佈式轉型。session

工行的微服務體系組成以下圖所示:架構

  • 基礎設施方面,不論是業務系統的服務節點,仍是微服務平臺自身的工做節點,都已部署在工行的雲平臺。
  • 服務註冊發現方面,除了常規的服務註冊中心外,還配合部署了元數據中心,用於實現服務的按節點註冊發現。
  • 服務配置方面,經過外部的分佈式配置中心,以實現各種動態參數的統一管理和下發。
  • 服務監控方面,實現對服務各種運行指標的統一採集和存儲,並與企業的監控平臺對接。
  • 服務跟蹤方面,主要是用於實時跟蹤服務的總體鏈路,幫助業務系統快速定位故障點,並準確評估故障的影響範圍。
  • 服務網關是爲了知足傳統業務系統訪問服務需求,在 Dubbo 服務訂閱及 RPC 能力之上,實現了新服務、新版本的自動發現、自動訂閱和協議轉換能力(HTTP 協議轉 RPC 協議),實現 7×24 小時不間斷運行。
  • 服務治理平臺,提供給運維人員和開發測試人員一個一站式的管理、監控、查詢的平臺,提高平常服務治理的效率。

最大的挑戰

通過工行多年的落地實踐,本文共總結了如下兩方面的最大挑戰:併發

  • 性能容量方面,目前線上服務數(即 Dubbo 概念中的服務接口數),已超 2 萬,每一個註冊中心上的提供者條目數(即每一個服務的全部提供者累計),已超 70 萬。根據評估,將來須要能支撐 10 萬級別的服務數,以及每一個註冊中心 500 萬級的提供者條目數。
  • 高可用方面,工行的目標是:微服務平臺任何節點故障都不能影響線上交易。銀行的業務系統 7×24 小時運行,即便在版本投產時間窗內,各業務系統的投產時間也是相互錯開的,平臺自身節點要作升級,如何避免對線上交易帶來影響,特別是註冊中心的自身的版本更新。

本文將先從服務發現方面,來分享一下工行的應對策略及成效。app

服務發現難點和優化

1. 入門框架

在 Dubbo 中,服務的註冊訂閱及調用是一個標準範式,服務的提供者初始化時註冊服務,服務消費者初始化時訂閱服務並獲取全量提供者列表。而運行期間,服務提供者發生變化時,服務消費者可獲取最新的提供者列表。消費者與提供者之間點對點 RPC 調用,調用過程不經註冊中心。運維

在註冊中心的選擇上,工行在 2014 年就選擇了 Zookeeper。Zookeeper 在業界的各種場景下有大規模的應用,而且支持集羣化部署,節點間數據一致性經過 CP 模式保證。分佈式

在 Zookeeper 內部,Dubbo 會按服務創建不一樣的節點,每一個服務節點下又有 providers、consumers、configurations 及 routers 四個字節點:ide

  • providers 臨時節點:記錄該服務提供者清單。提供方下線子節點就自動刪除,經過 Zookeeper 的 watch 機制,消費者能夠第一時間知道提供者清單發生了變化。
  • consumers 臨時節點:記錄消費者的清單,主要用於服務治理時查詢消費者。
  • configurations 持久節點:主要保存服務治理時須要調整的服務參數。
  • routers:子節點爲持久節點,主要用於配置服務的動態路由策略。

在線上生產環境,Zookeeper 分數據中心部署了多個集羣,每一個集羣配置了 5 個選舉節點,若干個 Observer 節點。Observer 節點是 Zookeeper3.3.3 版本引入的一個新的節點類型,它不參與選舉,只聽取表決結果,其餘能力則和 Follower 節點相同。Observer 節點有如下幾方面的好處:

  • 分流網絡壓力:隨着服務節點的增多,若是客戶端都鏈接選舉節點,對選舉節點來講須要消耗大量的 CPU 去處理網絡鏈接和請求。可是選舉節點又沒法任意水平擴容,選舉節點越多,事務投票過程就越長,對高併發寫性能是不利的。
  • 下降跨城跨 DC 的註冊訂閱流量:當有 100 個消費者須要跨城訂閱同一個服務,Observer 能夠統一處理這部分跨城網絡流量,避免對城際間的網絡帶寬帶來壓力。
  • 客戶端隔離:能夠將幾個 Observer 節點專門分配給某個重點應用使用,保障其網絡流量隔離。

2. 問題分析

工行根據這幾年線上 Zookeeper 的使用心酸血淚史,總結了 Zookeeper 在做爲服務註冊中心時面臨的問題:

  • 隨着服務數量以及服務提供者節點的增長,服務推送的數據量會呈爆炸式增加。舉個例子,一個服務有 100 個提供者,當提供者啓動的時候,由於 Zookeeper 的 CP 特性,每上線一個提供者,消費者都會收到事件通知,並從 Zookeeper 來讀取這個服務的當前所有提供者的列表,而後刷新本地緩存。這個場景下,理論上每一個消費者總共收到了 100 次事件通知,並從 Zookeeper 讀取了 100 次服務提供者列表,1+2+3+...+100,總計 5050 條提供者數據。這在業務系統投產高峯期問題尤其突出,容易致使 Zookeeper 集羣的網絡被打滿,形成服務訂閱效率極其低下,並進一步影響了服務註冊的性能。
  • 隨着寫在 Zookeeper 上節點數量的增多,Zookeeper 的 snapshot 文件也不斷變大,每次 snapshot 寫入磁盤,會出現一次磁盤 IO 衝高。投產高峯期,由於事務量大,寫 snapshot 文件的頻率也很是高,這對基礎設施帶來了較大的風險。同時 snapshot 文件越大,也預示着 Zookeeper 節點故障後恢復的時間越長。
  • 當 Zookeeper 選舉節點發生從新選舉後,Observer 節點都要重新的 Leader 節點同步全量事務,這個階段若是耗時過長,就很容易致使鏈接在 Observer 節點上的客戶端 session 超時,使對應 providers 節點下的臨時節點所有被刪除,即從註冊中心角度看,這些服務都下線了,消費者端則出現無提供方的異常報錯。緊接着,這些提供者會從新鏈接 Zookeeper 並從新註冊服務,這種短期內大批量服務的註冊翻轉現象,每每帶來更爲嚴重的服務註冊推送的性能問題。

綜上,能夠得出的結論是:整體上 Zookeeper 做爲註冊中心仍是比較稱職的,但在更大規模服務量場景下,須要進一步優化。

3. 優化方案

工行最主要的優化措施包括下面這幾方面:訂閱延遲更新、註冊中心採起 multiple 模式、升級到按節點註冊等。

1)訂閱延遲更新

工行對 Zookeeper 客戶端組件 zkclient 作了優化,把消費者收到事件通知後獲取提供者列表作了一個小的延時。

當 zkclient 收到 childchange 一次性的事件後,installWatch() 經過 EventThread 去恢復對節點的監聽,同時又使用 getChildren() 去讀取節點下的所有子節點獲取提供者列表,並刷新本地服務提供者緩存。這就是前面說的「5050 條數據」問題的根源。

工行在 zkclient 收到 childchange() 的事件後,作了個等待延遲,再讓 installWatch() 去作它原來該作的事情。這個等待過程當中若是服務提供者發生變化,則不產生 childchange 事件。

有人會問,這是否是違背了 zookeeper 的 CP 模型呢,其實並非,zookeeper 服務端的數據是強一致的,消費者也收到了事件通知,只是延後去讀取提供者清單,後面執行 getChildren() 時,讀取到的已是 zookeeper 上的最新數據,因此是沒有問題的。

內部壓測結果顯示,服務提供者大規模上線時,優化前,每一個消費者收到了總計 422 萬個提供者節點的數據量,而延遲 1 秒處理後,這個數據量則變成了 26 萬,childchange 事件次數和網絡流量都變成了原來的 5% 左右,作完這個優化,就能從容應對投產高峯期大量服務的上下線。

2)Multiple 模式

工行採納並優化改造了 Dubbo 新版本中 registry-multiple 的 SPI 實現,用於優化多註冊中心場景下的服務訂閱。

Dubbo 中服務消費者原有處理邏輯是這樣:當存在多個註冊中心的時候,消費者按註冊中心對應的 invoker 緩存去篩選提供方,第一個註冊中心對應的緩存中若是沒找到,則去找第二個註冊中心對應的緩存。若是此時第一個註冊中心出現可用性問題,推送給消費者的數據有缺失,甚至爲空,就會影響消費者的這個篩選過程,如出現無提供方的異常、調用負載不均衡等。

而 multiple 註冊中心是把多個註冊中心推送的數據合併後再更新緩存,因此即便單個註冊中心故障,推送了數據不完整或者爲空,只要有其餘任意一個註冊中心的數據使完整的,就不會影響最後合併的數據。

而且,multiple 註冊中心機制也用於異構的註冊中心場景,出現問題能夠隨時把註冊中心下線,這個過程對服務節點的服務調用則徹底透明,比較適合灰度試點或者應急切換。

更進一步,還有額外的收益,消費者端 Reference 對象是比較佔用 JVM 內存,經過 multiple 註冊中心模式,能夠幫消費者端節省一半的 invoker 對象開銷,所以,很是推薦多個註冊中心場景採用 multiple 模式。

3)按節點註冊

工行反向移植 Dubbo2.7 及 Dubbo3.0 的服務發現邏輯,使用「按節點註冊」的服務註冊-發現模型。這裏即配置中心、元數據中心、註冊中心這個鐵三角組合:

  • 配置中心:主要用來存儲節點級別的動態參數,以及服務的原來寫在 Zookeeper 上的 configurations 和 routers 這些持久節點的數據。
  • 元數據中心:存儲節點元數據,也就是每一個服務節點名稱(也就是 applicaiton-name)和其提供的服務的映射關係,以及每一個服務的類定義信息,好比每一個方法的輸入輸出參數信息。
  • 註冊中心:此時註冊中心則只須要存儲服務提供者節點名稱和實際 ip 端口的關係。

這個模型的變化,對於消費者的服務調用則沒有任何影響。消費者端根據元數據中心上「服務節點名稱」與「服務」的關係,以及註冊中心「服務節點名稱」與實際 ip 端口的關係,生成兼容存量模式的服務提供方 invoker 緩存。

壓測結果顯示,按節點註冊可讓註冊中心上的數據量變成原來的 1.68%,這對量就對線上的 Zookeeper 來講毫無壓力,10 萬級別的服務量和 10 萬級別的節點量都可以輕鬆支撐。

將來的規劃

將來,工行也但願能有機會走出去,深度參與到社區中,把自身在 Dubbo、Zookeeper 服務端、zkclient 上的好的 feature 貢獻出來,好比除了上面的優化點外,工行還在 Dubbo 上作了 RPC 結果的精細化識別,PAAS 的適配,同端口多協議、自隔離等能力,還在 Zookeeper 上增長了註冊熔斷機制,同時正在研究 Observer 的同步機制避免數據全量同步帶來的一系列問題。

另外,從微服務的發展看,Mesh 已是目前的熱點之一。工行的痛點主要在服務 SDK 版本升級上,Istio 不爭氣,MCP 生死未卜,如何能讓存量 Dubbo 服務平滑過渡到 MESH 架構,目前已經有初步的方案,但還有很是多的技術難關須要克服。

歡迎 Dubbo 有實踐的同窗們一塊兒來探討大規模場景下的問題和心得,共同把 Dubbo 的企業落地作的更好!

做者:張遠征

 

原文連接

本文爲阿里雲原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索