螞蟻金服通訊框架SOFABolt解析 | 協議框架解析
SOFA
S calable O pen F inancial A rchitecture
是螞蟻金服自主研發的金融級分散式中介軟體,包含了構建金融級雲原生架構所需的各個元件,是在金融場景裡錘鍊出來的最佳實踐。
本文為《螞蟻金服通訊框架 SOFABolt 解析》系列第三篇,作者顏洄、丞一。
《螞蟻金服通訊框架 SOFABolt 解析》系列由 SOFA 團隊和原始碼愛好者們出品。
SOFARPC: ofollow,noindex"> https:// github.com/alipay/sofa- rpc
SOFABolt: https:// github.com/alipay/sofa- bolt

前言
為了讓中介軟體開發者們將更多的精力投入到產品的功能特性上,而不是重複的寫通訊層框架, 螞蟻中介軟體團隊設計並實現了 SOFABolt 。
Bolt 名字取自迪士尼動畫-閃電狗,是一個基於 Netty 最佳實踐的輕量、易用、高效能、易擴充套件的通訊框架。螞蟻中介軟體的同學這些年在微服務和訊息中介軟體上解決了很多網路通訊的問題,積累了很多經驗,並將這些經驗、解決方案沉澱到了 SOFABolt 這個專案中,希望能讓更多需要使用網路通訊的團隊、開發者受益。目前 SOFABolt 已經執行在滿意中介軟體的微服務 (SOFARPC)、訊息中心、分散式事務、分散式開關、以及配置中心等眾多產品上。
主要特性
SOFABolt 核心功能包括三大塊:
- 網路通訊能力
- 協議框架
- 私有協議實現
網路通訊能力
網路通訊能力(remoting-core)可以理解為 Netty 的最佳實踐,並額外進行了一些優化工作,包含:
- 基於 Netty 的高效的網路IO於執行緒模型的應用
- 連結管理(無鎖建連、定時斷連、自動重連)
- 通訊模型(oneway、sync、callback、future)
- 超時控制
- 批量解包和批量提交處理
- 心跳於IDLE機制
協議框架
協議框架(protocol-skeleton)包含命令處理器、編解碼器等,是底層通訊能力之上,具體私有協議之下,連線通訊能力和私有協議的中間層。網路通訊層是 SOFABolt 對 Netty 的封裝和功能增強,協議框架則是 SOFABolt 對網路請求處理流程的抽象,是使用者可以不關心底層細節快速實現自己的處理器來完成網路請求的處理邏輯,是使用者可以進行拓展來實現自定義的私有協議的基礎,也是本篇文章分析的內容。
私有協議實現
由於效能、安全性等等的原因,很多中介軟體都會採用私有協議進行通訊。SOFABolt 除了提供基礎的通訊能力、協議框架之外,還提供了預設的 RPC 協議的實現,這樣它就是一個完整的通訊框架,使用者可以不關心協議而直接上手使用。本篇文章主要分析 SOFABolt 的協議框架的設計和實現,不展開對 SOFABolt 中的RPC 協議實現做介紹。
協議框架
協議框架整體如下:

- Command:協議命令,通訊資料的頂層抽象。從互動的角度可以分為Request(請求)於Response(響應),從功能的角度,分為負載命令(交換業務資料)和控制命令(進行系統的管理、協調等)。
- CommandEncoder/CommandDecoder:協議命令的編解碼器,自定義協議實現的基礎,編解碼器完成物件和位元組陣列之間的相互轉換。
- CommandHandler:協議命令的處理器,命令處理入口,負責分發、處理命令。
- CommandFactory:協議命令工廠類,負責建立協議命令物件。
- HeartbeatTrigger:心跳的處理器,使用者使用者拓展特定的心跳機制的處理。
下面以 SOFABolt 中預設實現的 RPC 協議為例來介紹 SOFABolt 協議框架的實現。
3.1 請求的處理流程
一個請求處理流程大致如下:
- 通過 CommandFactory 構建請求物件
- 通過 CommandEncoder 對請求物件進行編碼,寫入到網路連線
- 服務端從連線中讀取資料,通過 CommandDecoder 解析成請求物件
- CommandHandler 接收請求物件,進行分發和處理

CommandFactory 是一個工廠類,比較簡單,不展開介紹。編解碼相關內容見 《SOFABolt編解碼機制》 。下面介紹一下CommandHandler 對請求的分發和處理。

上面是 SOFABolt 中 RpcHandler 的程式碼片段,這段程式碼是命令處理的入口:
- 首先從連線的上下文中獲取使用的協議的版本 ProtocolCode
- 再根據 ProtocolCode 從 ProtocolManager 中獲取具體的協議
- 之後從協議中獲取 CommandHandler,並構造請求的上下文資訊和請求的物件(程式碼片段中的msg)提交處理
上面的處理邏輯中透露出一個資訊:SOFABolt 支援同時執行多個版本的協議,通過 ProtocolCode 來區分協議。這一點可以使得系統在做升級或重構時,需要同時支援新老系統不同協議時變得簡單。

上面是 CommandHandler 的程式碼片段,透露出的資訊是 SOFABolt 支援批量提交請求,這在《SOFABolt 編解碼機制》一文中也有部分介紹。而具體的 process流程如下:

