日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Seata RPC 模块的重构之路

發布時間:2025/3/20 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Seata RPC 模块的重构之路 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者 | 張乘輝
來源|阿里巴巴云原生公眾號

RPC 模塊是我最初研究 Seata 源碼開始的地方,因此我對 Seata 的 RPC 模塊有過一些深刻研究,在我研究了一番后,發現 RPC 模塊中的代碼需要進行優化,使得代碼更加優雅,交互邏輯更加清晰易懂,本著 “讓天下沒有難懂的 RPC 通信代碼” 的初衷,我開始了 RPC 模塊的重構之路。

這里建議想要深入了解 Seata 交互細節的,不妨從 RPC 模塊的源碼入手,RPC 模塊相當于 Seata 的中樞,Seata 所有的交互邏輯在 RPC 模塊中表現得淋漓盡致。

這次 RPC 模塊的重構將會使得 Seata 的中樞變得更加健壯和易于解讀。

重構繼承關系

在 Seata 的舊版本中,RPC 模塊的整體結構有點混亂,尤其是在各個類的繼承關系上,主要體現在:

  • 直接在 Remoting 類繼承 Netty Handler,使得 Remoting 類與 Netty Handler 處理邏輯耦合在一起。
  • 客戶端和服務端的 Reomting 類繼承關系不統一。
  • RemotingClient 被 RpcClientBootstrap 實現,而 RemotingServer 卻被 RpcServer 實現,沒有一個獨立的 ServerBootstrap,這個看起來關系非常混亂。
  • 有些接口沒必要抽取出來,比如 ClientMessageSender、ClientMessageListener、ServerMessageSender 等接口,因這些接口會增加整體結構繼承關系的復雜性。
  • 針對上面發現的問題,在重構過程中我大致做了如下事情:

  • 將 ?Netty Handler 抽象成一個內部類放在 Remoting 類中。
  • 將 RemotingClient 為客戶端頂級接口,定義客戶端與服務端交互的基本方法,抽象一層 AbstractNettyRemotingClient,下面分別有 RmNettyRemotingClient、TmNettyRemotingClient;將 RemotingServer 為服務端頂級接口,定義服務端與客戶端交互的基本方法,實現類 NettyRemotingServer。
  • 同時將 ClientMessageSender、ClientMessageListener、ServerMessageSender 等接口方法歸入到 RemotingClient、RemotingServer 中,由 Reomting 類實現 RemotingClient、RemotingServer,統一 Remoting 類繼承關系。
  • 新建 RemotingBootstrap 接口,客戶端和服務端分別實現 NettyClientBootstrap、NettyServerBootstrap,將引導類邏輯從 Reomting 類抽離出來。
  • 在最新的 RPC 模塊中的繼承關系簡單清晰,用如下類關系圖表示:

  • AbstractNettyRemoting:Remoting 類的最頂層抽象,包含了客戶端和服務端公用的成員變量與公用方法,擁有通用的請求方法(文章后面會講到),Processor 處理器調用邏輯(文章后面會講到)。
  • RemotingClient:客戶端最頂級接口,定義客戶端與服務端交互的基本方法。
  • RemotingServer:服務端最頂級接口,定義服務端與客戶端交互的基本方法。
  • AbstractNettyRemotingClient:客戶端抽象類,繼承 AbstractNettyRemoting 類并實現了 RemotingClient 接口。
  • NettyRemotingServer:服務端實現類,繼承 AbstractNettyRemoting 類并實現了 RemotingServer 接口。
  • RmNettyRemotingClient:Rm 客戶端實現類,繼承 AbstractNettyRemotingClient 類。
  • TmNettyRemotingClient:Tm 客戶端實現類,繼承 AbstractNettyRemotingClient 類。
  • 同時將客戶端和服務端的引導類邏輯抽象出來,如下類關系圖表示:

  • RemotingBootstrap:引導類接口,有 start 和 stop 兩個抽象方法。
  • NettyClientBootstrap:客戶端引導實現類。
  • NettyServerBootstrap:服務端引導實現類。
  • 解耦處理邏輯

    解耦處理邏輯即是將 RPC 交互的處理邏輯從 Netty Handler 中抽離出來,并將處理邏輯抽象成一個個 Processor,為什么要這么做呢?我大致講下現在存在的一些問題:

  • Netty Handler 與 處理邏輯是糅合在一起的,由于客戶端與服務端都共用了一套處理邏輯,因此為了兼容更多的交互,在處理邏輯中你可以看到非常多難以理解的判斷邏輯。
  • 在 Seata 的交互中有些請求是異步處理的,也有一些請求是同步處理的,但是在舊的處理代碼邏輯中對同步異步處理的表達非常隱晦,而且難以看明白。
  • 無法從代碼邏輯當中清晰地表達出請求消息類型與對應的處理邏輯關系。
  • 在 Seata 后面的更新迭代中,如果不將處理處理邏輯抽離出來,這部分代碼想要增加新的交互邏輯,將會非常困難。
  • 在將處理邏輯從 Netty Handler 進行抽離之前,我們先梳理一下 Seata 現有的交互邏輯。

    • RM 客戶端請求服務端的交互邏輯:

    • TM 客戶端請求服務端的交互邏輯:

    • 服務端請求 RM 客戶端的交互邏輯:

    從以上的交互圖中可以清晰地看到了 Seata 的交互邏輯。

    客戶端總共接收服務端的消息:

    1)服務端請求消息

    • BranchCommitRequest、BranchRollbackRequest、UndoLogDeleteRequest

    2)服務端響應消息

    • RegisterRMResponse、BranchRegisterResponse、BranchReportResponse、GlobalLockQueryResponse
    • RegisterTMResponse、GlobalBeginResponse、GlobalCommitResponse、GlobalRollbackResponse、GlobalStatusResponse、GlobalReportResponse
    • HeartbeatMessage(PONG)

    服務端總共接收客戶端的消息:

    1)客戶端請求消息

    • RegisterRMRequest、BranchRegisterRequest、BranchReportRequest、GlobalLockQueryRequest
    • RegisterTMRequest、GlobalBeginRequest、GlobalCommitRequest、GlobalRollbackRequest、GlobalStatusRequest、GlobalReportRequest
    • HeartbeatMessage(PING)

    2)客戶端響應消息

    • BranchCommitResponse、BranchRollbackResponse

    基于以上的交互邏輯分析,我們可以將處理消息的邏輯抽象成若干個 Processor,一個 Processor 可以處理一個或者多個消息類型的消息,只需在 Seata 啟動時注冊將消息類型注冊到 ProcessorTable 中即可,形成一個映射關系,這樣就可以根據消息類型調用對應的 Processor 對消息進行處理,用如下圖表示:

    在抽象 Remoting 類中定一個 processMessage 方法,方法邏輯是根據消息類型從 ProcessorTable 中拿到消息類型對應的 Processor。

    這樣就成功將處理邏輯從 Netty Handler 中徹底抽離出來了,Handler#channelRead 方法只需要調用 processMessage 方法即可,且還可以靈活根據消息類型動態注冊 Processor 到 ProcessorTable 中,處理邏輯的可擴展性得到了極大的提升。

    以下是 Processor 的調用流程:

    1)客戶端

    • RmBranchCommitProcessor:處理服務端全局提交請求。
    • RmBranchRollbackProcessor:處理服務端全局回滾請求。
    • RmUndoLogProcessor:處理服務端 undo log 刪除請求。
    • ClientOnResponseProcessor:客戶端處理服務端響應請求,如:BranchRegisterResponse、GlobalBeginResponse、GlobalCommitResponse 等。
    • ClientHeartbeatProcessor:處理服務端心跳響應。

    2)服務端

    • RegRmProcessor:處理 RM 客戶端注冊請求。
    • RegTmProcessor:處理 TM 客戶端注冊請求。
    • ServerOnRequestProcessor:處理客戶端相關請求,如:BranchRegisterRequest、GlobalBeginRequest、GlobalLockQueryRequest 等。
    • ServerOnResponseProcessor:處理客戶端相關響應,如:BranchCommitResponse、BranchRollbackResponse 等。
    • ServerHeartbeatProcessor:處理客戶端心跳響應。

    下面我以 TM 發起全局事務提交請求為例子,讓大家感受下 Processor 在整個交互中所處的位置:

    重構請求方法

    在 Seata 的舊版本當中,RPC 的請求方法也是欠缺優雅,主要體現在:

  • 請求方法過于雜亂無章,沒有層次感。
  • sendAsyncRequest 方法耦合的代碼太多,邏輯過于混亂,客戶端與服務端都共用了一套請求邏輯,方法中決定是否批量發送是根據參數 address 是否為 null 決定,決定是否同步請求是根據 timeout 是否大于 0 決定,顯得極為不合理,且批量請求只有客戶端有用到,服務端并沒有批量請求,共用一套請求邏輯還會導致服務端異步請求也會創建 MessageFuture 放入 futures 中。
  • 請求方法名稱風格不統一,比如客戶端 sendMsgWithResponse,服務端卻叫 sendSyncRequest;
  • 針對以上舊版本 RPC 請求方法的各種缺點,我作了以下改動:

  • 將請求方法統一放入 RemotingClient、RemotingServer 接口當中,并作為頂級接口;
  • 分離客戶端與服務端請求邏輯,將批量請求邏輯單獨抽到客戶端相關請求方法中,使得是否批量發送不再根據參數 address 是否為 null 決定;
  • 由于 Seata 自身的邏輯特點,客戶端服務端請求方法的參數無法統一,可通過抽取通用的同步/異步請求方法,客戶端和服務端根據自身請求邏輯特點實現自身的同步/異步請求邏輯,最后再調用通用的同步/異步請求方法,使得同步/異步請求都有明確的方法,不再根據 timeout 是否大于 0 決定;
  • 統一請求名稱風格。
  • 最終,Seata RPC 的請求方法終于看起來更加優雅且有層次感了。

    同步請求:

    異步請求:

    其它

  • 類目錄調整:RPC 模塊目錄中還有一個 netty 目錄,也可以從目錄結構中發現 Seata 的初衷是兼容多個 RPC 框架,目前只實現了 netty,但發現 netty 模塊中有些類并不 ”netty“,且 RPC 跟目錄的類也并不通用,因此需要將相關類的位置進行調整。
  • 某些類重新命名,比如 netty 相關類包含 「netty」。
  • 最終 RPC 模塊看起來是這樣的:

    更多詳情可訪問?Seata?官網進行了解。

    總結

    以上是生活随笔為你收集整理的Seata RPC 模块的重构之路的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。