溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何解析SOFARegistry

發(fā)布時間:2021-10-22 11:14:10 來源:億速云 閱讀:114 作者:柒染 欄目:大數(shù)據(jù)

這篇文章將為大家詳細講解有關如何解析SOFARegistry,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

SOFAStack(Scalable Open Financial Architecture Stack) 是螞蟻金服自主研發(fā)的金融級分布式架構,包含了構建金融級云原生架構所需的各個組件,是在金融場景里錘煉出來的最佳實踐。

SOFARegistry 是螞蟻金服開源的具有承載海量服務注冊和訂閱能力的、高可用的服務注冊中心,在支付寶/螞蟻金服的業(yè)務發(fā)展驅(qū)動下,近十年間已經(jīng)演進至第五代。

概述

在前面的章節(jié)中我們已經(jīng)提到,SOFARegistry 與其他服務發(fā)現(xiàn)領域的產(chǎn)品相比,最大的不同點在于支持海量數(shù)據(jù)。本章即將講述 SOFARegistry 在支撐海量數(shù)據(jù)上的一些特性。

本文將從如下幾個方面進行講解:

  • DataServer 總體架構:對 SOFARegistry 中支持海量數(shù)據(jù)的總體架構做一個簡述,講解數(shù)據(jù)分片和同步方案中所涉及到的關鍵技術點;

  • DataServer 啟動:講解 DataServer 啟動的服務,從而為接下來更直觀地理解數(shù)據(jù)分片、數(shù)據(jù)同步的觸發(fā)時機以及觸發(fā)方式等做一個鋪墊;

  • 數(shù)據(jù)分片:講解 SOFARegistry 中采用的一致性 Hash 算法進行數(shù)據(jù)分片的緣由以及具體實現(xiàn)方法;

  • 數(shù)據(jù)同步方案:講解 SOFARegistry 采用的數(shù)據(jù)同步方案;

DataServer 總體架構

在大部分的服務注冊中心系統(tǒng)中,每臺服務器都存儲著全量的服務注冊數(shù)據(jù),服務器之間通過一致性協(xié)議(paxos、Raft 等)實現(xiàn)數(shù)據(jù)的復制,或者采用只保障最終一致性的算法,來實現(xiàn)異步數(shù)據(jù)復制。這樣的設計對于一般業(yè)務規(guī)模的系統(tǒng)來說沒有問題,而當應用于有著海量服務的龐大的業(yè)務系統(tǒng)來說,就會遇到性能瓶頸。

為解決這一問題,SOFARegistry 采用了數(shù)據(jù)分片的方法。全量服務注冊數(shù)據(jù)不再保存在單機里,而是分布于每個節(jié)點中,每臺服務器保存一定量的服務注冊數(shù)據(jù),同時進行多副本備份,從理論上實現(xiàn)了服務無限擴容,且實現(xiàn)了高可用,最終達到支撐海量數(shù)據(jù)的目的。

在各種數(shù)據(jù)分片算法中,SOFARegistry 采用了業(yè)界主流的一致性 Hash 算法做數(shù)據(jù)分片,當節(jié)點動態(tài)擴縮容時,數(shù)據(jù)仍能均勻分布,維持數(shù)據(jù)的平衡。

在數(shù)據(jù)同步時,沒有采用與 Dynamo、Casandra、Tair、Codis、Redis cluster 等項目中類似的預分片機制,而是在 DataServer 內(nèi)存里以 dataInfoId 為粒度進行操作日志記錄,這種實現(xiàn)方式在某種程度上也實現(xiàn)了“預分片”,從而保障了數(shù)據(jù)同步的有效性。

如何解析SOFARegistry

圖 1 SOFARegistry 總體架構圖

DataServer 啟動

啟動入口

DataServer 模塊的各個 bean 在 JavaConfig 中統(tǒng)一配置,JavaConfig 類為 DataServerBeanConfiguration, 啟動入口類為 DataServerInitializer,該類不由 JavaConfig 管理配置,而是繼承了 SmartLifecycle 接口,在啟動時由 Spring 框架調(diào)用其 start 方法。

該方法中調(diào)用了 DataServerBootstrap#start 方法(圖 2),用于啟動一系列的初始化服務。

從代碼中可以看出,DataServer 服務在啟動時,會啟動 DataServer、DataSyncServer、HttpServer 三個 bolt 服務。在啟動這些 Server 之時,DataServer 注冊了一系列 Handler 來處理各類消息。

如何解析SOFARegistry

圖2 DataServerBootstrap 中的 start 方法

