[從原始碼學設計]螞蟻金服SOFARegistry之網路封裝和操作
阿新 • • 發佈:2020-11-25
# [從原始碼學設計]螞蟻金服SOFARegistry之網路封裝和操作
[toc]
## 0x00 摘要
SOFARegistry 是螞蟻金服開源的一個生產級、高時效、高可用的服務註冊中心。
本系列文章重點在於分析設計和架構,即利用多篇文章,從多個角度反推總結 DataServer 或者 SOFARegistry 的實現機制和架構思路,讓大家藉以學習阿里如何設計。
本文為第二篇,介紹SOFARegistry的網路封裝和操作。
## 0x01 業務領域
### 1.1 SOFARegistry 總體架構
因為有的兄弟可能沒有讀過前面MetaServer的文章,所以這裡回憶下SOFARegistry 總體架構。
- **Client 層**
應用伺服器叢集。Client 層是應用層,每個應用系統通過依賴註冊中心相關的客戶端 jar 包,通過程式設計方式來使用服務註冊中心的服務釋出和服務訂閱能力。
- **Session 層**
Session 伺服器叢集。顧名思義,Session 層是會話層,通過長連線和 Client 層的應用伺服器保持通訊,負責接收 Client 的服務釋出和服務訂閱請求。該層只在記憶體中儲存各個服務的釋出訂閱關係,對於具體的服務資訊,只在 Client 層和 Data 層之間透傳轉發。Session 層是無狀態的,可以隨著 Client 層應用規模的增長而擴容。
- **Data 層**
資料伺服器叢集。Data 層通過分片儲存的方式儲存著所用應用的服務註冊資料。資料按照 dataInfoId(每一份服務資料的唯一標識)進行一致性 Hash 分片,多副本備份,保證資料的高可用。下文的重點也在於隨著資料規模的增長,Data 層如何在不影響業務的前提下實現平滑的擴縮容。
- **Meta 層**
元資料伺服器叢集。這個叢集管轄的範圍是 Session 伺服器叢集和 Data 伺服器叢集的伺服器資訊,其角色就相當於 SOFARegistry 架構內部的服務註冊中心,只不過 SOFARegistry 作為服務註冊中心是服務於廣大應用服務層,而 Meta 叢集是服務於 SOFARegistry 內部的 Session 叢集和 Data 叢集,Meta 層能夠感知到 Session 節點和 Data 節點的變化,並通知叢集的其它節點。
### 1.2 應用場景
DataServer,SessionServer,MetaServer 本質上都是網路應用程式。這就決定了網路封裝和操作是本系統的基礎模組及功能,下面我們講講其應用場景。
#### 1.2.1 單元化狀態
SOFARegistry 的應用場景是單元化狀態下。
在單元化狀態下,一個單元,是一個五臟俱全的縮小版整站,它是全能的,因為部署了所有應用;但它不是全量的,因為只能操作一部分資料。能夠單元化的系統,很容易在多機房中部署,因為可以輕易的把幾個單元部署在一個機房,而把另外幾個部署在其他機房。藉由在業務入口處設定一個流量調配器,可以調整業務流量在單元之間的比例。
#### 1.2.2 內網通訊
所以 SOFARegistry 考慮的就是在 IDC 私網環境中如何進行節點間通訊。高吞吐、高併發的通訊 ,數量眾多的連線管理(C10K 問題),便捷的升級機制,相容性保障,靈活的執行緒池模型運用,細緻的異常處理與日誌埋點等,這些功能都需要在通訊協議和實現框架上做文章。
#### 1.2.3 Http協議
伺服器也有若干配置需求,這用簡單的http協議即可。
### 1.3 問題點
在這種內網單元化場景下,能夠想到的問題點如下:
- 如何制定私有協議。對於私網環境,如果所有應用的節點間,全部通過標準協議來通訊,會有很多問題:比如研發效率方面的影響,升級相容性,無用欄位的傳輸,功能定製也可能不那麼靈活。
- 如何進行連結管理(無鎖建連、定時斷連、自動重連);
- 如何進行精細的執行緒模型的設計;
- 如何進行超時控制;
- 如何進行批量解包和批量提交處理;
- 如何進行心跳控制;
- 如何支援通訊模型(oneway、sync、callback、future);
- 如何實現長連線;
- 如何實現推拉模式;
- 如何進行節點判活;
### 1.4 解決方案
對於這種高效能,高併發的場景,在Java體系下,必然選擇非阻塞IO複用,那麼自然選擇基於Netty進行開發。
### 1.5 阿里方案
阿里就是藉助 [SOFABolt](https://github.com/sofastack/sofa-bolt) 通訊框架,實現基於TCP長連線的節點判活與推模式的變更推送,服務上下線通知時效性在秒級以內。
sofa-bolt是螞蟻開源的一款基於Netty的網路通訊框架。在Netty的基礎上對網路程式設計常見問題進行了一層簡單封裝,讓中介軟體開發者更關注於中介軟體產品本身。
大體功能為:
1. 連線管理
2. 請求處理
SOFABolt可以理解為Netty的最佳實踐,並額外進行了一些優化工作。
- 基於Netty的高效的網路IO於執行緒模型的應用
- 連結管理(無鎖建連、定時斷連、自動重連)
- 通訊模型(oneway、sync、callback、future)
- 超時控制
- 批量解包和批量提交處理
- 心跳於IDLE機制
SOFABolt框架我們後續可能會專門有系列進行分析,目前認為基於SOFABolt此可以滿足我們需求,所以我們會簡單介紹SOFABolt,重點在於如何使用以及業務實現 。
### 1.6 實現問題
在確定了採用SOFABolt之後,之前提到的問題點就基本被SOFABolt解決了,所以我們暫時能想到的其他問題大致如下:
- 對於網路中的各種功能模組,是否需要封裝,如果封裝,到什麼程度比較恰當;
- 具體封裝,縱向橫向分別需要細化到什麼程度;
- Data Server 既要對外提供服務,也會作為客戶端向其他模組傳送請求,這兩個功能是否需要抽象出來;
- 是否需要按照具體業務功能進行分類封裝;
### 1.7 總述
我們提前劇透,即從邏輯上看,阿里提供了兩個層級的封裝
從連線角度看,阿里實現了基於 netty.channel.Channel 的封裝,從下往上看是:
- 因為SOFABolt基於Netty,所以封裝的核心是netty.channel.Channel。
- 在此基礎上, SOFABolt封裝了com.alipay.remoting.Connection
- 然後 SOFARegistry 基於SOFABolt 封裝了 BoltChannel
從應用角度看,阿里實現了Server,Client層次的封裝,從下往上看是:
- SOFABolt構建了 RpcServer,RpcClient。
- SOFARegisty 基於 RpcServer,RpcClient 構建了BoltClient 和 BoltServer。
- 然後 SOFARegistry 基於此構建了 BoltExchange。作為 Client / Server 連線的抽象,負責節點之間的連線。
- 最後構建了 XXXNodeExchanger,在 BoltExchange 基礎上,把所有 Data Server 相關的 **非** “Server,Client概念 強相關” 的網路操作統一集中在這裡,使用者可以直接使用。以DataServer業務模組為例,其內部按照業務不同,實現了 DataNodeExchanger 和 MetaNodeExchanger。用以讓:
- DataServer 內部直接使用 DataNodeExchanger 與其他 DataServer 互動,
- DataServer 內部直接使用 MetaNodeExchanger 與 MetaServer 互動。
具體邏輯大致如下:
```java
+---------------------+ +---------------------+
| | | |
| DataNodeExchanger | | MetaNodeExchanger |
| | | |
+----------------+----+ +--------+------------+
| |
+-----------+ +-------------+
| |
v v
+---------+---------------------+--------+
| BoltExchange |
| +------------------------------------+ |
| | | |
| |