1. 程式人生 > >[從原始碼學設計]螞蟻金服SOFARegistry 之 服務註冊和操作日誌

[從原始碼學設計]螞蟻金服SOFARegistry 之 服務註冊和操作日誌

# [從原始碼學設計]螞蟻金服SOFARegistry之服務註冊和操作日誌 [toc] ## 0x00 摘要 SOFARegistry 是螞蟻金服開源的一個生產級、高時效、高可用的服務註冊中心。 本系列文章重點在於分析設計和架構,即利用多篇文章,從多個角度反推總結 DataServer 或者 SOFARegistry 的實現機制和架構思路,讓大家藉以學習阿里如何設計。 本文為第十四篇,介紹SOFARegistry服務上線和操作日誌。上文是從Session Server角度,本文從 Data Server 角度介紹。 ## 0x01 整體業務流程 我們首先回顧總體業務流程,這部分屬於資料分片。 ### 1.1 服務註冊過程 回顧下“一次服務註冊過程”的服務資料在內部流轉過程。 1. Client 呼叫 publisher.register 向 SessionServer 註冊服務。 2. SessionServer 收到服務資料 (PublisherRegister) 後,將其寫入記憶體 (SessionServer 會儲存 Client 的資料到記憶體,用於後續可以跟 DataServer 做定期檢查),再根據 dataInfoId 的一致性 Hash 尋找對應的 DataServer,將 PublisherRegister 發給 DataServer。 3. DataServer 接收到 PublisherRegister 資料,首先也是將資料寫入記憶體 ,DataServer 會以 dataInfoId 的維度彙總所有 PublisherRegister。同時,DataServer 將該 dataInfoId 的變更事件通知給所有 SessionServer,變更事件的內容是 dataInfoId 和版本號資訊 version。 4. 同時,非同步地,DataServer 以 dataInfoId 維度增量地同步資料給其他副本。因為 DataServer 在一致性 Hash 分片的基礎上,對每個分片儲存了多個副本(預設是3個副本)。 5. SessionServer 接收到變更事件通知後,對比 SessionServer 記憶體中儲存的 dataInfoId 的 version,若發現比 DataServer 發過來的小,則主動向 DataServer 獲取 dataInfoId 的完整資料,即包含了所有該 dataInfoId 具體的 PublisherRegister 列表。 6. 最後,SessionServer 將資料推送給相應的 Client,Client 就接收到這一次服務註冊之後的最新的服務列表資料。 **因為篇幅所限,上文討論的是前兩點,本文介紹第三,第四點**。 ### 1.2 資料分片 當服務上線時,會計算新增服務的 dataInfoId Hash 值,從而對該服務進行分片,最後尋找最近的一個節點,儲存到相應的節點上。 DataServer 服務在啟動時添加了 publishDataProcessor 來處理相應的服務釋出者資料釋出請求,該 publishDataProcessor 就是 PublishDataHandler。當有新的服務釋出者上線,DataServer 的 PublishDataHandler 將會被觸發。 該 Handler 首先會判斷當前節點的狀態,若是非工作狀態則返回請求失敗。若是工作狀態,則觸發資料變化事件中心 DataChangeEventCenter 的 onChange 方法。 DataChangeEventQueue 中維護著一個 DataChangeEventQueue 佇列陣列,陣列中的每個元素是一個事件佇列。當上文中的 onChange 方法被觸發時,會計算該變化服務的 dataInfoId 的 Hash 值,從而進一步確定出該服務註冊資料所在的佇列編號,進而把該變化的資料封裝成一個數據變化物件,傳入到佇列中。 DataChangeEventQueue#start 方法在 DataChangeEventCenter 初始化的時候被一個新的執行緒呼叫,該方法會源源不斷地從佇列中獲取新增事件,並且進行分發。新增資料會由此新增進節點內,實現分片。 與此同時,DataChangeHandler 會把這個事件變更資訊通過 ChangeNotifier 對外發布,通知其他節點進行資料同步。 ## 0x02 基礎資料結構 這裡需要首先講解幾個相關資料結構。 ### 2.1 Publisher Publisher是資料釋出者資訊。 ```java public class Publisher extends BaseInfo { priv