這幾個 Server 的作用如下:

  • DataServer:數(shù)據(jù)服務,獲取數(shù)據(jù)的推送,服務上下線通知等;

  • DataSyncServer:數(shù)據(jù)同步服務;

  • HttpServer:提供一系列 REST 接口,用于 dashboard 管理、數(shù)據(jù)查詢等;

各 Handler 具體作用如圖 3 所示:

如何解析SOFARegistry

圖 3 各 Handler 作用

同時啟動了 RaftClient 用于保障 DataServer 節(jié)點之間的分布式一致性,啟動了各項啟動任務,具體內(nèi)容如圖 4 所示:

如何解析SOFARegistry

圖 4 DataServer 各項啟動任務

各個服務的啟動監(jiān)聽端口如圖 5 所示:

如何解析SOFARegistry

圖5 監(jiān)聽端口

其他初始化 Bean

除上述的啟動服務之外,還有一些 bean 在模塊啟動時被初始化, 系統(tǒng)初始化時的 bean 都在 DataServerBeanConfiguration 里面通過 JavaConfig 來注冊,主要以如下幾個配置類體現(xiàn)(配置類會有變更,具體內(nèi)容可以參照源碼實現(xiàn)):

  • DataServerBootstrapConfigConfiguration:該配置類主要作用是提供一些 DataServer 服務啟動時基本的 Bean,比如 DataServerConfig 基礎配置 Bean、DataNodeStatus 節(jié)點狀態(tài) Bean、DatumCache 緩存 Bean 等;

  • LogTaskConfigConfiguration:該配置類主要用于提供一些日志處理相關的 Bean;

  • SessionRemotingConfiguration:該配置類主要作用是提供一些與 SessionServer 相互通信的 Bean,以及連接過程中的一些請求處理 Bean。比如 BoltExchange、JerseyExchange 等用于啟動服務的 Bean,還有節(jié)點上下線、數(shù)據(jù)發(fā)布等的 Bean,為關鍵配置類;

  • DataServerNotifyBeanConfiguration:該配置類中配置的 Bean 主要用于進行事件通知,如用于處理數(shù)據(jù)變更的 DataChangeHandler 等;

  • DataServerSyncBeanConfiguration:該配置類中配置的 Bean 主要用于數(shù)據(jù)同步操作;

  • DataServerEventBeanConfiguration:該配置類中配置的 Bean 主要用于處理與數(shù)據(jù)節(jié)點相關的事件,如事件中心 EventCenter、數(shù)據(jù)變化事件中心 DataChangeEventCenter 等;

  • DataServerRemotingBeanConfiguration:該配置類中配置的 Bean 主要用于 DataServer 的連接管理;

  • ResourceConfiguration:該配置類中配置的 Bean 主要用于提供一些 Rest 接口資源;

  • AfterWorkingProcessConfiguration:該配置類中配置一些后處理 Handler Bean,用于處理一些業(yè)務邏輯結束后的后處理動作;

  • ExecutorConfiguration:該配置類主要配置一些線程池 Bean,用于執(zhí)行不同的任務;

數(shù)據(jù)分片講解

數(shù)據(jù)分片機制是 SOFARegistry 支撐海量數(shù)據(jù)的核心所在,DataServer 負責存儲具體的服務數(shù)據(jù),數(shù)據(jù)按照 dataInfoId 進行一致性 Hash 分片存儲,支持多副本備份,保證數(shù)據(jù)的高可用。

(對一致性 Hash 算法感興趣想深入了解的同學可以閱讀該算法的提出者 Karger 及其合作者的原始論文:Consistent hashing and random trees: distributed caching protocols for relieving hot spots on the World Wide Web。)

在講解 SOFARegistry 的數(shù)據(jù)分片之前,我們先看下最簡單的傳統(tǒng)數(shù)據(jù)分片 Hash 算法。

傳統(tǒng)數(shù)據(jù)分片 Hash 算法

在傳統(tǒng)的數(shù)據(jù)分片算法中,先對每個節(jié)點的 ID 進行 1 到 K 的標號,然后再對每個要存儲到節(jié)點上的數(shù)據(jù)使用 Hash 算法,計算之后的值對 K 取模,所得結果就是要落在的節(jié)點 ID。

該算法簡單且常用,很多場景中都使用該算法進行數(shù)據(jù)分片。

如何解析SOFARegistry 圖 6 傳統(tǒng) Hash 分片算法

