Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Example Analysis of Seata RPC Module

2025-03-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)05/31 Report--

Today, I will talk to you about the example analysis of the Seata RPC module, many people may not know much about it. In order to make you understand better, the editor has summarized the following content for you. I hope you can get something according to this article.

The RPC module is where I first studied the Seata source code, so I have done some deep research on the RPC module of Seata. After studying it, I found that the code in the RPC module needs to be optimized to make the code more elegant and the interaction logic more clear and easy to understand. In line with the original intention of "there is no difficult RPC communication code in the world", I started the road of refactoring the RPC module.

It is suggested that if you want to have an in-depth understanding of the details of Seata interaction, you might as well start with the source code of the RPC module, the RPC module is equivalent to the hub of Seata, and all the interaction logic of Seata is shown incisively and vividly in the RPC module.

This refactoring of the RPC module will make the hub of Seata more robust and easy to interpret.

Reconstruct inheritance relationship

In the old version of Seata, the overall structure of the RPC module was a bit confusing, especially in terms of the inheritance of the various classes, mainly reflected in:

Inherit Netty Handler directly from the Remoting class, making the Remoting class coupled to the Netty Handler processing logic.

The Reomting class inheritance relationship between the client and the server is not uniform.

RemotingClient is implemented by RpcClientBootstrap, while RemotingServer is implemented by RpcServer, without a separate ServerBootstrap, which seems to be very confusing.

Some interfaces do not need to be extracted, such as ClientMessageSender, ClientMessageListener, ServerMessageSender, and so on, because these interfaces will increase the complexity of the overall structural inheritance relationship.

In view of the problems found above, I roughly did the following things in the process of refactoring:

Abstract the Netty Handler into an inner class and put it in the Remoting class.

Take RemotingClient as the top-level interface of the client, define the basic method of interaction between the client and the server, abstract a layer of AbstractNettyRemotingClient, below, RmNettyRemotingClient and TmNettyRemotingClient; respectively regard RemotingServer as the top-level interface of the server, define the basic method of interaction between the server and the client, and implement the class NettyRemotingServer.

At the same time, interface methods such as ClientMessageSender, ClientMessageListener and ServerMessageSender are grouped into RemotingClient and RemotingServer, and RemotingClient and RemotingServer are implemented by Reomting class to unify the inheritance relationship of Remoting class.

Create a new RemotingBootstrap interface, and the client and server implement NettyClientBootstrap and NettyServerBootstrap, respectively, to extract the boot class logic from the Reomting class.

The inheritance relationship in the latest RPC module is simple and clear, represented by the following class diagram:

The top-level abstraction of the AbstractNettyRemoting:Remoting class, which contains member variables and common methods common to both the client and server, has a common request method (described later in the article), and Processor processor invocation logic (discussed later in the article).

RemotingClient: the top-level interface of the client, defining the basic method of interaction between the client and the server.

RemotingServer: the top-level interface on the server side, which defines the basic method for the server to interact with the client.

AbstractNettyRemotingClient: a client-side abstract class that inherits the AbstractNettyRemoting class and implements the RemotingClient interface.

NettyRemotingServer: server-side implementation class that inherits the AbstractNettyRemoting class and implements the RemotingServer interface.

The RmNettyRemotingClient:Rm client implementation class inherits the AbstractNettyRemotingClient class.

The TmNettyRemotingClient:Tm client implementation class inherits the AbstractNettyRemotingClient class.

At the same time, the boot class logic of the client and the server is abstracted, as shown in the following class diagram:

RemotingBootstrap: bootstrap class interface with two abstract methods, start and stop.

NettyClientBootstrap: the client guides the implementation class.

NettyServerBootstrap: the server guides the implementation class.

Decoupling processing logic

Decoupling processing logic is to extract the processing logic of RPC interaction from the Netty Handler and abstract the processing logic into Processor. Why do you do this? I would like to outline some of the problems that exist today:

Netty Handler and processing logic are mixed together. Because both the client and the server share a set of processing logic, in order to be compatible with more interactions, you can see a lot of incomprehensible judgment logic in the processing logic.

In Seata interactions, some requests are handled asynchronously and others synchronously, but the expression of synchronous and asynchronous processing in the old processing code logic is very obscure and difficult to understand.

The relationship between the request message type and the corresponding processing logic cannot be clearly expressed from the code logic.

In the update iterations that follow Seata, it will be very difficult for this part of the code to add new interaction logic without pulling out the processing logic.

Before we pull the processing logic away from Netty Handler, let's comb through the existing interaction logic of Seata.

The RM client requests the interaction logic of the server:

The TM client requests the interaction logic of the server:

The server requests the RM client's interaction logic:

From the above interaction diagram, you can clearly see the interaction logic of Seata.

The client receives a total of messages from the server:

