螞蟻金服開源服務註冊中心 SOFARegistry | SOFA 開源一週年獻禮

SOFAStackgit

Scalable Open Financial Architecture Stack 是螞蟻金服自主研發的金融級分佈式架構,包含了構建金融級雲原生架構所需的各個組件,是在金融場景裏錘鍊出來的最佳實踐。github

本文根據 SOFA Meetup#1 北京站 現場分享整理,完整的分享 PPT 獲取方式見文章底部。算法


SOFAStack 開源一週年,繼續補充開源大圖

2018 年 4 月, 螞蟻金服宣佈開源 SOFAStack 金融級分佈式架構。這一年的時間,感謝社區的信任和支持,目前已經累積超過一萬的 Star 數目,超過 30 家企業用戶。數據庫

2019 年 3 月 24 日,SOFA 在北京舉辦了首場 Meetup,咱們有幸見到了關心SOFA 的朋友們。後端

這次,咱們宣佈開源螞蟻金服註冊中心 SOFARegistry 做爲一週年的禮物之一,本文爲根據現場分享整理的詳細介紹。緩存

SOFARegistry 是螞蟻金服開源的具備承載海量服務註冊和訂閱能力的、高可用的服務註冊中心,最先源自於淘寶的第一版 ConfigServer,在支付寶/螞蟻金服的業務發展驅動下,近十年間已經演進至第五代。服務器

GitHub 地址:github.com/alipay/sofa…數據結構

概念

註冊中心在微服務架構中位置

服務發現,並不是新鮮名詞,在早期的 SOA 框架和如今主流的微服務框架中,每一個服務實例都須要對外提供服務,同時也須要依賴外部服務。如何找到依賴的服務(即服務定位),最初咱們思考了不少方式,好比直接在 Consumer 上配置所依賴的具體的服務地址列表,或者使用 LVS、F5 以及 DNS(域名指向全部後端服務的 IP)等負載均衡。架構

可是以上方式都有明顯的缺點,好比沒法動態感知服務提供方節點變動的狀況,另外基於負載均衡的話還須要考慮它的瓶頸問題。因此須要藉助第三方的組件,即服務註冊中心來提供服務註冊和訂閱服務,在服務提供方服務信息發生變化、或者節點上下線時,能夠動態更新消費方的服務地址列表信息,最終解耦服務調用方和服務提供方。負載均衡

image.png

能力

服務註冊中心的主要能力:

  • 服務註冊
  • 服務訂閱

演進

螞蟻金服的服務註冊中心,經歷了 5 代技術架構演進,才最終造成了現在足以支撐螞蟻海量服務註冊訂閱的,具備高可用、高擴展性和高時效性的架構。

數據結構

SOFARegistry 的存儲模型比較簡單,主要基於 KV 存儲兩類數據,一類是訂閱關係,體現爲多個訂閱方關心的 Topic(或服務鍵值)和他們的監聽器列表,另外一類是同一個 Topic(或服務鍵值)的發佈者列表。基於觀察者模式,在服務提供方發生變化時(好比服務提供方的節點上下線),會從訂閱關係中尋找相應的訂閱者,最終推送最新的服務列表給訂閱者。

image.png

存儲擴展

主備模式

  • 既然服務註冊中心最主要能力之一是存儲,那麼就要思考:怎麼存?存哪兒?存了會不會丟?
  • 怎麼存,主要是由存什麼數據來決定的,因爲 SOFARegistry 所存儲的數據結構比較簡單( KV),由於並無基於關係數據庫;另外因爲服務發現對變動推送的時效性要求高,但並無很高的持久化要求(數據能夠從服務提供方恢復),因此最終咱們決定本身實現存儲能力。
  • SOFARegistry 的存儲節點,最初是主備模式。

image.png

強一致集羣

隨着螞蟻的服務數據量不斷增加,咱們將存儲改成集羣方式,每一個存儲節點的數據是同樣的,每一次寫入都保證全部節點寫入成功後纔算成功。這種模式的特色是每臺服務器都存儲了全量的服務數據,在當時數據規模比較小的狀況下,尚可接受。

image.png

這樣的部署結構有兩個問題:

  • 首先,根據 CAP 原理,在分區容忍性(P)的前提下,爲了保持強一致(C),必然犧牲高可用(A)爲代價,好比 Zookeeper 是 CP 系統,它在內部選舉期間是沒法對外提供服務的,另外因爲須要保證 C(順序一致性),寫的效率會有所犧牲。
  • 其次,每一個節點都存儲全量的服務數據,隨着業務的發展就有很大的瓶頸問題。