在這種算法下,當某個節(jié)點下線(如圖 6 中的 Node 2),該節(jié)點之后的所有節(jié)點需要重新標號。所有數(shù)據(jù)要重新求 Hash 值取模,再重新存儲到相應節(jié)點中。(圖 7)

在海量數(shù)據(jù)場景下,該方式將會帶來很大的性能開銷。

如何解析SOFARegistry

圖 7 傳統(tǒng) Hash 分片算法,某個節(jié)點下線后將影響全局數(shù)據(jù)分布

傳統(tǒng)一致性 Hash 進行數(shù)據(jù)分片

為了使服務節(jié)點上下線不會影響到全局數(shù)據(jù)的分布,在實際的生產(chǎn)環(huán)境中,很多系統(tǒng)使用的是一致性 Hash 算法進行數(shù)據(jù)分片。業(yè)界使用一致性 Hash 的代表項目有 Memcached、Twemproxy 等。

數(shù)據(jù)范圍

一致性 Hash 算法采用了 $$2^{32}$$ 個桶來存儲所有的 Hash 值,0 ~ $$2^{32}-1$$ 作為取值范圍,并且形成一個環(huán)。

數(shù)據(jù)分片原則

在圖 8 中,NodeA#1、NodeB#1、NodeC#1 分別為 A、B、C 三個節(jié)點的 ID 經(jīng)過一致性 Hash 算法的計算后落在環(huán)上的位置。

三角形為不同的數(shù)據(jù)經(jīng)過一致性 Hash 算法之后落在環(huán)上的位置。每個數(shù)據(jù)經(jīng)過順時針,找尋最近的一個節(jié)點,作為數(shù)據(jù)存儲的節(jié)點。

如何解析SOFARegistry

圖 8 一致性 Hash 算法

從圖 8 中不難想到,當有節(jié)點上下線時,僅僅影響到上下線節(jié)點與該節(jié)點逆時針方向最近的一個節(jié)點之間的數(shù)據(jù)分布。此時,只需要對掉落到這個區(qū)間內(nèi)的數(shù)據(jù)重排即可。(如圖 9)

如何解析SOFARegistry

圖 9 一致性 Hash 算法中 NodeB#1 下線

一致性 Hash 算法特點

該算法中,每個節(jié)點的 ID 需要通過一致性 Hash 算法計算后映射到圓環(huán)上,以此帶來了一致性 Hash 算法的兩個特點:

  • 當節(jié)點總量較少時,可以虛擬多個虛擬節(jié)點(如圖 10,實際中可能會交叉排布,在這里方便描述則放在一起),當虛擬節(jié)點足夠多時,可以保障數(shù)據(jù)在真實節(jié)點上面能夠均勻分散分布,這是一致性 Hash 算法的優(yōu)點;

  • 采用一致性 Hash 之后,數(shù)據(jù)在節(jié)點環(huán)中的分布范圍不固定。當節(jié)點動態(tài)擴縮容之后,部分數(shù)據(jù)要重新分布,在數(shù)據(jù)同步時會帶來一定的問題;

如何解析SOFARegistry

圖 10 虛擬節(jié)點排布

SOFARegistry 的一致性 Hash 代碼實現(xiàn)

在 SOFARegistry 中,由 ConsistentHash 類來實現(xiàn)一致性 Hash 類圖,如圖 11 所示:

如何解析SOFARegistry

圖 11 SOFARegistry 的一致性 Hash 類圖

在該類中,SIGN 為 ID 的分隔符,numberOfReplicas 則是每個節(jié)點的虛擬節(jié)點數(shù),realNodes 為節(jié)點列表,hashFunction 為采用的 Hash 算法,circle 為預分片機制中的 Hash 環(huán)。

ConsistentHash 默認采用了 MD5 摘要算法來進行 hash,同時構造函數(shù)支持 hash 函數(shù)定制化,用戶可以定制自己的 Hash 算法。同時,該類中 circle 的實現(xiàn)為 TreeMap,巧妙地使用了 TreeMap 的 tailMap() 方法來實現(xiàn)一致性 Hash 的節(jié)點查找能力,數(shù)據(jù)最近的節(jié)點 hash 值計算代碼如圖 12 所示:

如何解析SOFARegistry

圖 12 數(shù)據(jù)最近節(jié)點 hash 值計算方法

預分片機制