1) Server request message

BranchCommitRequest 、 BranchRollbackRequest 、 UndoLogDeleteRequest

2) Server response message

RegisterRMResponse 、 BranchRegisterResponse 、 BranchReportResponse 、 GlobalLockQueryResponse

RegisterTMResponse 、 GlobalBeginResponse 、 GlobalCommitResponse 、 GlobalRollbackResponse 、 GlobalStatusResponse 、 GlobalReportResponse

HeartbeatMessage (PONG)

The server receives a total of messages from the client:

1) client request message

RegisterRMRequest 、 BranchRegisterRequest 、 BranchReportRequest 、 GlobalLockQueryRequest

RegisterTMRequest 、 GlobalBeginRequest 、 GlobalCommitRequest 、 GlobalRollbackRequest 、 GlobalStatusRequest 、 GlobalReportRequest

HeartbeatMessage (PING)

2) client response message

BranchCommitResponse 、 BranchRollbackResponse

Based on the above interaction logic analysis, we can abstract the logic of processing messages into several Processor. A Processor can handle messages of one or more message types. You only need to register the message type into ProcessorTable when the Seata is started to form a mapping relationship. In this way, you can call the corresponding Processor according to the message type to process the message, as shown in the following figure:

Specify a processMessage method in the abstract Remoting class, and the method logic is to get the Processor corresponding to the message type from the ProcessorTable according to the message type.

In this way, the processing logic is completely extracted from the Netty Handler. The Handler#channelRead method only needs to call the processMessage method, and it can also flexibly register the Processor to the ProcessorTable according to the message type. The scalability of the processing logic has been greatly improved.

The following is the process of invoking Processor:

1) client

RmBranchCommitProcessor: handles the server's global submission request.

RmBranchRollbackProcessor: handles server-side global rollback requests.

RmUndoLogProcessor: handles server-side undo log deletion requests.

ClientOnResponseProcessor: the client handles server response requests, such as BranchRegisterResponse, GlobalBeginResponse, GlobalCommitResponse, etc.

ClientHeartbeatProcessor: handles the server heartbeat response.

2) Server side

RegRmProcessor: handles RM client registration requests.

RegTmProcessor: handles TM client registration requests.

ServerOnRequestProcessor: handles client-related requests, such as BranchRegisterRequest, GlobalBeginRequest, GlobalLockQueryRequest, etc.

ServerOnResponseProcessor: handle client-related responses, such as BranchCommitResponse, BranchRollbackResponse, etc.

ServerHeartbeatProcessor: handles the client heartbeat response.

Let me take the global transaction commit request initiated by TM as an example to let you feel the position of Processor in the whole interaction:

Refactoring request method

In the old version of Seata, the request method of RPC was also lack of elegance, mainly reflected in:

The request method is too disorganized and unhierarchical.

There is too much code coupled by the sendAsyncRequest method, and the logic is too confusing. Both the client and the server share a set of request logic. In the method, the decision on whether to send a batch is based on whether the parameter address is null or not, and it is extremely unreasonable to decide whether the synchronous request is based on whether the timeout is greater than 0, and the batch request is available only to the client, but not to the server. Sharing a set of request logic can also cause server-side asynchronous requests to create a MessageFuture and put it into the futures.

The style of the request method name is different, for example, the client side sendMsgWithResponse, but the server side is called sendSyncRequest.

In view of the shortcomings of the previous version of the RPC request method, I made the following changes:

Put the request method into the RemotingClient and RemotingServer interfaces as the top-level interface

Separate the client-side and server-side request logic, and separate the batch request logic into the client-side related request methods, so that whether to send a batch is no longer determined according to whether the parameter address is null or not.

Due to the logic characteristics of Seata itself, the parameters of the client server request method can not be unified. By extracting the general synchronous / asynchronous request method, the client and the server can implement their own synchronous / asynchronous request logic according to their own request logic characteristics. Finally, the general synchronous / asynchronous request method is called, so that the synchronous / asynchronous request has a clear method and is no longer determined according to whether the timeout is greater than 0.

Uniform request name style.

In the end, Seata RPC's request method finally looks more elegant and hierarchical.

Synchronization request:

Asynchronous request:

Other

Class directory adjustment: there is also a netty directory in the RPC module directory. It can also be found from the directory structure that Seata's original intention is to be compatible with multiple RPC frameworks. At present, only netty is implemented, but it is found that some classes in the netty module are not "netty", and the RPC and directory classes are not common, so the location of related classes needs to be adjusted.

Some classes are renamed, such as netty-related classes that contain "netty".

The final RPC module looks like this:

After reading the above, do you have any further understanding of the example analysis of the Seata RPC module? If you want to know more knowledge or related content, please follow the industry information channel, thank you for your support.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report