數據分片

若是要實現容量可無限擴展,須要把全部數據按照必定維度進行拆分,並存儲到不一樣節點,固然還須要儘量地保證數據存儲的均勻分佈。咱們很天然地想到能夠進行 Hash 取餘,但簡單的取餘算法在節點數增減時會影響全局數據的分佈,因此最終採用了一致性 Hash 算法(這個算法在業界不少場景已經被大量使用,具體再也不進行介紹)。

image.png

每一個服務數據,通過一致性 Hash 算法計算後會存儲到某個具體的 Data 上,總體造成環形的結構。理論上基於一致性 Hash 對數據進行分片,集羣能夠根據數據量進行無限地擴展。

內部分層

鏈接承載

咱們知道單機的 TCP 鏈接數是有限制的,業務應用不斷的增多,爲了不單機鏈接數過多,咱們須要將存儲節點與業務應用數量成正比地擴容,而咱們實際上但願存儲節點的數量只跟數據量成正比。因此咱們選擇從存儲節點上把承載鏈接職責的能力獨立抽離出來成爲新的一個角色,稱之爲 Session 節點,Session 節點負責承載來自業務應用的鏈接。這麼一來,SOFARegistry 就由單個存儲角色被分爲了 Session 和 Data 兩個角色,Session 承載鏈接,Data 承載數據,而且理論上 Session 和 Data 都支持無限擴展。

image.png

如圖,客戶端直接和 Session 層創建鏈接,每一個客戶端只選擇鏈接其中一個 Session 節點,全部本來直接到達 Data層的鏈接被收斂到 Session 層。Session 層只進行數據透傳,不存儲數據。客戶端隨機鏈接一臺 Session 節點,當遇到 Session 不可用時從新選擇新的 Session 節點進行重連便可。

讀寫分離

分離出 Session 這一層負責承載鏈接,引發一個新的問題:數據到最終存儲節點 Data 的路徑變長了,整個集羣結構也變的複雜了,怎麼辦呢?

咱們知道,服務註冊中心的一個主要職責是將服務數據推送到客戶端,推送須要依賴訂閱關係,而這個訂閱關係目前是存儲到 Data 節點上。在 Data 上存儲訂閱關係,可是 Client 並無直接和 Data 鏈接,那必需要在 Session 上保存映射後才肯定推送目標,這樣的映射關係佔據了大量存儲,而且還會隨 Session 節點變化進行大量變動,會引發不少不一致問題。

所以,咱們後來決定,把訂閱關係信息(Sub)直接存儲在 Session 上,而且經過這個關係 Session 直接承擔把數據變化推送給客戶端的職責。而對於服務的發佈信息(Pub)仍是經過 Session 直接透傳最終在 Data 存儲節點上進行匯聚,即同一個服務 ID 的數據來自於不一樣的客戶端和不一樣的 Session 最終在 Data 的一個節點存儲。

image.png

這樣劃分了 Sub 和 Pub 數據以後,經過訂閱關係(Sub)進行推送的過程就有點相似於對服務數據讀取的過程,服務發佈進行存儲的過程有點相似數據寫的過程。數據讀取的過程,若是有訂閱關係就能夠肯定推送目標,遷移訂閱關係數據到 Session,不會影響整個集羣服務數據的狀態,而且 Client 節點鏈接新的 Session 時,也會回放全部訂閱關係,Session 就能夠無狀態的無限擴展。

其實這個讀寫集羣分離的概念,在 Eureka2.0 的設計文檔上也有所體現,一般讀取的需求比寫入的需求要大不少,因此讀集羣用於支撐大量訂閱讀請求,寫集羣重點負責存儲。

image.png

高可用

數據回放

數據備份,採用逐級緩存數據回放模式,Client 在本地內存裏緩存着須要訂閱和發佈的服務數據,在鏈接上 Session 後會回放訂閱和發佈數據給 Session,最終再發布到 Data。

另外一方面,Session 存儲着客戶端發佈的全部 Pub 數據,按期經過數據比對保持和 Data 一致性。

image.png

多副本

上述提到的數據回放能力,保證了數據從客戶端最終能恢復到存儲層(Data)。可是存儲層(Data)自身也須要保證數據的高可用,由於咱們對存儲層(Data)還作了數據多副本的備份機制。以下圖:

圖片1.png

當有 Data 節點縮容、宕機發生時,備份節點能夠當即經過備份數據生效成爲主節點,對外提供服務,而且把相應的備份數據再按照新列表計算備份給新的節點 E。