傳統(tǒng)的一致性 Hash 算法有數(shù)據(jù)分布范圍不固定的特性,該特性使得服務注冊數(shù)據(jù)在服務器節(jié)點宕機、下線、擴容之后,需要重新存儲排布,這為數(shù)據(jù)的同步帶來了困難。大多數(shù)的數(shù)據(jù)同步操作是利用操作日志記錄的內(nèi)容來進行的,傳統(tǒng)的一致性 Hash 算法中,數(shù)據(jù)的操作日志是以節(jié)點分片來劃分的,節(jié)點變化導致數(shù)據(jù)分布范圍的變化。

在計算機領域,大多數(shù)難題都可以通過增加一個中間層來解決,那么對于數(shù)據(jù)分布范圍不固定所導致的數(shù)據(jù)同步難題,也可以通過同樣的思路來解決。

這里的問題在于,當節(jié)點下線后,若再以當前存活節(jié)點 ID 一致性 Hash 值去同步數(shù)據(jù),就會導致已失效節(jié)點的數(shù)據(jù)操作日志無法獲取到,既然數(shù)據(jù)存儲在會變化的地方無法進行數(shù)據(jù)同步,那么如果把數(shù)據(jù)存儲在不會變化的地方是否就能保證數(shù)據(jù)同步的可行性呢?答案是肯定的,這個中間層就是預分片層,通過把數(shù)據(jù)與預分片這個不會變化的層相互對應就能解決這個數(shù)據(jù)同步的難題。

目前業(yè)界主要代表項目如 Dynamo、Casandra、Tair、Codis、Redis cluster 等,都采用了預分片機制來實現(xiàn)這個不會變化的層。

事先將數(shù)據(jù)存儲范圍等分為 N 個 slot 槽位,數(shù)據(jù)直接與 slot 相對應,數(shù)據(jù)的操作日志與相應的 solt 對應,slot 的數(shù)目不會因為節(jié)點的上下線而產(chǎn)生變化,由此保證了數(shù)據(jù)同步的可行性。除此之外,還需要引進“路由表”的概念,如圖 13,“路由表”負責存放每個節(jié)點和 N 個 slot 的映射關系,并保證盡量把所有 slot 均勻地分配給每個節(jié)點。這樣,當節(jié)點上下線時,只需要修改路由表內(nèi)容即可。保持 slot 不變,即保證了彈性擴縮容,也大大降低了數(shù)據(jù)同步的難度。

如何解析SOFARegistry

圖 13 預分片機制

SOFARegistry 的分片選擇

SOFARegistry 為了實現(xiàn)服務注冊數(shù)據(jù)的分布式存儲,采用了基于一致性 Hash 的數(shù)據(jù)分片。而由于歷史原因,為了實現(xiàn)數(shù)據(jù)在節(jié)點間的同步,則采用了在 DataServer 之間以 dataInfoId 為粒度進行數(shù)據(jù)同步。

節(jié)點分片

當 DataServer 節(jié)點初始化成功后,會啟動任務自動去連接 MetaServer。該任務會往事件中心 EventCenter 注冊一個 DataServerChangeEvent 事件,該事件注冊后會被觸發(fā),之后將對新增節(jié)點計算 Hash 值,同時進行納管分片。

DataServerChangeEvent 事件被觸發(fā)后,由 DataServerChangeEventHandler 來進行相應的處理,分別分為如下一些步驟:

  1. 初始化當前數(shù)據(jù)節(jié)點的一致性 Hash 值,把當前節(jié)點添加進一致性的 Hash 環(huán)中。(圖 14)

如何解析SOFARegistry

圖 14 初始化一致性 Hash 環(huán)

  1. 獲取變更了的 DataServer 節(jié)點,這些節(jié)點在啟動 DataServer 服務的時候從 MetaServer 中獲取到的,并且通過 DataServerChangeEvent 事件中的 DataServerChangeItem 傳入。(圖 15)

如何解析SOFARegistry

圖 15 獲取變更了的 DataServer 節(jié)點

  1. 獲取了當前的 DataServer 節(jié)點之后,若節(jié)點列表非空,則遍歷每個節(jié)點,建立當前節(jié)點與其余數(shù)據(jù)節(jié)點之間的連接,同時刪除本地維護的不在節(jié)點列表中的節(jié)點數(shù)據(jù)。同時,若當前節(jié)點是 DataCenter 節(jié)點,則觸發(fā) LocalDataServerChangeEvent 事件。

至此,節(jié)點初始化以及分片入 Hash 環(huán)的工作已經(jīng)完成。

數(shù)據(jù)節(jié)點相關數(shù)據(jù),儲存在 Map 中,相關的數(shù)據(jù)結構如圖 16 所示。

如何解析SOFARegistry