通過 Command 物件獲取 CommandCode,根據 CommandCode 獲取對應的RemotingProcessor 進行處理。
CommandCode是一個介面,只有一個返回 short 的value() 方法,表示Command的具體型別,每個請求都需要有自己的 CommandCode 來標識自己的型別。框架通過一個 Map 來維護 CommandCode 和 RemotingProcessor 的關係,每個 CommandCode 需要有對應的 RemotingProcessor 進行處理,一個 RemotingProcessor 可以處理多個 CommandCode 的請求。

再往下看一層,請求會被提交到RemotingProcessor中處理。上面是RpcRequestProcessor 處理請求的程式碼片段,處理流程中會通過cmd.getRequestClass()來獲取請求的物件的 Class 名稱,再獲取對應的UserProcess進行處理(具體處理不再上面的程式碼片段中)。
對使用者來說,只需要實現自己的 Command 物件、實現自己的 UserProcessor 並註冊到 ProcessorManager 中,就可以完成自己的網路通訊。
以上是一個請求在 SOFABolt 的協議框架下的處理流程和核心程式碼的分析。
3.2 協議框架的拓展機制
通過對請求處理流程的分析可以感受到 SOFABolt 的協議框架是支援多協議版本執行,能直接使用,也支援進行拓展來實現更豐富和定製化的功能。下面具體介紹SOFABolt 的拓展機制。

上圖是 RemotingCommand 在處理過程中的路由示意圖。第一層路由根據 ProtocolCode 進行,第二層路由根據 CmdCode 進行,第三層路由則根據 RequestClass 進行。使用者可以在每一層進行擴充套件來實現自己的處理。
這種設計具有很好的拓展性和靈活性,ProtocolCode 用於區分“大版本”的協議,適用於協議發生較大的變化的場景。CmdCode 則標識請求型別,比如在RPC場景中 CmdCode 可能就兩個:RPC_REQUEST、RPC_RESPONSE,而在訊息場景中CmdCode 可能會更豐富一些,比如有傳送訊息、批量傳送訊息、投遞訊息等等。RequestClass 是 Command上承載的資料的型別,使用者根據不同的類名進行不同的業務邏輯的實行。
實際應用中,以 RPC 的場景為例,使用者更多的是去實現 UserProcessor 來完成不同的業務邏輯的處理。而在訊息的場景中,因為訊息承載的是二進位制的資料,所以請求的資料型別是固定的,系統更多的是拓展 CmdCode 來執行不同型別的請求的處理,比如心跳請求的處理、寫入訊息的處理、批量寫入訊息的處理等等。SOFABolt 協議框架的設計和實現,具備較好的可拓展性,使其能應用於螞蟻的 RPC框架、訊息中心、分散式開關、配置中心等多箇中間件。
3.3 使用 SOFABolt 自定義協議
在瞭解了SOFABolt協議框架的基礎結構、請求處理流程、拓展機制後,我們來嘗試分析如何使用SOFABolt以更深入的理解它的協議框架。
下面以應用到 RPC 框架中為例進行分析。使用 SOFABolt 的第一步就是實現自己需要的 Command。因為 SOFABolt 中已經包含了預設的 RPC 協議的實現,所以在RPC 的場景中,並不需要拓展 Command 類。

SOFABolt 中也提供了CommandFactory 的預設實現:RpcCommandFactory,所以這塊也不需要進行拓展。

同樣的,SOFABolt中也包含了CommandEncoder和CommandDecoder 的實現,所以對於一個 RPC 應用而言,唯一需要拓展實現的就是在服務端註冊自己的UserProcessor:RpcServer#registerUserProcessor(UserProcessor)。

上面是 UserProcessor 相關的類圖,主要分兩類:註冊到單一資料型別上的 UserProcessor 和支援註冊到多個型別的 MultiInterestUserProcessor。
MultiInterestUserProcessor在 UserProcessor 的基礎上增加了multiInterest()方法,框架將此 Processor 註冊到 multiInterest() 方法返回的多個數據型別上,這樣便於一個 Processor 處理多種資料型別的請求的場景。
使用者只需要根據自己的需求,選擇是否使用 MultiInterestUserProcessor。再進一步根據是否需要同步處理來選擇繼承 Sync 或者 Async 的 UserProcessor 子類即可。那麼對於一個RPC的使用場景來說,實現 UserProcessor 並註冊到 RpcServer 和RpcClient即是所有的開發工作。
總結
本文首先對 SOFABolt 做了簡要的介紹,之後介紹了 SOFABolt 協議框架的整體結構、Command 的處理流程、拓展機制,之後通過分析如何使用 SOFABolt 來加深對 SOFABolt 協議框架及其拓展性的理解。
本文沒有展開說明 SOFABolt 中協議的細節,這個可以在 《 SOFABolt 編解碼機制》 中找到對應的解析。
《螞蟻金服通訊框架SOFABolt解析》系列歷史文章
和 SOFA 相遇,本週日活動推薦,座標上海

http:// weixin.qq.com/r/YymEnET E8xmMrQD-93xx (二維碼自動識別)
長按關注,獲取分散式架構乾貨
歡迎大家共同打造 SOFAStack https:// github.com/alipay