圖片2.png

當有 Data 節點擴容時,新增節點進入初始化狀態,期間禁止新數據寫入,對於讀取請求會轉發到後續可用的 Data 節點獲取數據。在其餘節點的備份數據按照新節點信息同步完成後,新擴容的 Data 節點狀態變成 Working,開始對外提供服務。

圖片2.png

數據同步

數據備份、以及內部數據的傳遞,主要經過操做日誌同步方式。

持有數據一方的 Data 發起變動通知,須要同步的 Client 進行版本對比,在判斷出數據須要更新時,將拉取最新的數據操做日誌。

操做日誌存儲採用堆棧方式,獲取日誌是經過當前版本號在堆棧內所處位置,把全部版本以後的操做日誌同步過來執行。

image.png

元數據管理

上述全部數據複製和數據同步都須要經過一致性 Hash 計算,這個計算最基本的輸入條件是當前集羣的全部 Data節點列表信息。因此如何讓集羣的每一個節點能感知集羣其餘節點的狀態,成爲接下來須要解決的問題。

最初,咱們直接將「Data 地址列表信息」 配置在每一個節點上,但這樣不具體動態性,因此又改成經過 DRM(螞蟻內部的動態配置中心)配置,可是這樣仍須要人爲維護,沒法作到自動感知。

image.png

後續又想到這個集羣列表經過集羣內節點進行選舉出主節點,其餘節點直接上報給主節點,主節點再進行分發,這樣主節點自身狀態成爲保證這個同步成功的關鍵,不然要從新選舉,這樣就沒法及時通知這個列表信息。

image.png

最後咱們決定獨立一個角色進行專職作集羣列表信息的註冊和發現,稱爲 MetaServer。Session 和 Data 每一個節點都在 MetaServer 上進行註冊,而且經過長鏈接按期保持心跳,這樣能夠明確各個集羣節點的變化,及時通知各個其餘節點。

image.png

咱們的優點

目前,SOFARegistry 能夠支撐以下的數據量:

  • 2000+ 應用 2.3w 服務註冊發現;
  • 單機房 Data 集羣支持百萬級 Pub 數據,千萬級 Sub 數據;
  • 高可用,集羣宕機 ½ 之內節點服務自恢復;
  • 支持數百應用同時啓動發佈訂閱。

SOFARegistry 與開源同類產品的比較:

比較

SOFARegistry

Eureka 1.0

ZooKeeper

一致性

最終一致

最終一致

強一致

可用性

高可用,集羣節點可動態擴縮容,數據保持多副本

高可用

節點選舉過程整個集羣不可用,沒法提供服務

可擴展

一致性 Hash 數據分片,理論上無限制擴展

數據節點相互同步方式保持一致,有上限瓶頸

數據強一致,一樣存在上限

時效性

秒級服務發現,經過鏈接狀態進行服務數據變動通知

採用長輪詢健康檢查方式獲取節點狀態,時效不敏感

強一致要求,多寫效率低

未來

挑戰

  • 面向現有主流微服務框架。目前主流微服務框架須要咱們進行適配,好比 SpringCloud、Dubbo 等,這些框架在服務發現方面有必定的規範能夠進行遵循後接入,對於適應性有所加強。此外對於雲上不少服務發現組件能夠進行對接好比 Cloudmap 等。
  • 面向雲原生微服務運維。衆所周知,服務註冊中心的運維很是複雜,必需要有特定的運維發佈方式來嚴格控制步驟,不然影響是不可逆的。咱們也進行了大量的運維嘗試,作了不少狀態劃分保持整個集羣發佈的順暢,後續雲原生和 k8s 接入必將對傳統的運維方式進行變革,這個過程要求咱們產品自身能夠微服務化、鏡像化才能適應容器運維的需求,而且須要考慮新的數據一致性方式。
  • 面對單元化部署。單元化其實在螞蟻內部已經大規模實踐,服務註冊中心在這裏承載的職責尤其重要,當前咱們對多機房多城市等部署模式在數據結構上已經進行開放,可是對於機房間一些特定功能考慮進一步開放和完善。

Roadmap

一些新的 Feature 規劃和上述過程的開源路徑:

image.png

總結

以上就是本期分享的全部內容。當前,代碼已開源託管在 GitHub 上,歡迎關注,同時也歡迎業界愛好者共同創造更好的 SOFARegistry。

SOFA 開源社區,感謝有你!

公衆號:金融級分佈式架構(Antfin_SOFA)

相關文章
相關標籤/搜索