圖 16 DataServer 節(jié)點一致性 Hash 存儲結構

數(shù)據(jù)分片

當服務上線時,會計算新增服務的 dataInfoId Hash 值,從而對該服務進行分片,最后尋找最近的一個節(jié)點,存儲到相應的節(jié)點上。

前文已經(jīng)說過,DataServer 服務在啟動時添加了 publishDataProcessor 來處理相應的服務發(fā)布者數(shù)據(jù)發(fā)布請求,該 publishDataProcessor 就是 PublishDataHandler。當有新的服務發(fā)布者上線,DataServer 的 PublishDataHandler 將會被觸發(fā)。

該 Handler 首先會判斷當前節(jié)點的狀態(tài),若是非工作狀態(tài)則返回請求失敗。若是工作狀態(tài),則觸發(fā)數(shù)據(jù)變化事件中心 DataChangeEventCenter 的 onChange 方法。

DataChangeEventQueue 中維護著一個 DataChangeEventQueue 隊列數(shù)組,數(shù)組中的每個元素是一個事件隊列。當上文中的 onChange 方法被觸發(fā)時,會計算該變化服務的 dataInfoId 的 Hash 值,從而進一步確定出該服務注冊數(shù)據(jù)所在的隊列編號,進而把該變化的數(shù)據(jù)封裝成一個數(shù)據(jù)變化對象,傳入到隊列中。

DataChangeEventQueue#start 方法在 DataChangeEventCenter 初始化的時候被一個新的線程調(diào)用,該方法會源源不斷地從隊列中獲取新增事件,并且進行分發(fā)。新增數(shù)據(jù)會由此添加進節(jié)點內(nèi),實現(xiàn)分片。

數(shù)據(jù)同步方案講解

SOFARegistry 是 Client、SessionServer、DataServer 三層架構,同時通過 MetaServer 管理 Session 和 Data 集群,在服務注冊的過程中,數(shù)據(jù)既有層間的數(shù)據(jù)同步,也有層內(nèi)的節(jié)點間同步。

層內(nèi)同步 —— 數(shù)據(jù)回放

Client 端在本地內(nèi)存內(nèi)已經(jīng)存儲了需要訂閱和發(fā)布的服務數(shù)據(jù),在連接上 Session 后會回放訂閱和發(fā)布數(shù)據(jù)給 Session,最終再發(fā)布到 Data。同時,Session 存儲著客戶端發(fā)布的所有 Pub 數(shù)據(jù),定期通過數(shù)據(jù)比對保持和 Data 一致性。當數(shù)據(jù)發(fā)生變更時,持有數(shù)據(jù)一方的 Data 發(fā)起變更通知,需要同步的 SessionServer 進行版本對比,在判斷出數(shù)據(jù)需要更新時,將拉取最新的數(shù)據(jù)操作日志。

操作日志存儲采用堆棧方式,獲取日志是通過當前版本號在堆棧內(nèi)所處位置,把所有版本之后的操作日志同步過來執(zhí)行。

層間同步 —— 多副本

為保障 Data 層數(shù)據(jù)的可用性,SOFARegistry 做了 Data 層的多副本機制。當有 Data 節(jié)點縮容、宕機發(fā)生時,備份節(jié)點可以立即通過備份數(shù)據(jù)生效成為主節(jié)點,對外提供服務,并且把相應的備份數(shù)據(jù)再按照新列表計算備份給新的節(jié)點。

當有 Data 節(jié)點擴容時,新增節(jié)點進入初始化狀態(tài),期間禁止新數(shù)據(jù)寫入,對于讀取請求會轉(zhuǎn)發(fā)到后續(xù)可用的 Data 節(jié)點獲取數(shù)據(jù)。在其他節(jié)點的備份數(shù)據(jù)按照新節(jié)點信息同步完成后,新擴容的 Data 節(jié)點狀態(tài)變成 Working,開始對外提供服務。

總結

在海量服務注冊場景下,為保障 DataServer 能否無限擴容面對海量數(shù)據(jù)的業(yè)務場景,與其他服務注冊中心不同的是,SOFARegistry 采用了一致性 Hash 算法進行數(shù)據(jù)分片,保障了數(shù)據(jù)的可擴展性。同時,通過在 DataServer 內(nèi)存里以 dataInfoId 的粒度記錄操作日志,并且在 DataServer 之間也是以 dataInfoId 的粒度去做數(shù)據(jù)同步,保障了數(shù)據(jù)的一致性。

關于如何解析SOFARegistry就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI