From aea11bebd249e1329045da01cdb8b40e4a65cb10 Mon Sep 17 00:00:00 2001 From: hein Date: Sat, 21 Dec 2024 11:50:26 +0800 Subject: [PATCH] seata-rpc-analysis (#929) --- blog/seata-rpc-analysis.md | 1 + .../seata-rpc-analysis.md | 1912 +++++++++++++++++ .../seata-rpc-analysis.md | 1912 +++++++++++++++++ static/img/blog/class-level.png | Bin 0 -> 70810 bytes static/img/blog/seata-channel.png | Bin 0 -> 91113 bytes static/img/blog/seata-protocol.png | Bin 0 -> 41387 bytes static/img/blog/seata-rpc.png | Bin 0 -> 80867 bytes 7 files changed, 3825 insertions(+) create mode 100644 blog/seata-rpc-analysis.md create mode 100644 i18n/en/docusaurus-plugin-content-blog/seata-rpc-analysis.md create mode 100644 i18n/zh-cn/docusaurus-plugin-content-blog/seata-rpc-analysis.md create mode 100644 static/img/blog/class-level.png create mode 100644 static/img/blog/seata-channel.png create mode 100644 static/img/blog/seata-protocol.png create mode 100644 static/img/blog/seata-rpc.png diff --git a/blog/seata-rpc-analysis.md b/blog/seata-rpc-analysis.md new file mode 100644 index 00000000000..e872b67af1f --- /dev/null +++ b/blog/seata-rpc-analysis.md @@ -0,0 +1 @@ +Placeholder. DO NOT DELETE. \ No newline at end of file diff --git a/i18n/en/docusaurus-plugin-content-blog/seata-rpc-analysis.md b/i18n/en/docusaurus-plugin-content-blog/seata-rpc-analysis.md new file mode 100644 index 00000000000..f1979dde9d9 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-blog/seata-rpc-analysis.md @@ -0,0 +1,1912 @@ +--- +title: Getting Started with Seata Network Communication Source Code +keywords: [Seata, RPC, Source Code, Distributed Transactions] +description: A comprehensive introductory analysis of Seata's RPC source code +author: Jin He +date: 2024-12-18 +--- + +In the previous articles, we have thoroughly discussed Seata's XA, AT, and TCC modes, all of which are different transaction models defined within the global framework of Seata. + +We know that in Seata, there are three types of roles: TC (Transaction Coordinator), RM (Resource Manager), and TM (Transaction Manager). The Seata Server acts as a TC to coordinate the commit and rollback of branch transactions, while various resources act as RMs and TMs. So, how do these three communicate with each other? + +Therefore, this article will explore how Seata performs network communication at the underlying level. + +## Overall Class Hierarchy Structure + +Let's start by looking at the big picture, examining the overall RPC class hierarchy structure of Seata. + +![image-20241217222005964](/img/blog/class-level.png) + +From the class hierarchy structure, it can be seen that AbstractNettyRemoting is the top-level abstract class for the entire Seata network communication. + +In this class, some basic common methods of RPC are mainly implemented, such as synchronous call sendSync, asynchronous call sendAsync, etc. + +Indeed, when it comes to network calls, they essentially boil down to synchronous calls and asynchronous calls; other aspects like requests and responses are just distinctions in message content. + +So, in Seata, I personally think there should also be a top-level interface Remoting, similar to the following: + +```java +import io.netty.channel.Channel; +import java.util.concurrent.TimeoutException; + +public interface Remoting { + + /** + * Synchronous call + */ + Resp sendSync(Channel channel, Req request, long timeout) throws TimeoutException; + + /** + * Asynchronous call + */ + void sendAsync(Channel channel, Req request); +} +``` + +While AbstractNettyRemoting implements general network calling methods, there are still some differences among different roles. For example, for the server, its request call needs to know which client to send to, whereas for the TM and RM, they can simply send requests without specifying a particular TC service. They only need to find an appropriate server node via a load balancing algorithm in the implementation class. + +Thus, RemotingServer and RemotingClient are differentiated, but they still rely on AbstractNettyRemoting for network calls at the bottom layer, so each has subclasses that implement AbstractNettyRemoting. + +One might say that this design in Seata is quite commendable, serving as a general solution pattern for remote communications in this kind of Client-Server architecture. + +## How to Start the Server and Client + +After discussing the underlying class hierarchy of Seata, let's look from the perspectives of the Server and Client on how they start up and what needs to be done during startup. + +### How the Server Starts + +As an independent Spring Boot project, how does the Seata Server automatically perform certain tasks when Spring Boot starts? + +Seata achieves this by implementing the `CommandLineRunner` interface. The principle behind this is not within the scope of this article. + +We mainly focus on its `run` method: + +```java +// org.apache.seata.server.ServerRunner#run +public void run(String... args) { + try { + long start = System.currentTimeMillis(); + seataServer.start(args); + started = true; + long cost = System.currentTimeMillis() - start; + LOGGER.info("\r\n you can visit seata console UI on http://127.0.0.1:{}. \r\n log path: {}.", this.port, this.logPath); + LOGGER.info("seata server started in {} millSeconds", cost); + } catch (Throwable e) { + started = Boolean.FALSE; + LOGGER.error("seata server start error: {} ", e.getMessage(), e); + System.exit(-1); + } +} +``` + +The core logic lies within the `seataServer.start()` method: + +```java +// org.apache.seata.server.Server#start +public void start(String[] args) { + // Parameter parser used to parse startup parameters from the shell script + ParameterParser parameterParser = new ParameterParser(args); + // Initialize metrics + MetricsManager.get().init(); + ThreadPoolExecutor workingThreads = new ThreadPoolExecutor( + NettyServerConfig.getMinServerPoolSize(), + NettyServerConfig.getMaxServerPoolSize(), + NettyServerConfig.getKeepAliveTime(), TimeUnit.SECONDS, + new LinkedBlockingQueue<>(NettyServerConfig.getMaxTaskQueueSize()), + new NamedThreadFactory("ServerHandlerThread", NettyServerConfig.getMaxServerPoolSize()), + new ThreadPoolExecutor.CallerRunsPolicy()); + // 127.0.0.1 and 0.0.0.0 are not valid here. + if (NetUtil.isValidIp(parameterParser.getHost(), false)) { + XID.setIpAddress(parameterParser.getHost()); + } else { + String preferredNetworks = ConfigurationFactory.getInstance().getConfig(REGISTRY_PREFERED_NETWORKS); + if (StringUtils.isNotBlank(preferredNetworks)) { + XID.setIpAddress(NetUtil.getLocalIp(preferredNetworks.split(REGEX_SPLIT_CHAR))); + } else { + XID.setIpAddress(NetUtil.getLocalIp()); + } + } + + /** + * Main tasks performed: + * 1. Set workingThreads as the messageExecutor handler for AbstractNettyRemoting + * 2. Create ServerBootstrap, configure Boss and Worker, and set the port that the Seata Server listens on + * 3. Set outbound and inbound handlers ServerHandler, which is a composite handler of ChannelDuplexHandler + */ + NettyRemotingServer nettyRemotingServer = new NettyRemotingServer(workingThreads); + XID.setPort(nettyRemotingServer.getListenPort()); + UUIDGenerator.init(parameterParser.getServerNode()); + ConfigurableListableBeanFactory beanFactory = ((GenericWebApplicationContext) ObjectHolder.INSTANCE.getObject(OBJECT_KEY_SPRING_APPLICATION_CONTEXT)).getBeanFactory(); + DefaultCoordinator coordinator = DefaultCoordinator.getInstance(nettyRemotingServer); + if (coordinator instanceof ApplicationListener) { + beanFactory.registerSingleton(NettyRemotingServer.class.getName(), nettyRemotingServer); + beanFactory.registerSingleton(DefaultCoordinator.class.getName(), coordinator); + ((GenericWebApplicationContext) ObjectHolder.INSTANCE.getObject(OBJECT_KEY_SPRING_APPLICATION_CONTEXT)).addApplicationListener((ApplicationListener) coordinator); + } + // Log store mode: file, db, redis + SessionHolder.init(); + LockerManagerFactory.init(); + // Initialize a series of scheduled thread pools for retrying transaction commit/rollback, etc. + coordinator.init(); + // Set the transaction processing Handler to DefaultCoordinator + nettyRemotingServer.setHandler(coordinator); + serverInstance.serverInstanceInit(); + // Let ServerRunner handle destruction instead of ShutdownHook, see https://github.com/seata/seata/issues/4028 + ServerRunner.addDisposable(coordinator); + // Server initialization + nettyRemotingServer.init(); +} +``` + +The final `nettyRemotingServer.init()` is crucial for starting the entire Seata Server, primarily performing the following tasks: + +1. Register a series of handlers +2. Initialize a scheduled thread pool for cleaning up expired MessageFuture objects +3. Start the ServerBootstrap and register the TC service with the registry center, such as Nacos + +#### Registering Processors + +Within Seata, a `Pair` object is used to associate a processor with an executor (thread pool), as shown below: + +```java +package org.apache.seata.core.rpc.processor; + +public final class Pair { + + private final T1 first; + private final T2 second; + + public Pair(T1 first, T2 second) { + this.first = first; + this.second = second; + } + + public T1 getFirst() { + return first; + } + + public T2 getSecond() { + return second; + } +} +``` + +Registering processors essentially involves associating message types, the processors that handle those messages, and the specific thread pools for execution, all stored in a hash table. + +```java +// AbstractNettyRemotingServer +protected final Map> processorTable = new HashMap<>(32); +``` + +```java +// org.apache.seata.core.rpc.netty.NettyRemotingServer#registerProcessor +private void registerProcessor() { + // 1. Register request message processors + ServerOnRequestProcessor onRequestProcessor = new ServerOnRequestProcessor(this, getHandler()); + ShutdownHook.getInstance().addDisposable(onRequestProcessor); + super.registerProcessor(MessageType.TYPE_BRANCH_REGISTER, onRequestProcessor, messageExecutor); + super.registerProcessor(MessageType.TYPE_BRANCH_STATUS_REPORT, onRequestProcessor, messageExecutor); + super.registerProcessor(MessageType.TYPE_GLOBAL_BEGIN, onRequestProcessor, messageExecutor); + super.registerProcessor(MessageType.TYPE_GLOBAL_COMMIT, onRequestProcessor, messageExecutor); + super.registerProcessor(MessageType.TYPE_GLOBAL_LOCK_QUERY, onRequestProcessor, messageExecutor); + super.registerProcessor(MessageType.TYPE_GLOBAL_REPORT, onRequestProcessor, messageExecutor); + super.registerProcessor(MessageType.TYPE_GLOBAL_ROLLBACK, onRequestProcessor, messageExecutor); + super.registerProcessor(MessageType.TYPE_GLOBAL_STATUS, onRequestProcessor, messageExecutor); + super.registerProcessor(MessageType.TYPE_SEATA_MERGE, onRequestProcessor, messageExecutor); + // 2. Register response message processors + ServerOnResponseProcessor onResponseProcessor = new ServerOnResponseProcessor(getHandler(), getFutures()); + super.registerProcessor(MessageType.TYPE_BRANCH_COMMIT_RESULT, onResponseProcessor, branchResultMessageExecutor); + super.registerProcessor(MessageType.TYPE_BRANCH_ROLLBACK_RESULT, onResponseProcessor, branchResultMessageExecutor); + // 3. Register RM message processors + RegRmProcessor regRmProcessor = new RegRmProcessor(this); + super.registerProcessor(MessageType.TYPE_REG_RM, regRmProcessor, messageExecutor); + // 4. Register TM message processors + RegTmProcessor regTmProcessor = new RegTmProcessor(this); + super.registerProcessor(MessageType.TYPE_REG_CLT, regTmProcessor, null); + // 5. Register heartbeat message processors + ServerHeartbeatProcessor heartbeatMessageProcessor = new ServerHeartbeatProcessor(this); + super.registerProcessor(MessageType.TYPE_HEARTBEAT_MSG, heartbeatMessageProcessor, null); +} + +// org.apache.seata.core.rpc.netty.AbstractNettyRemotingServer#registerProcessor +public void registerProcessor(int messageType, RemotingProcessor processor, ExecutorService executor) { + Pair pair = new Pair<>(processor, executor); + this.processorTable.put(messageType, pair); +} +``` + +You might notice that during the registration of some processors, the passed-in thread pool is `null`. In such cases, which thread will execute the corresponding message? + +We will discuss this in a later section. + +#### Initializing the Scheduled Thread Pool + +```java +// org.apache.seata.core.rpc.netty.AbstractNettyRemoting#init +public void init() { + timerExecutor.scheduleAtFixedRate(() -> { + for (Map.Entry entry : futures.entrySet()) { + MessageFuture future = entry.getValue(); + if (future.isTimeout()) { + futures.remove(entry.getKey()); + RpcMessage rpcMessage = future.getRequestMessage(); + future.setResultMessage(new TimeoutException(String.format("msgId: %s, msgType: %s, msg: %s, request timeout", + rpcMessage.getId(), String.valueOf(rpcMessage.getMessageType()), rpcMessage.getBody().toString()))); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("timeout clear future: {}", entry.getValue().getRequestMessage().getBody()); + } + } + } + nowMills = System.currentTimeMillis(); + }, TIMEOUT_CHECK_INTERVAL, TIMEOUT_CHECK_INTERVAL, TimeUnit.MILLISECONDS); +} +``` + +There's not much to explain here—it initializes a scheduled thread pool that periodically cleans up timed-out `MessageFuture` objects. The `MessageFuture` is key to Seata converting asynchronous calls into synchronous ones, which we will discuss in detail later. + +#### Starting the ServerBootstrap + +Finally, starting the `ServerBootstrap` is mostly related to Netty. + +```java +// org.apache.seata.core.rpc.netty.NettyServerBootstrap#start +public void start() { + int port = getListenPort(); + this.serverBootstrap.group(this.eventLoopGroupBoss, this.eventLoopGroupWorker) + .channel(NettyServerConfig.SERVER_CHANNEL_CLAZZ) + .option(ChannelOption.SO_BACKLOG, nettyServerConfig.getSoBackLogSize()) + .option(ChannelOption.SO_REUSEADDR, true) + .childOption(ChannelOption.SO_KEEPALIVE, true) + .childOption(ChannelOption.TCP_NODELAY, true) + .childOption(ChannelOption.SO_SNDBUF, nettyServerConfig.getServerSocketSendBufSize()) + .childOption(ChannelOption.SO_RCVBUF, nettyServerConfig.getServerSocketResvBufSize()) + .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(nettyServerConfig.getWriteBufferLowWaterMark(), nettyServerConfig.getWriteBufferHighWaterMark())) + .localAddress(new InetSocketAddress(port)) + .childHandler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) { + // Multi-version protocol decoder + MultiProtocolDecoder multiProtocolDecoder = new MultiProtocolDecoder(channelHandlers); + ch.pipeline() + .addLast(new IdleStateHandler(nettyServerConfig.getChannelMaxReadIdleSeconds(), 0, 0)) + .addLast(multiProtocolDecoder); + } + }); + try { + this.serverBootstrap.bind(port).sync(); + LOGGER.info("Server started, service listen port: {}", getListenPort()); + InetSocketAddress address = new InetSocketAddress(XID.getIpAddress(), XID.getPort()); + for (RegistryService registryService : MultiRegistryFactory.getInstances()) { + // Register service + registryService.register(address); + } + initialized.set(true); + } catch (SocketException se) { + throw new RuntimeException("Server start failed, the listen port: " + getListenPort(), se); + } catch (Exception exx) { + throw new RuntimeException("Server start failed", exx); + } +} +``` + +The `childOption` settings during the startup of `ServerBootstrap` belong to the networking part and won't be explained in depth here. + +You might have a question regarding why only a `MultiProtocolDecoder` is added to the pipeline, what about the business handler? + +In fact, the `channelHandlers` passed into the constructor of `MultiProtocolDecoder` include the `ServerHandler`, which is set when creating the `NettyRemotingServer`. + +This approach is related to Seata's multi-version protocol support. + +When the Seata Server decodes messages for the first time after starting, it removes the `MultiProtocolDecoder` from the pipeline and adds specific `Encoder` and `Decoder` based on the version to the pipeline. At this point, the `ServerHandler` is also added to the pipeline. + +### How the Client Starts + +For the Client, since we typically use Seata within a Spring Boot application, our focus lies within the `SeataAutoConfiguration` class. + +In this class, a `GlobalTransactionScanner` object is created. Notably, it implements `InitializingBean`, so we turn our attention to the `afterPropertiesSet` method. + +Indeed, within this method, the initialization of TM (Transaction Manager) and RM (Resource Manager) takes place. + +#### Initialization of TM + +For TM, the initialization logic is as follows: + +```java +public static void init(String applicationId, String transactionServiceGroup, String accessKey, String secretKey) { + /** + * Main tasks include: + * 1. Creating a thread pool as the messageExecutor for AbstractNettyRemotingClient + * 2. Setting the transaction role transactionRole to TM_ROLE + * 3. Creating Bootstrap and setting outbound and inbound handlers ClientHandler + * 4. Creating a client Channel manager NettyClientChannelManager + */ + TmNettyRemotingClient tmNettyRemotingClient = TmNettyRemotingClient.getInstance(applicationId, transactionServiceGroup, accessKey, secretKey); + + /** + * Main tasks include: + * 1. Registering a series of processors + * 2. Creating a scheduled thread pool that periodically initiates connections to servers within the transaction group; if the connection is broken, it tries to reconnect + * 3. If the client allows batch message sending, creating a mergeSendExecutorService thread pool and submitting MergedSendRunnable tasks + * 4. Initializing a scheduled thread pool to clean up expired MessageFuture objects + * 5. Starting the client Bootstrap + * 6. Initializing connections initConnection + */ + tmNettyRemotingClient.init(); +} +``` + +The logic for starting the client Bootstrap is as follows: + +```java +@Override +public void start() { + if (this.defaultEventExecutorGroup == null) { + this.defaultEventExecutorGroup = new DefaultEventExecutorGroup(nettyClientConfig.getClientWorkerThreads(), + new NamedThreadFactory(getThreadPrefix(nettyClientConfig.getClientWorkerThreadPrefix()), nettyClientConfig.getClientWorkerThreads())); + } + this.bootstrap.group(this.eventLoopGroupWorker) + .channel(nettyClientConfig.getClientChannelClazz()) + .option(ChannelOption.TCP_NODELAY, true) + .option(ChannelOption.SO_KEEPALIVE, true) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, nettyClientConfig.getConnectTimeoutMillis()) + .option(ChannelOption.SO_SNDBUF, nettyClientConfig.getClientSocketSndBufSize()) + .option(ChannelOption.SO_RCVBUF, nettyClientConfig.getClientSocketRcvBufSize()); + if (nettyClientConfig.enableNative()) { + if (PlatformDependent.isOsx()) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("client run on macOS"); + } + } else { + bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED) + .option(EpollChannelOption.TCP_QUICKACK, true); + } + } + bootstrap.handler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) { + ch.pipeline().addLast(new IdleStateHandler(nettyClientConfig.getChannelMaxReadIdleSeconds(), + nettyClientConfig.getChannelMaxWriteIdleSeconds(), + nettyClientConfig.getChannelMaxAllIdleSeconds())) + .addLast(new ProtocolDecoderV1()) + .addLast(new ProtocolEncoderV1()); + if (channelHandlers != null) { + addChannelPipelineLast(ch, channelHandlers); + } + } + }); + if (initialized.compareAndSet(false, true) && LOGGER.isInfoEnabled()) { + LOGGER.info("NettyClientBootstrap has started"); + } +} +``` + +Since the protocol version for the client can be determined based on different versions of Seata, V1 version encoders and decoders are directly added here. The `channelHandlers` are actually the `ClientHandler`, which is also a composite handler in Netty. + +#### Initialization of RM + +The initialization logic for RM is largely similar to that of TM and will not be elaborated on further here. + +## How Messages Are Sent and Handled + +After understanding the general startup processes of the Seata Server and Client, we can delve deeper into how Seata sends and handles messages. + +We mentioned earlier that the core logic for sending requests and processing messages lies within `AbstractNettyRemoting`. Let's take a closer look at this class. + +### Synchronous and Asynchronous + +First, let's briefly discuss what synchronous and asynchronous mean. + +Synchronous (Synchronous) and Asynchronous (Asynchronous), in essence, describe different behavior patterns when a program handles multiple events or tasks. + +Synchronous means one process must wait for another to complete before it can proceed. In other words, in synchronous operations, the caller will block waiting for a response after issuing a request until it receives a response result or times out before continuing with subsequent code execution. + +In contrast, asynchronous allows the caller to continue executing without waiting for a response after making a request, but when the request is completed, it notifies the caller of the response in some way (such as through callback functions or Future). The asynchronous model can improve concurrency and efficiency. + +From another perspective, synchronous calls require the calling thread to obtain the result, whereas asynchronous calls either have an asynchronous thread place the result somewhere (Future) or execute pre-prepared call success/failure callback methods (callback function). + +Below is a simple example demonstrating three invocation styles: synchronous, asynchronous with Future, and asynchronous with Callback. + +```java +import lombok.Data; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +public class AsyncTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(AsyncTest.class); + + public static void main(String[] args) throws InterruptedException, ExecutionException { + Result syncResponse = testSync(); + LOGGER.info("Synchronous response result: {}", syncResponse.getString()); + CompletableFuture result = testAsyncFuture(); + testAsyncCallback(); + LOGGER.info("Main thread continues executing~~"); + TimeUnit.SECONDS.sleep(1); // Ensure all results are processed + LOGGER.info("Main thread retrieves result from async Future: {}", result.get().getString()); + } + + public static void testAsyncCallback() { + new AsyncTask().execute(new AsyncCallback() { + @Override + public void onComplete(Result result) { + try { + TimeUnit.MILLISECONDS.sleep(50); // Simulate asynchronous delay + } catch (InterruptedException e) { + } + LOGGER.info("Async Callback gets result: {}", result.getString()); + } + }); + } + + public static CompletableFuture testAsyncFuture() { + return CompletableFuture.supplyAsync(() -> { + try { + TimeUnit.MILLISECONDS.sleep(50); // Simulate asynchronous delay + } catch (InterruptedException e) { + } + Result asyncResponse = getResult(); + LOGGER.info("Async Future gets result: {}", asyncResponse.getString()); + return asyncResponse; + }); + } + + public static Result testSync() { + return getResult(); + } + + @Data + static class Result { + private String string; + } + + interface AsyncCallback { + void onComplete(Result result); + } + + static class AsyncTask { + void execute(AsyncCallback callback) { + new Thread(() -> { + Result asyncRes = getResult(); + callback.onComplete(asyncRes); + }).start(); + } + } + + private static Result getResult() { + Result result = new Result(); + result.setString("result"); + return result; + } +} +``` + +Output: + +```java +22:26:38.788 [main] INFO org.hein.netty.AsyncTest - Synchronous response result: result +22:26:38.849 [main] INFO org.hein.netty.AsyncTest - Main thread continues executing~~ +22:26:38.911 [Thread-0] INFO org.hein.netty.AsyncTest - Async Callback gets result: result +22:26:38.911 [ForkJoinPool.commonPool-worker-1] INFO org.hein.netty.AsyncTest - Async Future gets result: result +22:26:39.857 [main] INFO org.hein.netty.AsyncTest - Main thread retrieves result from async Future: result +``` + +From the output, we can observe at least three points: + ++ One is that asynchronous Future and asynchronous Callback do not block the main thread from continuing its execution. ++ Two, the handling of results during asynchronous calls is not done by the main thread. ++ Finally, the difference between Future and Callback lies in that Future has the asynchronous thread store the result in a specific location (CompletableFuture#result), but retrieving the result still requires the main thread (or another thread) to call the get method. With Callback, it's essentially setting up the predefined way to handle the result, which is executed by the asynchronous thread. + +Of course, `CompletableFuture` can also be used for callbacks, for example, by calling the `whenComplete` method. + +### Asynchronous Invocation + +Netty, as a high-performance asynchronous IO framework, is designed to be asynchronous at its core. Therefore, implementing asynchronous calls based on Netty is relatively straightforward. + +```java +protected void sendAsync(Channel channel, RpcMessage rpcMessage) { + channelWritableCheck(channel, rpcMessage.getBody()); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("write message: {}, channel: {}, active? {}, writable? {}, isopen? {}", rpcMessage.getBody(), channel, channel.isActive(), channel.isWritable(), channel.isOpen()); + } + doBeforeRpcHooks(ChannelUtil.getAddressFromChannel(channel), rpcMessage); + channel.writeAndFlush(rpcMessage).addListener((ChannelFutureListener) future -> { + if (!future.isSuccess()) { + destroyChannel(future.channel()); + } + }); +} +``` + +An asynchronous call can be achieved by simply invoking the `writeAndFlush` method of the channel. + +It's important to note that the `writeAndFlush` method will operate synchronously when called from an EventLoop thread. + +### Synchronous Invocation + +Implementing asynchronous calls in Netty is simple, but converting them into synchronous calls requires more effort since it involves transforming an asynchronous call into a synchronous one. + +Essentially, converting asynchronous to synchronous means that after the calling thread initiates a call, it should block until it receives a response, and then it continues execution. + +The core of Seata's handling for this conversion lies within the `MessageFuture` class, as follows: + +```java +package org.apache.seata.core.protocol; + +import org.apache.seata.common.exception.ShouldNeverHappenException; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class MessageFuture { + + private RpcMessage requestMessage; + private long timeout; + private final long start = System.currentTimeMillis(); + + private final transient CompletableFuture origin = new CompletableFuture<>(); + + public boolean isTimeout() { + return System.currentTimeMillis() - start > timeout; + } + + public Object get(long timeout, TimeUnit unit) throws TimeoutException, InterruptedException { + Object result; + try { + result = origin.get(timeout, unit); + if (result instanceof TimeoutException) { + throw (TimeoutException) result; + } + } catch (ExecutionException e) { + throw new ShouldNeverHappenException("Should not get results in a multi-threaded environment", e); + } catch (TimeoutException e) { + throw new TimeoutException(String.format("%s, cost: %d ms", e.getMessage(), System.currentTimeMillis() - start)); + } + if (result instanceof RuntimeException) { + throw (RuntimeException) result; + } else if (result instanceof Throwable) { + throw new RuntimeException((Throwable) result); + } + return result; + } + + public void setResultMessage(Object obj) { + origin.complete(obj); + } + + public RpcMessage getRequestMessage() { return requestMessage; } + + public void setRequestMessage(RpcMessage requestMessage) { this.requestMessage = requestMessage;} + + public long getTimeout() { return timeout; } + + public void setTimeout(long timeout) { this.timeout = timeout;} +} +``` + +With this class, the process of a synchronous call works as follows, using a client request and server response as an example: + ++ First, the client constructs the request into a `MessageFuture`, then stores the request ID along with this `MessageFuture` object in a hash table. ++ The client then calls `channel.writeAndFlush` to initiate an asynchronous call. Yes, it's still asynchronous at this point. ++ The key to converting asynchronous to synchronous lies in the fact that the thread needs to call the `get` method on the `MessageFuture` object, which blocks the thread, effectively calling the `get` method on `CompletableFuture` to enter a blocking state. ++ When the server finishes processing and sends a request from its perspective, the client sees this as a response. ++ When the client receives the response, the EventLoop thread sets the response result in the `MessageFuture`. Since the request and response IDs are the same, the corresponding `MessageFuture` object can be retrieved from the aforementioned hash table. ++ Once the response result is set, the previously blocked thread can resume execution, thereby achieving a synchronous effect. + +Thus, Seata's solution essentially uses `CompletableFuture` objects as containers for storing results. + +```java +protected Object sendSync(Channel channel, RpcMessage rpcMessage, long timeoutMillis) throws TimeoutException { + if (timeoutMillis <= 0) { + throw new FrameworkException("timeout should more than 0ms"); + } + if (channel == null) { + LOGGER.warn("sendSync nothing, caused by null channel."); + return null; + } + MessageFuture messageFuture = new MessageFuture(); + messageFuture.setRequestMessage(rpcMessage); + messageFuture.setTimeout(timeoutMillis); + futures.put(rpcMessage.getId(), messageFuture); // The request and response IDs are the same + // Check if the Channel is writable (Channels have write buffers, and if the buffer reaches a threshold water level, it becomes unwritable) + channelWritableCheck(channel, rpcMessage.getBody()); + // Get the destination IP address + String remoteAddr = ChannelUtil.getAddressFromChannel(channel); + // Execute pre-send hooks + doBeforeRpcHooks(remoteAddr, rpcMessage); + // Send the result and set up a callback, non-blocking + channel.writeAndFlush(rpcMessage).addListener((ChannelFutureListener) future -> { + // If sending fails, remove the future and close the Channel + if (!future.isSuccess()) { + MessageFuture mf = futures.remove(rpcMessage.getId()); + if (mf != null) { + mf.setResultMessage(future.cause()); + } + destroyChannel(future.channel()); + } + }); + try { + // Since Netty sends asynchronously, we need to wait for the result here, converting async to sync + Object result = messageFuture.get(timeoutMillis, TimeUnit.MILLISECONDS); + // Execute post-send hooks + doAfterRpcHooks(remoteAddr, rpcMessage, result); + return result; + } catch (Exception exx) { + LOGGER.error("wait response error:{},ip:{},request:{}", exx.getMessage(), channel.remoteAddress(), rpcMessage.getBody()); + // Timeout exception + if (exx instanceof TimeoutException) { + throw (TimeoutException) exx; + } else { + throw new RuntimeException(exx); + } + } +} +``` + +### Message Handling + +When it comes to message handling in Netty, one should think of inbound and outbound handlers first. + +In the Seata Server side, besides common encoding and decoding handlers, there is also the `ServerHandler`. Here's an example: + +```java +@ChannelHandler.Sharable +class ServerHandler extends ChannelDuplexHandler { + + @Override + public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception { + // Preceded by a decoder handler, so the message here is RpcMessage + if (msg instanceof RpcMessage) { + processMessage(ctx, (RpcMessage) msg); + } else { + LOGGER.error("rpcMessage type error"); + } + } + + // ... +} +``` + +The `channelRead` method has significant business meaning, as all messages sent to the Server will come to this method after being decoded. + +The `processMessage` method within this context refers to the business processing method found in `AbstractNettyRemoting`, as follows: + +```java +protected void processMessage(ChannelHandlerContext ctx, RpcMessage rpcMessage) throws Exception { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("{} msgId: {}, body: {}", this, rpcMessage.getId(), rpcMessage.getBody()); + } + Object body = rpcMessage.getBody(); + if (body instanceof MessageTypeAware) { + MessageTypeAware messageTypeAware = (MessageTypeAware) body; + // During Server startup, a lot of processors are registered with processorTable + final Pair pair = this.processorTable.get((int) messageTypeAware.getTypeCode()); + if (pair != null) { + // Execute with the corresponding thread pool + if (pair.getSecond() != null) { + try { + pair.getSecond().execute(() -> { + try { + // Find the corresponding processor to execute + pair.getFirst().process(ctx, rpcMessage); + } catch (Throwable th) { + LOGGER.error(FrameworkErrorCode.NetDispatch.getErrCode(), th.getMessage(), th); + } finally { + MDC.clear(); + } + }); + } catch (RejectedExecutionException e) { + // Thread pool is full, execute rejection policy + LOGGER.error(FrameworkErrorCode.ThreadPoolFull.getErrCode(), "thread pool is full, current max pool size is " + messageExecutor.getActiveCount()); + if (allowDumpStack) { + // Export thread stack information + String name = ManagementFactory.getRuntimeMXBean().getName(); + String pid = name.split("@")[0]; + long idx = System.currentTimeMillis(); + try { + String jstackFile = idx + ".log"; + LOGGER.info("jstack command will dump to {}", jstackFile); + Runtime.getRuntime().exec(String.format("jstack %s > %s", pid, jstackFile)); + } catch (IOException exx) { + LOGGER.error(exx.getMessage()); + } + allowDumpStack = false; + } + } + } else { + try { + // If no thread pool is configured for the processor, it is executed by the current thread, which is basically the EventLoop thread + pair.getFirst().process(ctx, rpcMessage); + } catch (Throwable th) { + LOGGER.error(FrameworkErrorCode.NetDispatch.getErrCode(), th.getMessage(), th); + } + } + } else { + LOGGER.error("This message type [{}] has no processor.", messageTypeAware.getTypeCode()); + } + } else { + LOGGER.error("This rpcMessage body[{}] is not MessageTypeAware type.", body); + } +} +``` + +The logic of this method is quite straightforward. + +During the startup process of Seata Server, a multitude of processors are registered into the `processorTable`, so here we can obtain the corresponding processor and thread pool based on the message type code. + +If there is a thread pool, the processor's method is executed within that thread pool; otherwise, it is handed over to the EventLoop thread for execution. + +Of course, the same approach applies to the Client. + +### Batch Sending + +In network programming, there are times when batch sending is also required. Let's see how Seata implements this, focusing on the client sending to the server. + +Recall that during the Client startup process, we mentioned a thread pool `mergeSendExecutorService`. If batch sending is allowed, then upon Client startup, a `MergedSendRunnable` task is submitted. First, let's look at what this task does: + +```java +private class MergedSendRunnable implements Runnable { + + @Override + public void run() { + // Infinite loop + while (true) { + synchronized (mergeLock) { + try { + // Ensure the thread idles for no more than 1ms + mergeLock.wait(MAX_MERGE_SEND_MILLS); // 1 + } catch (InterruptedException ignore) { + // ignore + } + } + // Flag indicating sending in progress + isSending = true; + // basketMap: key is address, value is the queue of messages (blocking queue) to be sent to that address + basketMap.forEach((address, basket) -> { + if (basket.isEmpty()) { + return; + } + MergedWarpMessage mergeMessage = new MergedWarpMessage(); + while (!basket.isEmpty()) { + // Merge all RpcMessages from the same blocking queue + RpcMessage msg = basket.poll(); + mergeMessage.msgs.add((AbstractMessage) msg.getBody()); + mergeMessage.msgIds.add(msg.getId()); + } + if (mergeMessage.msgIds.size() > 1) { + printMergeMessageLog(mergeMessage); + } + Channel sendChannel = null; + try { + // Batch message sending is a synchronous request but doesn't require a return value. + // Because messageFuture is created before putting the message into basketMap. + // The return value will be set in ClientOnResponseProcessor. + sendChannel = clientChannelManager.acquireChannel(address); + // Internally wraps mergeMessage as a regular RpcMessage and sends it + AbstractNettyRemotingClient.this.sendAsyncRequest(sendChannel, mergeMessage); + } catch (FrameworkException e) { + if (e.getErrorCode() == FrameworkErrorCode.ChannelIsNotWritable && sendChannel != null) { + destroyChannel(address, sendChannel); + } + // Fast fail + for (Integer msgId : mergeMessage.msgIds) { + MessageFuture messageFuture = futures.remove(msgId); + if (messageFuture != null) { + messageFuture.setResultMessage(new RuntimeException(String.format("%s is unreachable", address), e)); + } + } + LOGGER.error("client merge call failed: {}", e.getMessage(), e); + } + }); + isSending = false; + } + } +} +``` + +The related batch sending code follows: + +```java +public Object sendSyncRequest(Object msg) throws TimeoutException { + String serverAddress = loadBalance(getTransactionServiceGroup(), msg); + long timeoutMillis = this.getRpcRequestTimeout(); + RpcMessage rpcMessage = buildRequestMessage(msg, ProtocolConstants.MSGTYPE_RESQUEST_SYNC); + // Send batch message + // Put message into basketMap, @see MergedSendRunnable + if (this.isEnableClientBatchSendRequest()) { + // If client-side batch message sending is enabled + // Sending batch messages is a sync request, which needs to create messageFuture and put it in futures. + MessageFuture messageFuture = new MessageFuture(); + messageFuture.setRequestMessage(rpcMessage); + messageFuture.setTimeout(timeoutMillis); + futures.put(rpcMessage.getId(), messageFuture); + + // Put message into basketMap + // Get the sending queue corresponding to serverAddress + BlockingQueue basket = CollectionUtils.computeIfAbsent(basketMap, serverAddress, + key -> new LinkedBlockingQueue<>()); + // Add the message to the queue, waiting for mergeSendExecutorService to perform the actual sending + if (!basket.offer(rpcMessage)) { + LOGGER.error("put message into basketMap offer failed, serverAddress: {}, rpcMessage: {}", serverAddress, rpcMessage); + return null; + } + if (!isSending) { + // Ensure that once there is data in the queue, the thread is awakened to continue batch sending + synchronized (mergeLock) { + mergeLock.notifyAll(); + } + } + try { + // Thread blocks waiting for response + return messageFuture.get(timeoutMillis, TimeUnit.MILLISECONDS); + } catch (Exception exx) { + LOGGER.error("wait response error: {}, ip: {}, request: {}", exx.getMessage(), serverAddress, rpcMessage.getBody()); + if (exx instanceof TimeoutException) { + throw (TimeoutException) exx; + } else { + throw new RuntimeException(exx); + } + } + } else { + // Normal sending, acquire channel and call the parent class's synchronous method + Channel channel = clientChannelManager.acquireChannel(serverAddress); + return super.sendSync(channel, rpcMessage, timeoutMillis); + } +} +``` + +As can be seen, object lock synchronization-wait mechanisms are used here, resulting in the following effects: + +1. Messages are sent by traversing the `basketMap` every 1ms at most. +2. During the blocking period of threads inside `mergeSendExecutorService` (mainLock.wait), if a message that needs to be sent arrives, the thread on `mainLock` is awakened to continue sending. + +How does the Server handle this? It mainly looks at the `TypeCode` of the `MergedWarpMessage`, which is actually `TYPE_SEATA_MERGE`. During Server startup, the processor registered for this Code is actually `ServerOnRequestProcessor`. + +> This shows you how to find out how a certain message is processed; teaching you how to fish is better than giving you fish! + +On the `ServerOnRequestProcessor` side, there are actually two ways to handle `MergedWarpMessage` messages: + +1. After processing all individual requests within `MergedWarpMessage`, send a unified `MergeResultMessage`. +2. Handle the sending task with the `batchResponseExecutorService` thread pool, ensuring two points: one is to respond immediately when there is a message result, even if the thread is waiting, it will notify it, and secondly, it responds at least once every 1ms because the thread executing within `batchResponseExecutorService` waits for no more than 1ms. + +Note that these two methods respond with different message types; the first responds with `MergeResultMessage`, and the second with `BatchResultMessage`, each handled differently on the Client side. + +The core processing method within `ServerOnRequestProcessor` is as follows: + +```java +private void onRequestMessage(ChannelHandlerContext ctx, RpcMessage rpcMessage) { + Object message = rpcMessage.getBody(); + RpcContext rpcContext = ChannelManager.getContextFromIdentified(ctx.channel()); + // the batch send request message + if (message instanceof MergedWarpMessage) { + final List msgs = ((MergedWarpMessage) message).msgs; + final List msgIds = ((MergedWarpMessage) message).msgIds; + // Allow TC server to batch return results && client version >= 1.5.0 + if (NettyServerConfig.isEnableTcServerBatchSendResponse() && StringUtils.isNotBlank(rpcContext.getVersion()) + && Version.isAboveOrEqualVersion150(rpcContext.getVersion())) { + // Handled by `batchResponseExecutorService` individually without waiting for all batch requests to complete + for (int i = 0; i < msgs.size(); i++) { + if (PARALLEL_REQUEST_HANDLE) { + int finalI = i; + CompletableFuture.runAsync( + () -> handleRequestsByMergedWarpMessageBy150(msgs.get(finalI), msgIds.get(finalI), rpcMessage, ctx, rpcContext)); + } else { + handleRequestsByMergedWarpMessageBy150(msgs.get(i), msgIds.get(i), rpcMessage, ctx, rpcContext); + } + } + } else { + // Responses are sent only after each request has been processed + List results = new ArrayList<>(); + List> futures = new ArrayList<>(); + for (int i = 0; i < msgs.size(); i++) { + if (PARALLEL_REQUEST_HANDLE) { + int finalI = i; + futures.add(CompletableFuture.supplyAsync(() -> handleRequestsByMergedWarpMessage(msgs.get(finalI), rpcContext))); + } else { + results.add(i, handleRequestsByMergedWarpMessage(msgs.get(i), rpcContext)); + } + } + if (CollectionUtils.isNotEmpty(futures)) { + try { + for (CompletableFuture future : futures) { + results.add(future.get()); // Blocking wait for processing result + } + } catch (InterruptedException | ExecutionException e) { + LOGGER.error("handle request error: {}", e.getMessage(), e); + } + } + MergeResultMessage resultMessage = new MergeResultMessage(); + resultMessage.setMsgs(results.toArray(new AbstractResultMessage[0])); + remotingServer.sendAsyncResponse(rpcMessage, ctx.channel(), resultMessage); + } + } else { + // Handle individual message response + } +} +``` + +The difference between `handleRequestsByMergedWarpMessage` and `handleRequestsByMergedWarpMessageBy150` lies in the fact that the latter encapsulates the result into a `QueueItem` and adds it to a blocking queue for actual sending by threads in `batchResponseExecutorService`, while the former simply returns the processing result. + +```java +private AbstractResultMessage handleRequestsByMergedWarpMessage(AbstractMessage subMessage, RpcContext rpcContext) { + AbstractResultMessage resultMessage = transactionMessageHandler.onRequest(subMessage, rpcContext); + return resultMessage; +} + +private void handleRequestsByMergedWarpMessageBy150(AbstractMessage msg, int msgId, RpcMessage rpcMessage, + ChannelHandlerContext ctx, RpcContext rpcContext) { + AbstractResultMessage resultMessage = transactionMessageHandler.onRequest(msg, rpcContext); + // Get the sending queue corresponding to the channel + BlockingQueue msgQueue = CollectionUtils.computeIfAbsent(basketMap, ctx.channel(), key -> new LinkedBlockingQueue<>()); + // Add the result to the queue, waiting for `batchResponseExecutorService` thread pool to perform the actual sending + if (!msgQueue.offer(new QueueItem(resultMessage, msgId, rpcMessage))) { + LOGGER.error("put message into basketMap offer failed, channel: {}, rpcMessage: {}, resultMessage: {}", ctx.channel(), rpcMessage, resultMessage); + } + if (!isResponding) { + // Ensure that once there is data in the queue, the thread is awakened to perform batch sending + synchronized (batchResponseLock) { + batchResponseLock.notifyAll(); + } + } +} +``` + +Now, let's look at how the `batchResponseExecutorService` thread pool handles batch sending tasks: + +```java +private class BatchResponseRunnable implements Runnable { + @Override + public void run() { + while (true) { + synchronized (batchResponseLock) { + try { + // Idle for no more than 1ms + batchResponseLock.wait(MAX_BATCH_RESPONSE_MILLS); + } catch (InterruptedException e) { + LOGGER.error("BatchResponseRunnable Interrupted error", e); + } + } + isResponding = true; + // Traverse `basketMap` for processing + basketMap.forEach((channel, msgQueue) -> { + if (msgQueue.isEmpty()) { + return; + } + // Group responses according to [serialization,compressor,rpcMessageId,headMap] dimensions. + // Encapsulate queue messages into `BatchResultMessage` but not send all at once. + // Send asynchronously per group based on [serialization,compressor,rpcMessageId,headMap]. + Map batchResultMessageMap = new HashMap<>(); + while (!msgQueue.isEmpty()) { + QueueItem item = msgQueue.poll(); + BatchResultMessage batchResultMessage = CollectionUtils.computeIfAbsent(batchResultMessageMap, + new ClientRequestRpcInfo(item.getRpcMessage()), + key -> new BatchResultMessage()); + batchResultMessage.getResultMessages().add(item.getResultMessage()); + batchResultMessage.getMsgIds().add(item.getMsgId()); + } + batchResultMessageMap.forEach((clientRequestRpcInfo, batchResultMessage) -> + remotingServer.sendAsyncResponse(buildRpcMessage(clientRequestRpcInfo), channel, batchResultMessage)); + }); + isResponding = false; + } + } +} +``` + +Finally, let's see how the Client side processes Server's batch response messages. According to the processor registered by the Client, the processor handling batch messages is `ClientOnResponseProcessor`, as follows: + +```java +public void process(ChannelHandlerContext ctx, RpcMessage rpcMessage) throws Exception { + // Process `MergeResultMessage` + if (rpcMessage.getBody() instanceof MergeResultMessage) { + MergeResultMessage results = (MergeResultMessage) rpcMessage.getBody(); + MergedWarpMessage mergeMessage = (MergedWarpMessage) mergeMsgMap.remove(rpcMessage.getId()); + for (int i = 0; i < mergeMessage.msgs.size(); i++) { + int msgId = mergeMessage.msgIds.get(i); + MessageFuture future = futures.remove(msgId); + if (future == null) { + LOGGER.error("msg: {} is not found in futures, result message: {}", msgId, results.getMsgs()[i]); + } else { + future.setResultMessage(results.getMsgs()[i]); + } + } + } else if (rpcMessage.getBody() instanceof BatchResultMessage) { + // Process `BatchResultMessage` + try { + BatchResultMessage batchResultMessage = (BatchResultMessage) rpcMessage.getBody(); + for (int i = 0; i < batchResultMessage.getMsgIds().size(); i++) { + int msgId = batchResultMessage.getMsgIds().get(i); + MessageFuture future = futures.remove(msgId); + if (future == null) { + LOGGER.error("msg: {} is not found in futures, result message: {}", msgId, batchResultMessage.getResultMessages().get(i)); + } else { + future.setResultMessage(batchResultMessage.getResultMessages().get(i)); + } + } + } finally { + // For compatibility with old versions, in batch sending of version 1.5.0, + // batch messages will also be placed in the local cache of `mergeMsgMap`, + // but version 1.5.0 no longer needs to obtain batch messages from `mergeMsgMap`. + mergeMsgMap.clear(); + } + } else { + // Process non-batch sending messages + MessageFuture messageFuture = futures.remove(rpcMessage.getId()); + if (messageFuture != null) { + messageFuture.setResultMessage(rpcMessage.getBody()); + } else { + if (rpcMessage.getBody() instanceof AbstractResultMessage) { + if (transactionMessageHandler != null) { + transactionMessageHandler.onResponse((AbstractResultMessage) rpcMessage.getBody(), null); + } + } + } + } +} +``` + +Of course, the logic here is quite simple: it involves putting the results into the corresponding `MessageFuture`, so the initially blocked thread that sent the request can obtain the result, thereby completing one cycle of batch sending and response handling. + +Let's do some extra thinking: Why does Seata have two methods for batch sending, and which is better? + +For the `MergeResultMessage` approach, it must wait until all messages have been processed before sending them out, so its response speed is limited by the longest-processing message, even if other messages could be sent out much sooner. + +However, the `BatchResultMessage` approach differs in that it can achieve sending as soon as a message is processed, without waiting for other messages, thanks to parallel processing with `CompletableFuture`. This method definitely responds faster. + +The latter approach was introduced in Seata version 1.5 onwards, which can be seen as a better way to handle batch sending. + +Lastly, sharing an interaction flow diagram for global transaction commit requests by the author of the Seata RPC refactoring would be beneficial. + +![image-20241217222048505](/img/blog/seata-rpc.png) + +## How Seata Manages Channel + +Throughout the network communication process involving TC, TM, and RM, Channel is a critical communication component. To understand how Seata manages Channels, the easiest approach is to examine where the Server and Client obtain the Channel when sending messages. + +In the `sendSyncRequest` method of the `AbstractNettyRemotingClient` class, we can see the following code: + +```java +public Object sendSyncRequest(Object msg) throws TimeoutException { + // ... + // The Client acquires a Channel through NettyClientChannelManager + Channel channel = clientChannelManager.acquireChannel(serverAddress); + return super.sendSync(channel, rpcMessage, timeoutMillis); +} +``` + +And in the `sendSyncRequest` method of the `AbstractNettyRemotingServer` class, we can see the following code: + +```java +public Object sendSyncRequest(String resourceId, String clientId, Object msg, boolean tryOtherApp) throws TimeoutException { + // The Server obtains a Channel through ChannelManager + Channel channel = ChannelManager.getChannel(resourceId, clientId, tryOtherApp); + if (channel == null) { + throw new RuntimeException("rm client is not connected. dbkey:" + resourceId + ",clientId:" + clientId); + } + RpcMessage rpcMessage = buildRequestMessage(msg, ProtocolConstants.MSGTYPE_RESQUEST_SYNC); + return super.sendSync(channel, rpcMessage, NettyServerConfig.getRpcRequestTimeout()); +} +``` + +Therefore, on the Client side, it mainly acquires Channels through `NettyClientChannelManager`, while the Server retrieves Channels from `ChannelManager` based on `resourceId` and `clientId`. + +So, below we will primarily investigate these two classes along with some related logic. + +### Client Channel + +Let's first look at how Channels are managed on the Client side; the core class here is `NettyClientChannelManager`. + +First, let's take a simple look at the attributes of this class, + +```java +// serverAddress -> lock +private final ConcurrentMap channelLocks = new ConcurrentHashMap<>(); +// serverAddress -> NettyPoolKey +private final ConcurrentMap poolKeyMap = new ConcurrentHashMap<>(); +// serverAddress -> Channel +private final ConcurrentMap channels = new ConcurrentHashMap<>(); +// Object pool, NettyPoolKey -> Channel +private final GenericKeyedObjectPool nettyClientKeyPool; +// Functional interface, encapsulates the logic for obtaining a NettyPoolKey via serverAddress +private final Function poolKeyFunction; +``` + +#### Core Classes of the Object Pool + +Seata uses `GenericKeyedObjectPool` as the object pool managing Channels. + +`GenericKeyedObjectPool` is an implementation from the Apache Commons Pool library, primarily used for managing a set of object pools, each distinguished by a unique Key. It can support pooling requirements for multiple types of objects. + +When using `GenericKeyedObjectPool`, it's typically necessary to configure a `KeyedPoolableObjectFactory`. This factory defines how to create, validate, activate, passivate, and destroy objects within the pool. + +When `GenericKeyedObjectPool` needs to create an object, it calls the `makeObject` method of the `KeyedPoolableObjectFactory` factory, and when it needs to destroy an object, it calls the `destroyObject` method to destroy it…… + +#### How to Pool Channel + +The object being pooled is the Channel, and the corresponding Key is `NettyPoolKey`, as follows: + +```java +public class NettyPoolKey { + + private TransactionRole transactionRole; + private String address; + private AbstractMessage message; + + // ... +} +``` + +In `NettyPoolKey`, three pieces of information are maintained: the transaction role (TM, RM, Server), the target TC Server address, and the RPC message sent by the Client when connecting to the Server. + +How is this `NettyPoolKey` created? In Seata, the client actually has two roles, TM and RM, and the creation logic for each will be different. Therefore, Seata abstracts a method in `AbstractNettyRemotingClient` whose return value is a functional interface that encapsulates the logic for creating a `NettyPoolKey` based on `serverAddress`. + +```java +// org.apache.seata.core.rpc.netty.AbstractNettyRemotingClient#getPoolKeyFunction +protected abstract Function getPoolKeyFunction(); +``` + +For example, the implementation in TM is: + +```java +protected Function getPoolKeyFunction() { + return severAddress -> { + RegisterTMRequest message = new RegisterTMRequest(applicationId, transactionServiceGroup, getExtraData()); + return new NettyPoolKey(NettyPoolKey.TransactionRole.TM_ROLE, severAddress, message); + }; +} +``` + +And the implementation in RM is: + +```java +protected Function getPoolKeyFunction() { + return serverAddress -> { + String resourceIds = getMergedResourceKeys(); + if (resourceIds != null && LOGGER.isInfoEnabled()) { + LOGGER.info("RM will register: {}", resourceIds); + } + RegisterRMRequest message = new RegisterRMRequest(applicationId, transactionServiceGroup); + message.setResourceIds(resourceIds); + return new NettyPoolKey(NettyPoolKey.TransactionRole.RM_ROLE, serverAddress, message); + }; +} +``` + +From here, you can see that the message sent by TM after connecting to the Server is `RegisterTMRequest`, while for RM it is `RegisterRMRequest`. + +When is this functional interface called? We'll look at that later. + +We also mentioned earlier that an object pool comes with a corresponding object creation factory `KeyedPoolableObjectFactory`. In Seata, `NettyPoolableFactory` extends `KeyedPoolableObjectFactory` to implement this. + +```java +/** + * Netty Channel creation factory, creates Channel through NettyPoolKey, methods in this class must be thread-safe + */ +public class NettyPoolableFactory implements KeyedPoolableObjectFactory { + + // ... + + /** + * This method is called when a new instance is needed + */ + @Override + public Channel makeObject(NettyPoolKey key) { + InetSocketAddress address = NetUtil.toInetSocketAddress(key.getAddress()); + // Create Channel, essentially connect to Seata Server via bootstrap.connect and return Channel + Channel tmpChannel = clientBootstrap.getNewChannel(address); + long start = System.currentTimeMillis(); + Object response; + Channel channelToServer = null; + if (key.getMessage() == null) { + throw new FrameworkException("register msg is null, role:" + key.getTransactionRole().name()); + } + try { + // Send Message, for TM it's RegisterTMRequest, for RM it's RegisterRMRequest + response = rpcRemotingClient.sendSyncRequest(tmpChannel, key.getMessage()); + // Determine if registration was successful based on response + if (!isRegisterSuccess(response, key.getTransactionRole())) { + rpcRemotingClient.onRegisterMsgFail(key.getAddress(), tmpChannel, response, key.getMessage()); + } else { + // Registration successful + channelToServer = tmpChannel; + // Add serverAddress as key and Channel as value to NettyClientChannelManager.channels + // If RM, possibly need to register resources with Server + rpcRemotingClient.onRegisterMsgSuccess(key.getAddress(), tmpChannel, response, key.getMessage()); + } + } catch (Exception exx) { + if (tmpChannel != null) { + tmpChannel.close(); + } + throw new FrameworkException("register " + key.getTransactionRole().name() + " error, errMsg:" + exx.getMessage()); + } + return channelToServer; + } + + // ... + + @Override + public void destroyObject(NettyPoolKey key, Channel channel) throws Exception { + if (channel != null) { + channel.disconnect(); + channel.close(); + } + } + + /** + * This method is called to validate object validity (optional) when borrowing an object + */ + @Override + public boolean validateObject(NettyPoolKey key, Channel obj) { + if (obj != null && obj.isActive()) { + return true; + } + return false; + } + + /** + * This method is called to activate the object when borrowing an object + */ + @Override + public void activateObject(NettyPoolKey key, Channel obj) throws Exception {} + + /** + * This method is called to passivate the object when returning it + */ + @Override + public void passivateObject(NettyPoolKey key, Channel obj) throws Exception {} +} +``` + +#### Acquiring Channel + +Throughout the Seata client, there are three ways to acquire a Channel: initialization, scheduled reconnection, and acquiring Channel when sending messages. + +```java +// Entry point one +private void initConnection() { + boolean failFast = + ConfigurationFactory.getInstance().getBoolean(ConfigurationKeys.ENABLE_TM_CLIENT_CHANNEL_CHECK_FAIL_FAST, DefaultValues.DEFAULT_CLIENT_CHANNEL_CHECK_FAIL_FAST); + getClientChannelManager().initReconnect(transactionServiceGroup, failFast); +} + +// Entry point two +public void init() { + // Default delay 60s, periodic reconnect every 10s + timerExecutor.scheduleAtFixedRate(() -> { + try { + clientChannelManager.reconnect(getTransactionServiceGroup()); + } catch (Exception ex) { + LOGGER.warn("reconnect server failed. {}", ex.getMessage()); + } + }, SCHEDULE_DELAY_MILLS, SCHEDULE_INTERVAL_MILLS, TimeUnit.MILLISECONDS); + // ... +} + +// Entry point three +public Object sendSyncRequest(Object msg) throws TimeoutException { + // ... + // Client acquires Channel through NettyClientChannelManager + Channel channel = clientChannelManager.acquireChannel(serverAddress); + return super.sendSync(channel, rpcMessage, timeoutMillis); +} +``` + +However, these three entry points will eventually call the `acquireChannel` method of `clientChannelManager` to obtain a Channel. + +```java +/** + * Get Channel based on serverAddress, if Channel does not exist or connection is dead then need to establish a new connection + */ +Channel acquireChannel(String serverAddress) { + // Get Channel from channels based on serverAddress + Channel channelToServer = channels.get(serverAddress); + if (channelToServer != null) { + channelToServer = getExistAliveChannel(channelToServer, serverAddress); + if (channelToServer != null) { + return channelToServer; + } + } + // If Channel does not exist in channels or this Channel is dead, then need to establish a connection for this address + Object lockObj = CollectionUtils.computeIfAbsent(channelLocks, serverAddress, key -> new Object()); + synchronized (lockObj) { + // Establish connection + return doConnect(serverAddress); + } +} + +private Channel doConnect(String serverAddress) { + // Try to get once more + Channel channelToServer = channels.get(serverAddress); + if (channelToServer != null && channelToServer.isActive()) { + return channelToServer; + } + Channel channelFromPool; + try { + // Call the functional interface here + NettyPoolKey currentPoolKey = poolKeyFunction.apply(serverAddress); + poolKeyMap.put(serverAddress, currentPoolKey); + // Borrow object from the object pool, if object creation is needed, it will call the factory's makeObject method, + // which internally connects to the Server and sends the message of currentPoolKey.message + channelFromPool = nettyClientKeyPool.borrowObject(currentPoolKey); + channels.put(serverAddress, channelFromPool); + } catch (Exception exx) { + LOGGER.error("{} register RM failed.", FrameworkErrorCode.RegisterRM.getErrCode(), exx); + throw new FrameworkException("can not register RM,err:" + exx.getMessage()); + } + return channelFromPool; +} +``` + +### Server Channel + +On the Server side, almost all core logic related to Channel management is within `ChannelManager`. So how does the Server get its Channels? Remember that on the Client side, after initiating a connection to the Server, it also sends a registration request for TM and RM. + +Let's first take a look at how the Server handles these `registerRequest`s. + +#### Handling Client Registration + +The related handlers are `RegRmProcessor` and `RegTmProcessor`. In these two processors, the core logic involves calling the `ChannelManager`'s `registerTMChannel` and `registerRMChannel` methods. + +```java +public static void registerTMChannel(RegisterTMRequest request, Channel channel) throws IncompatibleVersionException { + // Build RpcContext, which maintains the context of client connection information + RpcContext rpcContext = buildChannelHolder(NettyPoolKey.TransactionRole.TM_ROLE, request.getVersion(), + request.getApplicationId(), + request.getTransactionServiceGroup(), + null, channel); + // Put Channel as key and rpcContext as value into IDENTIFIED_CHANNELS + rpcContext.holdInIdentifiedChannels(IDENTIFIED_CHANNELS); + // applicationId:clientIp + String clientIdentified = rpcContext.getApplicationId() + Constants.CLIENT_ID_SPLIT_CHAR + ChannelUtil.getClientIpFromChannel(channel); + // Store Channel information in TM_CHANNELS + ConcurrentMap clientIdentifiedMap = CollectionUtils.computeIfAbsent(TM_CHANNELS, clientIdentified, key -> new ConcurrentHashMap<>()); + rpcContext.holdInClientChannels(clientIdentifiedMap); +} + +public static void registerRMChannel(RegisterRMRequest resourceManagerRequest, Channel channel) throws IncompatibleVersionException { + Set dbkeySet = dbKeytoSet(resourceManagerRequest.getResourceIds()); + RpcContext rpcContext; + if (!IDENTIFIED_CHANNELS.containsKey(channel)) { + // Build RpcContext and IDENTIFIED_CHANNELS + rpcContext = buildChannelHolder(NettyPoolKey.TransactionRole.RM_ROLE, resourceManagerRequest.getVersion(), + resourceManagerRequest.getApplicationId(), resourceManagerRequest.getTransactionServiceGroup(), + resourceManagerRequest.getResourceIds(), channel); + rpcContext.holdInIdentifiedChannels(IDENTIFIED_CHANNELS); + } else { + rpcContext = IDENTIFIED_CHANNELS.get(channel); + rpcContext.addResources(dbkeySet); + } + if (dbkeySet == null || dbkeySet.isEmpty()) { + return; + } + for (String resourceId : dbkeySet) { + String clientIp; + // Maintain RM_CHANNELS information + ConcurrentMap portMap = CollectionUtils.computeIfAbsent(RM_CHANNELS, resourceId, key -> new ConcurrentHashMap<>()) + .computeIfAbsent(resourceManagerRequest.getApplicationId(), key -> new ConcurrentHashMap<>()) + .computeIfAbsent(clientIp = ChannelUtil.getClientIpFromChannel(channel), key -> new ConcurrentHashMap<>()); + rpcContext.holdInResourceManagerChannels(resourceId, portMap); + updateChannelsResource(resourceId, clientIp, resourceManagerRequest.getApplicationId()); + } +} +``` + +These two methods have relatively simple logic. They construct an `RpcContext` based on the registration request and Channel information, maintaining relevant Map collections within the Server such as `IDENTIFIED_CHANNELS`, `RM_CHANNELS`, and `TM_CHANNELS`. + +However, to be honest, these collections are nested quite deeply, and it is uncertain whether they can be optimized. + +```java +/** + * Channel -> RpcContext + */ +private static final ConcurrentMap IDENTIFIED_CHANNELS = new ConcurrentHashMap<>(); + +/** + * resourceId -> applicationId -> ip -> port -> RpcContext + */ +// resourceId applicationId ip +private static final ConcurrentMap>>> RM_CHANNELS = new ConcurrentHashMap<>(); + +/** + * applicationId:clientIp -> port -> RpcContext + */ +private static final ConcurrentMap> TM_CHANNELS = new ConcurrentHashMap<>(); +``` + +#### Acquiring Channel + +On the Server side, the logic for acquiring a Channel is really long; those interested can take a look by themselves. Essentially, it involves obtaining an effective Channel from the map. + +```java +public static Channel getChannel(String resourceId, String clientId, boolean tryOtherApp) { + Channel resultChannel = null; + // Parse ClientId, composed of three parts: applicationId + clientIp + clientPort + String[] clientIdInfo = parseClientId(clientId); + if (clientIdInfo == null || clientIdInfo.length != 3) { + throw new FrameworkException("Invalid Client ID: " + clientId); + } + if (StringUtils.isBlank(resourceId)) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("No channel is available, resourceId is null or empty"); + } + return null; + } + // applicationId + String targetApplicationId = clientIdInfo[0]; + // clientIp + String targetIP = clientIdInfo[1]; + // clientPort + int targetPort = Integer.parseInt(clientIdInfo[2]); + // Below is continuously extracting the inner ConcurrentHashMaps + ConcurrentMap>> applicationIdMap = RM_CHANNELS.get(resourceId); + if (targetApplicationId == null || applicationIdMap == null || applicationIdMap.isEmpty()) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("No channel is available for resource[{}]", resourceId); + } + return null; + } + ConcurrentMap> ipMap = applicationIdMap.get(targetApplicationId); + if (ipMap != null && !ipMap.isEmpty()) { + // Firstly, try to find the original channel through which the branch was registered. + // Port -> RpcContext + ConcurrentMap portMapOnTargetIP = ipMap.get(targetIP); + /** + * Get Channel on targetIp + */ + if (portMapOnTargetIP != null && !portMapOnTargetIP.isEmpty()) { + RpcContext exactRpcContext = portMapOnTargetIP.get(targetPort); + if (exactRpcContext != null) { + Channel channel = exactRpcContext.getChannel(); + if (channel.isActive()) { + // If Channel is valid, skip all following ifs and return this Channel + resultChannel = channel; + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Just got exactly the one {} for {}", channel, clientId); + } + } else { + if (portMapOnTargetIP.remove(targetPort, exactRpcContext)) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Removed inactive {}", channel); + } + } + } + } + // The original channel was broken, try another one. + if (resultChannel == null) { + // Try other ports on the current node + for (ConcurrentMap.Entry portMapOnTargetIPEntry : portMapOnTargetIP.entrySet()) { + Channel channel = portMapOnTargetIPEntry.getValue().getChannel(); + if (channel.isActive()) { + resultChannel = channel; + if (LOGGER.isInfoEnabled()) { + LOGGER.info( + "Choose {} on the same IP[{}] as alternative of {}", channel, targetIP, clientId); + } + break; + } else { + if (portMapOnTargetIP.remove(portMapOnTargetIPEntry.getKey(), + portMapOnTargetIPEntry.getValue())) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Removed inactive {}", channel); + } + } + } + } + } + } + /** + * Get Channel on targetApplicationId + */ + // No channel on the app node, try another one. + if (resultChannel == null) { + for (ConcurrentMap.Entry> ipMapEntry : ipMap.entrySet()) { + if (ipMapEntry.getKey().equals(targetIP)) { + continue; + } + ConcurrentMap portMapOnOtherIP = ipMapEntry.getValue(); + if (portMapOnOtherIP == null || portMapOnOtherIP.isEmpty()) { + continue; + } + for (ConcurrentMap.Entry portMapOnOtherIPEntry : portMapOnOtherIP.entrySet()) { + Channel channel = portMapOnOtherIPEntry.getValue().getChannel(); + if (channel.isActive()) { + resultChannel = channel; + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Choose {} on the same application[{}] as alternative of {}", channel, targetApplicationId, clientId); + } + break; + } else { + if (portMapOnOtherIP.remove(portMapOnOtherIPEntry.getKey(), portMapOnOtherIPEntry.getValue())) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Removed inactive {}", channel); + } + } + } + } + if (resultChannel != null) { + break; + } + } + } + } + if (resultChannel == null && tryOtherApp) { + // Try other applicationId + resultChannel = tryOtherApp(applicationIdMap, targetApplicationId); + if (resultChannel == null) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("No channel is available for resource[{}] as alternative of {}", resourceId, clientId); + } + } else { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Choose {} on the same resource[{}] as alternative of {}", resultChannel, resourceId, clientId); + } + } + } + return resultChannel; +} + +private static Channel tryOtherApp(ConcurrentMap>> applicationIdMap, String myApplicationId) { + Channel chosenChannel = null; + for (ConcurrentMap.Entry>> applicationIdMapEntry : applicationIdMap.entrySet()) { + if (!StringUtils.isNullOrEmpty(myApplicationId) && applicationIdMapEntry.getKey().equals(myApplicationId)) { + continue; + } + ConcurrentMap> targetIPMap = applicationIdMapEntry.getValue(); + if (targetIPMap == null || targetIPMap.isEmpty()) { + continue; + } + for (ConcurrentMap.Entry> targetIPMapEntry : targetIPMap.entrySet()) { + ConcurrentMap portMap = targetIPMapEntry.getValue(); + if (portMap == null || portMap.isEmpty()) { + continue; + } + for (ConcurrentMap.Entry portMapEntry : portMap.entrySet()) { + Channel channel = portMapEntry.getValue().getChannel(); + if (channel.isActive()) { + chosenChannel = channel; + break; + } else { + if (portMap.remove(portMapEntry.getKey(), portMapEntry.getValue())) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Removed inactive {}", channel); + } + } + } + } + if (chosenChannel != null) { + break; + } + } + if (chosenChannel != null) { + break; + } + } + return chosenChannel; +} +``` + +### Summary in a Sequence Diagram + +Finally, let's summarize the Channel management process with a sequence diagram. + +![image-20241217222155609](/img/blog/seata-channel.png) + +## How Seata Designs Its Protocol + +For any network program, communication protocols are indispensable, and Seata is no exception. Here we will look at how the V1 version of the Seata protocol is implemented. + +The main related classes are `ProtocolEncoderV1` and `ProtocolDecoderV1`. + +Of course, as we know from before, the processor added when the Seata Server starts is actually `MultiProtocolDecoder`. In this class's decode method, it works as follows: + +```java +protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { + ByteBuf frame; + Object decoded; + byte version; + try { + if (isV0(in)) { + decoded = in; + version = ProtocolConstants.VERSION_0; + } else { + decoded = super.decode(ctx, in); + version = decideVersion(decoded); + } + if (decoded instanceof ByteBuf) { + frame = (ByteBuf) decoded; + // Identify multi-version protocols through MultiProtocolDecoder + // Select the corresponding codec based on version + ProtocolDecoder decoder = protocolDecoderMap.get(version); + ProtocolEncoder encoder = protocolEncoderMap.get(version); + try { + if (decoder == null || encoder == null) { + throw new UnsupportedOperationException("Unsupported version: " + version); + } + return decoder.decodeFrame(frame); + } finally { + if (version != ProtocolConstants.VERSION_0) { + frame.release(); + } + // Add the selected codec to the pipeline and remove MultiProtocolDecoder + ctx.pipeline().addLast((ChannelHandler) decoder); + ctx.pipeline().addLast((ChannelHandler) encoder); + if (channelHandlers != null) { + ctx.pipeline().addLast(channelHandlers); + } + ctx.pipeline().remove(this); + } + } + } catch (Exception exx) { + LOGGER.error("Decode frame error, cause: {}", exx.getMessage()); + throw new DecodeException(exx); + } + return decoded; +} +``` + +Therefore, here the corresponding codec for the version is chosen, then added to the pipeline, which will remove the `MultiProtocolDecoder`. + +### V1 Version Protocol + +Seata's protocol design is quite comprehensive and general, also being a mainstream solution to address issues like message fragmentation and partial messages, namely message length + message content. + +The format of the protocol is as follows: + +![image-20241217222155609](/img/blog/seata-protocol.png) + +As can be seen, it includes magic numbers, protocol version numbers, length fields, header lengths, message types, serialization algorithms, compression algorithms, request IDs, optional map extensions, and the message body. + +### How Encoding and Decoding Are Performed + +Seata decoders use Netty's built-in `LengthFieldBasedFrameDecoder`; those unfamiliar with it can take a look. + +However, encoding and decoding are not difficult, so I'll simply provide the code without much explanation. + +```java +package org.apache.seata.core.rpc.netty.v1; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; +import org.apache.seata.core.rpc.netty.ProtocolEncoder; +import org.apache.seata.core.serializer.Serializer; +import org.apache.seata.core.compressor.Compressor; +import org.apache.seata.core.compressor.CompressorFactory; +import org.apache.seata.core.protocol.ProtocolConstants; +import org.apache.seata.core.protocol.RpcMessage; +import org.apache.seata.core.serializer.SerializerServiceLoader; +import org.apache.seata.core.serializer.SerializerType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +/** + *
+ * 0     1     2     3     4     5     6     7     8     9    10     11    12    13    14    15    16
+ * +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
+ * |   magic   |proto|     full length       |    head   | Msg |Seria|Compr|      RequestId        |
+ * |   code    |versi|     (head+body)       |   length  |Type |lizer|ess  |                       |
+ * +-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
+ * |                                   Head Map [Optional]                                         |
+ * +-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
+ * |                                         body                                                  |
+ * +-----------------------------------------------------------------------------------------------+
+ * 
+ *

+ *

  • Full Length: include all data
  • + *
  • Head Length: include head data from magic code to head map.
  • + *
  • Body Length: Full Length - Head Length
  • + *

    + */ +public class ProtocolEncoderV1 extends MessageToByteEncoder implements ProtocolEncoder { + + private static final Logger LOGGER = LoggerFactory.getLogger(ProtocolEncoderV1.class); + + public void encode(RpcMessage message, ByteBuf out) { + try { + ProtocolRpcMessageV1 rpcMessage = new ProtocolRpcMessageV1(); + rpcMessage.rpcMsgToProtocolMsg(message); + int fullLength = ProtocolConstants.V1_HEAD_LENGTH; + int headLength = ProtocolConstants.V1_HEAD_LENGTH; + byte messageType = rpcMessage.getMessageType(); + out.writeBytes(ProtocolConstants.MAGIC_CODE_BYTES); + out.writeByte(ProtocolConstants.VERSION_1); + // full Length(4B) and head length(2B) will fix in the end. + out.writerIndex(out.writerIndex() + 6); // Here we skip the full length and head length positions and fill in the last + out.writeByte(messageType); + out.writeByte(rpcMessage.getCodec()); + out.writeByte(rpcMessage.getCompressor()); + out.writeInt(rpcMessage.getId()); + // direct write head with zero-copy + Map headMap = rpcMessage.getHeadMap(); + if (headMap != null && !headMap.isEmpty()) { + int headMapBytesLength = HeadMapSerializer.getInstance().encode(headMap, out); + headLength += headMapBytesLength; + fullLength += headMapBytesLength; + } + byte[] bodyBytes = null; + // heartbeat don't have body + if (messageType != ProtocolConstants.MSGTYPE_HEARTBEAT_REQUEST && messageType != ProtocolConstants.MSGTYPE_HEARTBEAT_RESPONSE) { + Serializer serializer = SerializerServiceLoader.load(SerializerType.getByCode(rpcMessage.getCodec()), ProtocolConstants.VERSION_1); + bodyBytes = serializer.serialize(rpcMessage.getBody()); + Compressor compressor = CompressorFactory.getCompressor(rpcMessage.getCompressor()); + bodyBytes = compressor.compress(bodyBytes); + fullLength += bodyBytes.length; + } + if (bodyBytes != null) { + out.writeBytes(bodyBytes); + } + // fix fullLength and headLength + int writeIndex = out.writerIndex(); + // skip magic code(2B) + version(1B) + out.writerIndex(writeIndex - fullLength + 3); + out.writeInt(fullLength); + out.writeShort(headLength); + out.writerIndex(writeIndex); + } catch (Throwable e) { + LOGGER.error("Encode request error!", e); + throw e; + } + } + + @Override + protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception { + try { + if (msg instanceof RpcMessage) { + this.encode((RpcMessage) msg, out); + } else { + throw new UnsupportedOperationException("Not support this class:" + msg.getClass()); + } + } catch (Throwable e) { + LOGGER.error("Encode request error!", e); + } + } +} +``` + +```java +package org.apache.seata.core.rpc.netty.v1; + +import java.util.List; +import java.util.Map; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.apache.seata.core.compressor.Compressor; +import org.apache.seata.core.compressor.CompressorFactory; +import org.apache.seata.core.exception.DecodeException; +import org.apache.seata.core.protocol.HeartbeatMessage; +import org.apache.seata.core.protocol.ProtocolConstants; +import org.apache.seata.core.protocol.RpcMessage; +import org.apache.seata.core.rpc.netty.ProtocolDecoder; +import org.apache.seata.core.serializer.Serializer; +import org.apache.seata.core.serializer.SerializerServiceLoader; +import org.apache.seata.core.serializer.SerializerType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + *
    + * 0     1     2     3     4     5     6     7     8     9    10     11    12    13    14    15    16
    + * +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    + * |   magic   |proto|     full length       |    head   | Msg |Seria|Compr|      RequestId        |
    + * |   code    |versi|     (head+body)       |   length  |Type |lizer|ess  |                       |
    + * +-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
    + * |                                   Head Map [Optional]                                         |
    + * +-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
    + * |                                         body                                                  |
    + * +-----------------------------------------------------------------------------------------------+
    + * 
    + *

    + *

  • Full Length: include all data
  • + *
  • Head Length: include head data from magic code to head map.
  • + *
  • Body Length: Full Length - Head Length
  • + *

    + */ +public class ProtocolDecoderV1 extends LengthFieldBasedFrameDecoder implements ProtocolDecoder { + + private static final Logger LOGGER = LoggerFactory.getLogger(ProtocolDecoderV1.class); + + private final List supportDeSerializerTypes; + + public ProtocolDecoderV1() { + /** + * int maxFrameLength, + * int lengthFieldOffset, Magic 2B, version 1B so the length is offset by 3B + * int lengthFieldLength, FullLength is int(4B). so values is 4 + * int lengthAdjustment, FullLength include all data and read 7 bytes before, so the left length is (FullLength-7). so values is -7 + * int initialBytesToStrip we will check magic code and version self, so do not strip any bytes. so values is 0 + */ + super(ProtocolConstants.MAX_FRAME_LENGTH, 3, 4, -7, 0); + supportDeSerializerTypes = SerializerServiceLoader.getSupportedSerializers(); + if (supportDeSerializerTypes.isEmpty()) { + throw new IllegalArgumentException("No serializer found"); + } + } + + @Override + public RpcMessage decodeFrame(ByteBuf frame) { + byte b0 = frame.readByte(); + byte b1 = frame.readByte(); + if (ProtocolConstants.MAGIC_CODE_BYTES[0] != b0 || ProtocolConstants.MAGIC_CODE_BYTES[1] != b1) { + throw new IllegalArgumentException("Unknown magic code: " + b0 + ", " + b1); + } + byte version = frame.readByte(); + int fullLength = frame.readInt(); + short headLength = frame.readShort(); + byte messageType = frame.readByte(); + byte codecType = frame.readByte(); + byte compressorType = frame.readByte(); + int requestId = frame.readInt(); + ProtocolRpcMessageV1 rpcMessage = new ProtocolRpcMessageV1(); + rpcMessage.setCodec(codecType); + rpcMessage.setId(requestId); + rpcMessage.setCompressor(compressorType); + rpcMessage.setMessageType(messageType); + // direct read head with zero-copy + int headMapLength = headLength - ProtocolConstants.V1_HEAD_LENGTH; + if (headMapLength > 0) { + Map map = HeadMapSerializer.getInstance().decode(frame, headMapLength); + rpcMessage.getHeadMap().putAll(map); + } + // read body + if (messageType == ProtocolConstants.MSGTYPE_HEARTBEAT_REQUEST) { + rpcMessage.setBody(HeartbeatMessage.PING); + } else if (messageType == ProtocolConstants.MSGTYPE_HEARTBEAT_RESPONSE) { + rpcMessage.setBody(HeartbeatMessage.PONG); + } else { + int bodyLength = fullLength - headLength; + if (bodyLength > 0) { + byte[] bs = new byte[bodyLength]; + frame.readBytes(bs); + Compressor compressor = CompressorFactory.getCompressor(compressorType); + bs = compressor.decompress(bs); + SerializerType protocolType = SerializerType.getByCode(rpcMessage.getCodec()); + if (this.supportDeSerializerTypes.contains(protocolType)) { + Serializer serializer = SerializerServiceLoader.load(protocolType, ProtocolConstants.VERSION_1); + rpcMessage.setBody(serializer.deserialize(bs)); + } else { + throw new IllegalArgumentException("SerializerType not match"); + } + } + } + return rpcMessage.protocolMsgToRpcMsg(); + } + + @Override + protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { + Object decoded; + try { + decoded = super.decode(ctx, in); + if (decoded instanceof ByteBuf) { + ByteBuf frame = (ByteBuf) decoded; + try { + return decodeFrame(frame); + } finally { + frame.release(); + } + } + } catch (Exception exx) { + LOGGER.error("Decode frame error, cause: {}", exx.getMessage()); + throw new DecodeException(exx); + } + return decoded; + } +} +``` + +## Summary + +From the current perspective, the implementation of network communication in Seata is relatively easy to understand. However, this article's analysis is only superficial and does not delve into deeper, more critical aspects such as code robustness, exception handling, graceful shutdown, etc. Further analysis will be provided if there are new insights in the future. + +[Original Article Link](https://blog.hein-hp.click/article/5p94ivva/) \ No newline at end of file diff --git a/i18n/zh-cn/docusaurus-plugin-content-blog/seata-rpc-analysis.md b/i18n/zh-cn/docusaurus-plugin-content-blog/seata-rpc-analysis.md new file mode 100644 index 00000000000..3cf631e4873 --- /dev/null +++ b/i18n/zh-cn/docusaurus-plugin-content-blog/seata-rpc-analysis.md @@ -0,0 +1,1912 @@ +--- +title: 一文入门 Seata 网络通信源码 +keywords: [Seata,RPC,源码,分布式事务] +description: 一篇较为全面的入门级 Seata RPC 源码剖析 +author: 何锦 +date: 2024-12-18 +--- + +在前几篇文章中,我们详细聊了聊 Seata 的 XA、AT 以及 TCC 模式,它们都是在 Seata 定义的全局框架下的不同的事务模式。 + +我们知道,在 Seata 中,有三类角色,TC、RM、TM,Seata Server 作为 TC 协调分支事务的提交和回滚,各个资源作为 RM 和 TM,那么这三者之间是如何通信的? + +所以,这篇文章就来看看 Seata 底层是如何进行网络通信的。 + +## 整体类层次结构 + +我们先着眼大局,看一看 Seata 整个 RPC 的类层次结构。 + +![image-20241217222005964](/img/blog/class-level.png) + +从类结构层次可以看出来,AbstractNettyRemoting 是整个 Seata 网络通信的一个顶层抽象类。 + +在这个类中主要实现了一些 RPC 的基础通用方法,比如同步调用 sendSync、异步调用 sendAsync 等。 + +事实上,就网络调用来说,无非就是同步调用和异步调用,像其他的什么请求和响应都只是报文内容的区分。 + +所以,在 Seata 中,我个人认为还差一个顶层的接口 Remoting,类似于下面这样的: + +```java +import io.netty.channel.Channel; +import java.util.concurrent.TimeoutException; + +public interface Remoting { + + /** + * 同步调用 + */ + Resp sendSync(Channel channel, Req request, long timeout) throws TimeoutException; + + /** + * 异步调用 + */ + void sendAsync(Channel channel, Req request); +} +``` + +在 AbstractNettyRemoting 实现了通用的网络调用方法,但是不同角色在这方面还是有一些区分的,比如对于 Server 来说,它的请求调用需要知道向哪个客户端发送,而对于 TM、RM 来说,它们发送请求直接发就行,不需要指定某个特定的 TC 服务,只需要在实现类通过负载均衡算法找到合适的 Server 节点就行。 + +所以就区分出了 RemotingServer 和 RemotingClient,但是底层还是要依赖 AbstractNettyRemoting 进行网络调用的,所以它们各自有子类实现了 AbstractNettyRemoting。 + +可以说 Seata 的这种设计在我看来是非常不错的,对于这种 CS 架构的远程通信,可以算一种通用的设计方案。 + +## 如何启动 Server 和 Client + +聊完了 Seata 底层的类层次,我们再分别以 Server 和 Client 的视角来看它们是如何启动的,以及在启动的时候需要做些什么事情。 + +### Server 是怎么启动的 + +Seata Server 作为一个独立的 SpringBoot 项目,要怎么样才能在 SpringBoot 启动的时候自动做点事呢? + +Seata 的做法是实现了 CommandLineRunner 接口,至于这里面的原理就不是本篇文章讨论的内容了。 + +我们主要关注它的 run 方法: + +```java +// org.apache.seata.server.ServerRunner#run +public void run(String... args) { + try { + long start = System.currentTimeMillis(); + seataServer.start(args); + started = true; + long cost = System.currentTimeMillis() - start; + LOGGER.info("\r\n you can visit seata console UI on http://127.0.0.1:{}. \r\n log path: {}.", this.port, this.logPath); + LOGGER.info("seata server started in {} millSeconds", cost); + } catch (Throwable e) { + started = Boolean.FALSE; + LOGGER.error("seata server start error: {} ", e.getMessage(), e); + System.exit(-1); + } +} +``` + +这其中核心的逻辑就在 seataServer.start() 方法中: + +```java +// org.apache.seata.server.Server#start +public void start(String[] args) { + // 参数解析器,用于解析 sh 的启动参数 + ParameterParser parameterParser = new ParameterParser(args); + // initialize the metrics + MetricsManager.get().init(); + ThreadPoolExecutor workingThreads = new ThreadPoolExecutor(NettyServerConfig.getMinServerPoolSize(), + NettyServerConfig.getMaxServerPoolSize(), NettyServerConfig.getKeepAliveTime(), TimeUnit.SECONDS, + new LinkedBlockingQueue<>(NettyServerConfig.getMaxTaskQueueSize()), + new NamedThreadFactory("ServerHandlerThread", NettyServerConfig.getMaxServerPoolSize()), new ThreadPoolExecutor.CallerRunsPolicy()); + // 127.0.0.1 and 0.0.0.0 are not valid here. + if (NetUtil.isValidIp(parameterParser.getHost(), false)) { + XID.setIpAddress(parameterParser.getHost()); + } else { + String preferredNetworks = ConfigurationFactory.getInstance().getConfig(REGISTRY_PREFERED_NETWORKS); + if (StringUtils.isNotBlank(preferredNetworks)) { + XID.setIpAddress(NetUtil.getLocalIp(preferredNetworks.split(REGEX_SPLIT_CHAR))); + } else { + XID.setIpAddress(NetUtil.getLocalIp()); + } + } + /** + * 主要做这么几件事: + * 1. 设置 workingThreads 为 AbstractNettyRemoting 的 messageExecutor 处理器 + * 2. 创建 ServerBootstrap,配置 Boss 和 Worker,并且设置 Seata Server 需要监听的端口 + * 3. 设置出栈、入栈处理器 ServerHandler,它是一个 ChannelDuplexHandler 复合的处理器 + */ + NettyRemotingServer nettyRemotingServer = new NettyRemotingServer(workingThreads); + XID.setPort(nettyRemotingServer.getListenPort()); + UUIDGenerator.init(parameterParser.getServerNode()); + ConfigurableListableBeanFactory beanFactory = ((GenericWebApplicationContext) ObjectHolder.INSTANCE.getObject(OBJECT_KEY_SPRING_APPLICATION_CONTEXT)).getBeanFactory(); + DefaultCoordinator coordinator = DefaultCoordinator.getInstance(nettyRemotingServer); + if (coordinator instanceof ApplicationListener) { + beanFactory.registerSingleton(NettyRemotingServer.class.getName(), nettyRemotingServer); + beanFactory.registerSingleton(DefaultCoordinator.class.getName(), coordinator); + ((GenericWebApplicationContext) ObjectHolder.INSTANCE.getObject(OBJECT_KEY_SPRING_APPLICATION_CONTEXT)).addApplicationListener((ApplicationListener) coordinator); + } + // log store mode: file, db, redis + SessionHolder.init(); + LockerManagerFactory.init(); + // 初始化一系列定时线程池,用于重试事务提交/回滚等 + coordinator.init(); + // 设置事务处理 Handler 为 DefaultCoordinator + nettyRemotingServer.setHandler(coordinator); + serverInstance.serverInstanceInit(); + // let ServerRunner do destroy instead ShutdownHook, see https://github.com/seata/seata/issues/4028 + ServerRunner.addDisposable(coordinator); + // Server 初始化 + nettyRemotingServer.init(); +} +``` + +最后的 nettyRemotingServer.init() 是整个 Seata Server 启动的重要逻辑,主要做了这么几件事: + +1. 注册一系列处理器 +2. 初始化一个定时线程池,用于清理过期的 MessageFuture +3. 启动 ServerBootStrap 并将 TC 服务注册到注册中心,比如 Nacos + +#### 注册处理器 + +在 Seata 内部,用一个 Pair 对象关联了处理器和线程池,如下: + +```java +package org.apache.seata.core.rpc.processor; + +public final class Pair { + + private final T1 first; + private final T2 second; + + public Pair(T1 first, T2 second) { + this.first = first; + this.second = second; + } + + public T1 getFirst() { + return first; + } + + public T2 getSecond() { + return second; + } +} +``` + +而注册处理器本质就是将报文类型、处理该报文的处理器以及具体执行的线程池关联起来,存到一张哈希表中。 + +```java +// AbstractNettyRemotingServer +protected final Map> processorTable = new HashMap<>(32); +``` + +```java +// org.apache.seata.core.rpc.netty.NettyRemotingServer#registerProcessor +private void registerProcessor() { + // 1. registry on request message processor + ServerOnRequestProcessor onRequestProcessor = new ServerOnRequestProcessor(this, getHandler()); + ShutdownHook.getInstance().addDisposable(onRequestProcessor); + super.registerProcessor(MessageType.TYPE_BRANCH_REGISTER, onRequestProcessor, messageExecutor); + super.registerProcessor(MessageType.TYPE_BRANCH_STATUS_REPORT, onRequestProcessor, messageExecutor); + super.registerProcessor(MessageType.TYPE_GLOBAL_BEGIN, onRequestProcessor, messageExecutor); + super.registerProcessor(MessageType.TYPE_GLOBAL_COMMIT, onRequestProcessor, messageExecutor); + super.registerProcessor(MessageType.TYPE_GLOBAL_LOCK_QUERY, onRequestProcessor, messageExecutor); + super.registerProcessor(MessageType.TYPE_GLOBAL_REPORT, onRequestProcessor, messageExecutor); + super.registerProcessor(MessageType.TYPE_GLOBAL_ROLLBACK, onRequestProcessor, messageExecutor); + super.registerProcessor(MessageType.TYPE_GLOBAL_STATUS, onRequestProcessor, messageExecutor); + super.registerProcessor(MessageType.TYPE_SEATA_MERGE, onRequestProcessor, messageExecutor); + // 2. registry on response message processor + ServerOnResponseProcessor onResponseProcessor = new ServerOnResponseProcessor(getHandler(), getFutures()); + super.registerProcessor(MessageType.TYPE_BRANCH_COMMIT_RESULT, onResponseProcessor, branchResultMessageExecutor); + super.registerProcessor(MessageType.TYPE_BRANCH_ROLLBACK_RESULT, onResponseProcessor, branchResultMessageExecutor); + // 3. registry rm message processor + RegRmProcessor regRmProcessor = new RegRmProcessor(this); + super.registerProcessor(MessageType.TYPE_REG_RM, regRmProcessor, messageExecutor); + // 4. registry tm message processor + RegTmProcessor regTmProcessor = new RegTmProcessor(this); + super.registerProcessor(MessageType.TYPE_REG_CLT, regTmProcessor, null); + // 5. registry heartbeat message processor + ServerHeartbeatProcessor heartbeatMessageProcessor = new ServerHeartbeatProcessor(this); + super.registerProcessor(MessageType.TYPE_HEARTBEAT_MSG, heartbeatMessageProcessor, null); +} + + +// org.apache.seata.core.rpc.netty.AbstractNettyRemotingServer#registerProcessor +public void registerProcessor(int messageType, RemotingProcessor processor, ExecutorService executor) { + Pair pair = new Pair<>(processor, executor); + this.processorTable.put(messageType, pair); +} +``` + +你可能会注意到,在注册处理器时,有一些注册时传入的线程池是 null,那么对应的报文会由哪个线程执行呢? + +后面我们会提到。 + +#### 初始化定时线程池 + +```java +// org.apache.seata.core.rpc.netty.AbstractNettyRemoting#init +public void init() { + timerExecutor.scheduleAtFixedRate(() -> { + for (Map.Entry entry : futures.entrySet()) { + MessageFuture future = entry.getValue(); + if (future.isTimeout()) { + futures.remove(entry.getKey()); + RpcMessage rpcMessage = future.getRequestMessage(); + future.setResultMessage(new TimeoutException(String.format("msgId: %s, msgType: %s, msg: %s, request timeout", + rpcMessage.getId(), String.valueOf(rpcMessage.getMessageType()), rpcMessage.getBody().toString()))); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("timeout clear future: {}", entry.getValue().getRequestMessage().getBody()); + } + } + } + nowMills = System.currentTimeMillis(); + }, TIMEOUT_CHECK_INTERVAL, TIMEOUT_CHECK_INTERVAL, TimeUnit.MILLISECONDS); +} +``` + +这个没啥好说的,就是初始化了一个定时线程池定时清理那些超时的 MessageFuture,这里 MessageFuture 是 Seata 将异步调用转为同步调用的关键,我们后面也会详细说到。 + +#### 启动 ServerBootStrap + +最后启动 ServerBootStrap,这差不多就是 Netty 的内容了。 + +```java +// org.apache.seata.core.rpc.netty.NettyServerBootstrap#start +public void start() { + int port = getListenPort(); + this.serverBootstrap.group(this.eventLoopGroupBoss, this.eventLoopGroupWorker) + .channel(NettyServerConfig.SERVER_CHANNEL_CLAZZ) + .option(ChannelOption.SO_BACKLOG, nettyServerConfig.getSoBackLogSize()) + .option(ChannelOption.SO_REUSEADDR, true) + .childOption(ChannelOption.SO_KEEPALIVE, true) + .childOption(ChannelOption.TCP_NODELAY, true) + .childOption(ChannelOption.SO_SNDBUF, nettyServerConfig.getServerSocketSendBufSize()) + .childOption(ChannelOption.SO_RCVBUF, nettyServerConfig.getServerSocketResvBufSize()) + .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(nettyServerConfig.getWriteBufferLowWaterMark(), nettyServerConfig.getWriteBufferHighWaterMark())) + .localAddress(new InetSocketAddress(port)) + .childHandler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) { + // 多版本协议解码器 + MultiProtocolDecoder multiProtocolDecoder = new MultiProtocolDecoder(channelHandlers); + ch.pipeline() + .addLast(new IdleStateHandler(nettyServerConfig.getChannelMaxReadIdleSeconds(), 0, 0)) + .addLast(multiProtocolDecoder); + } + }); + try { + this.serverBootstrap.bind(port).sync(); + LOGGER.info("Server started, service listen port: {}", getListenPort()); + InetSocketAddress address = new InetSocketAddress(XID.getIpAddress(), XID.getPort()); + for (RegistryService registryService : MultiRegistryFactory.getInstances()) { + // 注册服务 + registryService.register(address); + } + initialized.set(true); + } catch (SocketException se) { + throw new RuntimeException("Server start failed, the listen port: " + getListenPort(), se); + } catch (Exception exx) { + throw new RuntimeException("Server start failed", exx); + } +} + +``` + +ServerBootstrap 启动时的 childOption 属于网络部分的内容,我们不过多解释。 + +这里你可能有一点疑问,在 pipeline 中仅仅只是添加了一个 MultiProtocolDecoder 解码器,那业务处理器呢? + +事实上,MultiProtocolDecoder 的构造参数中的 channelHandlers 就是 ServerHandler,它是在创建 NettyRemotingServer 时就被设置的。 + +至于为什么要这样做,其实是和 Seata 的多版本协议相关。 + +当 Seata Server 启动后第一次进行解码时,会将 MultiProtocolDecoder 从 pipeline 中移除,根据版本选择具体的 Encoder 和 Decoder 并添加到 pipeline 中,此时,也会将 ServerHandler 添加到 pipeline。 + +### Client 是怎么启动的 + +对于 Client 来说,由于我们一般是在 SpringBoot 中使用 Seata,所以我们需要关注的点在 SeataAutoConfiguration 类中。 + +在这个类里面创建了一个 GlobalTransactionScanner 对象,我们注意到它实现了 InitializingBean,所以将目光转移到 afterPropertiesSet 方法上。 + +果然在这个方法里面进行了 TM 和 RM 的初始化。 + +#### TM 的初始化 + +对于 TM 来说,初始化的逻辑如下: + +```java +public static void init(String applicationId, String transactionServiceGroup, String accessKey, String secretKey) { + /** + * 主要做这么几件事 + * 1. 创建线程池作为 AbstractNettyRemotingClient 的 messageExecutor + * 2. 设置事务角色 transactionRole 为 TM_ROLE + * 3. 创建 Bootstrap 并设置出栈、入栈处理器 ClientHandler + * 4. 创建客户端 Channel 管理器 NettyClientChannelManager + */ + TmNettyRemotingClient tmNettyRemotingClient = TmNettyRemotingClient.getInstance(applicationId, transactionServiceGroup, accessKey, secretKey); + + /** + * 主要做这么几件事: + * 1. 注册一系列处理器 + * 2. 创建定时线程池定时对事务组内的 Server 发起连接,如果连接断开,则尝试重新建立连接 + * 3. 如果客户端允许报文批量发送,则创建 mergeSendExecutorService 线程池,并提交 MergedSendRunnable 任务 + * 4. 初始化一个定时线程池清理过期的 MessageFuture + * 5. 启动客户端 Bootstrap + * 6. 初始化连接 initConnection + */ + tmNettyRemotingClient.init(); +} +``` + +启动客户端 Bootstrap 的逻辑如下: + +```java +@Override +public void start() { + if (this.defaultEventExecutorGroup == null) { + this.defaultEventExecutorGroup = new DefaultEventExecutorGroup(nettyClientConfig.getClientWorkerThreads(), + new NamedThreadFactory(getThreadPrefix(nettyClientConfig.getClientWorkerThreadPrefix()), nettyClientConfig.getClientWorkerThreads())); + } + this.bootstrap.group(this.eventLoopGroupWorker) + .channel(nettyClientConfig.getClientChannelClazz()) + .option(ChannelOption.TCP_NODELAY, true) + .option(ChannelOption.SO_KEEPALIVE, true) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, nettyClientConfig.getConnectTimeoutMillis()) + .option(ChannelOption.SO_SNDBUF, nettyClientConfig.getClientSocketSndBufSize()) + .option(ChannelOption.SO_RCVBUF, nettyClientConfig.getClientSocketRcvBufSize()); + if (nettyClientConfig.enableNative()) { + if (PlatformDependent.isOsx()) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("client run on macOS"); + } + } else { + bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.EDGE_TRIGGERED) + .option(EpollChannelOption.TCP_QUICKACK, true); + } + } + bootstrap.handler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) { + ch.pipeline().addLast(new IdleStateHandler(nettyClientConfig.getChannelMaxReadIdleSeconds(), + nettyClientConfig.getChannelMaxWriteIdleSeconds(), + nettyClientConfig.getChannelMaxAllIdleSeconds())) + .addLast(new ProtocolDecoderV1()) + .addLast(new ProtocolEncoderV1()); + if (channelHandlers != null) { + addChannelPipelineLast(ch, channelHandlers); + } + } + }); + if (initialized.compareAndSet(false, true) && LOGGER.isInfoEnabled()) { + LOGGER.info("NettyClientBootstrap has started"); + } +} +``` + +由于客户端的协议版本根据不同的 Seata 版本是可以确定的,所以这里直接添加了 V1 版本的编解码器,这里 channelHandlers 其实就是 ClientHandler,它也是 Netty 中的一个复合处理器。 + +#### RM 的初始化 + +RM 的初始化大致逻辑和 TM 是类似的,这里就不过多介绍了。 + +## 如何发送和处理报文 + +厘清了 Seata Server 和 Client 的大致启动流程之后,我们就可以深入的看一看 Seata 是如何进行报文发送和处理的。 + +前面我们也说过了,发送请求和处理报文的核心逻辑是在 AbstractNettyRemoting 中,接下来就看一看这个类。 + +### 同步和异步 + +先简单说一说什么是同步和异步。 + +同步 Synchronous 和异步 Asynchronous,本质上是描述了程序在处理多个事件或者任务时的不同行为模式。 + +同步是指一个过程必须等待另一个过程完成之后才能继续进行。换句话说,在同步操作中,调用方发出请求后会一直阻塞等待直到接收到响应结果、或者超时才会继续执行后续代码。 + +相比之下,异步则允许调用者在请求后不必等待响应就可以向下执行,但当请求完成时,会以某种方式将响应通知到调用者(如通过回调函数、Future),异步模型可以提高并发性和效率。 + +从另一个角度来说,同步调用需要发起调用的线程获取结果,而异步调用则是由异步线程将结果放到某个地方(Future)或者是异步线程去执行事先准备好的调用成功/失败的回调方法(回调函数)。 + +下面是一个简单的例子,展示了三种调用方式,同步、异步 Future、异步 Callback。 + +```java +import lombok.Data; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +public class AsyncTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(AsyncTest.class); + + public static void main(String[] args) throws InterruptedException, ExecutionException { + Result syncResponse = testSync(); + LOGGER.info("同步响应结果: {}", syncResponse.getString()); + CompletableFuture result = testAsyncFuture(); + testAsyncCallback(); + LOGGER.info("主线程继续向下执行~~"); + TimeUnit.SECONDS.sleep(1); // 保证所有结果处理完毕 + LOGGER.info("主线程从异步 Future 中获取结果: {}", result.get().getString()); + } + + public static void testAsyncCallback() { + new AsyncTask().execute(new AsyncCallback() { + @Override + public void onComplete(Result result) { + try { + TimeUnit.MILLISECONDS.sleep(50); // 模拟异步耗时 + } catch (InterruptedException e) { + } + LOGGER.info("异步 Callback 获取结果: {}", result.getString()); + } + }); + } + + public static CompletableFuture testAsyncFuture() { + return CompletableFuture.supplyAsync(() -> { + try { + TimeUnit.MILLISECONDS.sleep(50); // 模拟异步耗时 + } catch (InterruptedException e) { + } + Result asyncResponse = getResult(); + LOGGER.info("异步 Future 获取结果: {}", asyncResponse.getString()); + return asyncResponse; + }); + } + + public static Result testSync() { + return getResult(); + } + + @Data + static class Result { + private String string; + } + + interface AsyncCallback { + void onComplete(Result result); + } + + static class AsyncTask { + void execute(AsyncCallback callback) { + new Thread(() -> { + Result asyncRes = getResult(); + callback.onComplete(asyncRes); + }).start(); + } + } + + private static Result getResult() { + Result result = new Result(); + result.setString("结果"); + return result; + } +} +``` + +输出: + +```java +22:26:38.788 [main] INFO org.hein.netty.AsyncTest - 同步响应结果: 结果 +22:26:38.849 [main] INFO org.hein.netty.AsyncTest - 主线程继续向下执行~~ +22:26:38.911 [Thread-0] INFO org.hein.netty.AsyncTest - 异步 Callback 获取结果: 结果 +22:26:38.911 [ForkJoinPool.commonPool-worker-1] INFO org.hein.netty.AsyncTest - 异步 Future 获取结果: 结果 +22:26:39.857 [main] INFO org.hein.netty.AsyncTest - 主线程从异步 Future 中获取结果: 结果 +``` + +从结果中,至少可以看出三点, + ++ 一是异步 Future 和异步 Callback 并不会阻塞主线程向下执行。 ++ 二是异步调用时处理结果的不是主线程。 ++ 最后,Future 和 Callback 的区别在于 Future 只是由异步线程将结果存储在了一个地方(CompletableFuture#result),但是后续获取结果还是需要主线程(或者其他线程)调用 get 方法,而 Callback 的话,其实就相当于预先设定了结果的处理方式,由异步线程去执行就好了。 + +当然,CompletableFuture 也是可以作回调的,比如调用 whenComplete 方法。 + +### 异步调用 + +Netty 作为一个高性能的异步 IO 框架,它的设计核心就是异步的,所以基于 Netty 进行异步调用是比较简单的。 + +```java +protected void sendAsync(Channel channel, RpcMessage rpcMessage) { + channelWritableCheck(channel, rpcMessage.getBody()); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("write message: {}, channel: {}, active? {}, writable? {}, isopen? {}", rpcMessage.getBody(), channel, channel.isActive(), channel.isWritable(), channel.isOpen()); + } + doBeforeRpcHooks(ChannelUtil.getAddressFromChannel(channel), rpcMessage); + channel.writeAndFlush(rpcMessage).addListener((ChannelFutureListener) future -> { + if (!future.isSuccess()) { + destroyChannel(future.channel()); + } + }); +} +``` + +只需要简单调用 channel 的 writeAndFlush 方法即可实现异步调用。 + +特别要注意的是,writeAndFlush 方法在调用线程是 EventLoop 线程的情况下会变成同步调用。 + +### 同步调用 + +在 Netty 中实现异步调用很简单,要实现同步调用就麻烦一点,需要将异步调用转换为同步调用。 + +从本质上来说,异步转同步就是让调用线程发起调用后,拿到响应前进入阻塞,拿到响应后再唤醒它,向下执行。 + +那么 Seata 的处理的核心就是 MessageFuture 类,如下: + +```java +package org.apache.seata.core.protocol; + +import org.apache.seata.common.exception.ShouldNeverHappenException; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class MessageFuture { + + private RpcMessage requestMessage; + private long timeout; + private final long start = System.currentTimeMillis(); + + private final transient CompletableFuture origin = new CompletableFuture<>(); + + public boolean isTimeout() { + return System.currentTimeMillis() - start > timeout; + } + + public Object get(long timeout, TimeUnit unit) throws TimeoutException, InterruptedException { + Object result; + try { + result = origin.get(timeout, unit); + if (result instanceof TimeoutException) { + throw (TimeoutException) result; + } + } catch (ExecutionException e) { + throw new ShouldNeverHappenException("Should not get results in a multi-threaded environment", e); + } catch (TimeoutException e) { + throw new TimeoutException(String.format("%s, cost: %d ms", e.getMessage(), System.currentTimeMillis() - start)); + } + if (result instanceof RuntimeException) { + throw (RuntimeException) result; + } else if (result instanceof Throwable) { + throw new RuntimeException((Throwable) result); + } + return result; + } + + public void setResultMessage(Object obj) { + origin.complete(obj); + } + + public RpcMessage getRequestMessage() { return requestMessage; } + + public void setRequestMessage(RpcMessage requestMessage) { this.requestMessage = requestMessage;} + + public long getTimeout() { return timeout; } + + public void setTimeout(long timeout) { this.timeout = timeout;} +} +``` + +有了这个类之后,同步调用的过程如下,我们以客户端请求、服务端响应为例: + ++ 首先客户端将请求构建为 MessageFuture,然后将请求 id 和这个 MessageFuture 对象存储到一个哈希表中。 ++ 接着客户端调用 channel.writeAndFlush 发起异步调用,是的,这里还是异步。 ++ 异步转同步的核心在于,此时线程需要调用 MessageFuture 对象的 get 方法进入阻塞,当然实际是调用了 CompletableFuture 的 get 方法进入同步阻塞。 ++ 当服务端处理完毕,它又会发出请求(服务端视角),在客户端来看,这就是响应。 ++ 当客户端收到响应之后,由 EventLoop 线程将响应结果设置到 MessageFuture 中,由于一次请求和响应的 id 是相同的,所以可以从上面的哈希表中拿到对应的 MessageFuture 对象。 ++ 当响应结果被设置之后,上面阻塞的线程就可以恢复运行,这样就实现了同步的效果。 + +所以,Seata 的解决方案本质上来说就是利用了 CompletableFuture 对象,将它作为一个存储结果的容器。 + +```java +protected Object sendSync(Channel channel, RpcMessage rpcMessage, long timeoutMillis) throws TimeoutException { + if (timeoutMillis <= 0) { + throw new FrameworkException("timeout should more than 0ms"); + } + if (channel == null) { + LOGGER.warn("sendSync nothing, caused by null channel."); + return null; + } + MessageFuture messageFuture = new MessageFuture(); + messageFuture.setRequestMessage(rpcMessage); + messageFuture.setTimeout(timeoutMillis); + futures.put(rpcMessage.getId(), messageFuture); // 请求和响应的 id 是一样的 + // 检查该 Channel 是否可写(Channel 中有写缓冲区,如果缓冲区达到阈值水位,则不可写) + channelWritableCheck(channel, rpcMessage.getBody()); + // 获取目的 ip 地址 + String remoteAddr = ChannelUtil.getAddressFromChannel(channel); + // 执行发送前钩子方法 + doBeforeRpcHooks(remoteAddr, rpcMessage); + // 发送结果,并设置回调,非阻塞 + channel.writeAndFlush(rpcMessage).addListener((ChannelFutureListener) future -> { + // 发送失败,移除 future,关闭 Channel + if (!future.isSuccess()) { + MessageFuture mf = futures.remove(rpcMessage.getId()); + if (mf != null) { + mf.setResultMessage(future.cause()); + } + destroyChannel(future.channel()); + } + }); + try { + // Netty 是异步发送,所以这里需要等待结果,将异步转为同步 + Object result = messageFuture.get(timeoutMillis, TimeUnit.MILLISECONDS); + // 执行发送后的钩子方法 + doAfterRpcHooks(remoteAddr, rpcMessage, result); + return result; + } catch (Exception exx) { + LOGGER.error("wait response error:{},ip:{},request:{}", exx.getMessage(), channel.remoteAddress(), rpcMessage.getBody()); + // 超时异常 + if (exx instanceof TimeoutException) { + throw (TimeoutException) exx; + } else { + throw new RuntimeException(exx); + } + } +} +``` + +### 报文处理 + +在 Netty 中,提到报文处理,我们首先应该想到的就是入栈、出栈处理器。 + +在 Seata Server 端,除了常见的编解码处理器之外,就是 ServerHandler 处理器了,如下: + +```java +@ChannelHandler.Sharable +class ServerHandler extends ChannelDuplexHandler { + + @Override + public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception { + // 前置了解码处理器,所以这里的消息是 RpcMessage + if (msg instanceof RpcMessage) { + processMessage(ctx, (RpcMessage) msg); + } else { + LOGGER.error("rpcMessage type error"); + } + } + + // ... +} +``` + +比较有业务含义的就是这个 channelRead 方法,所有发向 Server 的报文在经过解码之后都会来到这个方法。 + +这里的 processMessage 方法就是 AbstractNettyRemoting 中的业务处理方法,如下: + +```java +protected void processMessage(ChannelHandlerContext ctx, RpcMessage rpcMessage) throws Exception { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("{} msgId: {}, body: {}", this, rpcMessage.getId(), rpcMessage.getBody()); + } + Object body = rpcMessage.getBody(); + if (body instanceof MessageTypeAware) { + MessageTypeAware messageTypeAware = (MessageTypeAware) body; + // 在 Server 启动的时候,向 processorTable 注册了一大堆处理器 + final Pair pair = this.processorTable.get((int) messageTypeAware.getTypeCode()); + if (pair != null) { + // 拿到对应的线程池执行 + if (pair.getSecond() != null) { + try { + pair.getSecond().execute(() -> { + try { + // 找对应的处理器执行 + pair.getFirst().process(ctx, rpcMessage); + } catch (Throwable th) { + LOGGER.error(FrameworkErrorCode.NetDispatch.getErrCode(), th.getMessage(), th); + } finally { + MDC.clear(); + } + }); + } catch (RejectedExecutionException e) { + // 线程池满了,执行拒绝策略 + LOGGER.error(FrameworkErrorCode.ThreadPoolFull.getErrCode(), "thread pool is full, current max pool size is " + messageExecutor.getActiveCount()); + if (allowDumpStack) { + // 导出线程栈信息 + String name = ManagementFactory.getRuntimeMXBean().getName(); + String pid = name.split("@")[0]; + long idx = System.currentTimeMillis(); + try { + String jstackFile = idx + ".log"; + LOGGER.info("jstack command will dump to {}", jstackFile); + Runtime.getRuntime().exec(String.format("jstack %s > %s", pid, jstackFile)); + } catch (IOException exx) { + LOGGER.error(exx.getMessage()); + } + allowDumpStack = false; + } + } + } else { + try { + // 如果没有为处理器配置线程池,则由当前线程执行,基本上就是 EventLoop 线程了 + pair.getFirst().process(ctx, rpcMessage); + } catch (Throwable th) { + LOGGER.error(FrameworkErrorCode.NetDispatch.getErrCode(), th.getMessage(), th); + } + } + } else { + LOGGER.error("This message type [{}] has no processor.", messageTypeAware.getTypeCode()); + } + } else { + LOGGER.error("This rpcMessage body[{}] is not MessageTypeAware type.", body); + } +} +``` + +这个方法的逻辑很简单。 + +Seata 在 Server 启动的过程中,向 processorTable 注册了一大堆处理器,那么这里就可以根据消息类型 Code 拿到对应的处理器和线程池。 + +如果有线程池,就在线程池内执行处理器的方法,否则就交给 EventLoop 线程去执行。 + +当然,对于 Client 而言,也是这样的。 + +### 批量发送 + +在网络程序中,有时候也需要实现批量发送,我们来看 Seata 是怎么做的,这里主要看客户端向服务端发送。 + +还记得我们上面在 Client 启动的过程中提到过一个线程池 mergeSendExecutorService,如果允许批量发送,那么在 Client 启动的时候就会提交一个 MergedSendRunnable 任务,我们先来看这个任务在干啥? + +```java +private class MergedSendRunnable implements Runnable { + + @Override + public void run() { + // 死循环 + while (true) { + synchronized (mergeLock) { + try { + // 保证线程最多只会空闲 1ms + mergeLock.wait(MAX_MERGE_SEND_MILLS); // 1 + } catch (InterruptedException ignore) { + // ignore + } + } + // 正在发送中的标识 + isSending = true; + // basketMap: key 是 address,value 是发向该 address 的报文队列(阻塞队列) + basketMap.forEach((address, basket) -> { + if (basket.isEmpty()) { + return; + } + MergedWarpMessage mergeMessage = new MergedWarpMessage(); + while (!basket.isEmpty()) { + // 将同一个阻塞队列中所有 RpcMessage 进行合并 + RpcMessage msg = basket.poll(); + mergeMessage.msgs.add((AbstractMessage) msg.getBody()); + mergeMessage.msgIds.add(msg.getId()); + } + if (mergeMessage.msgIds.size() > 1) { + printMergeMessageLog(mergeMessage); + } + Channel sendChannel = null; + try { + // 批量发送报文是一个同步请求,但是无需获取返回值 + // 因为 messageFuture 在将报文放入 basketMap 之前就已经被创建 + // 返回值将在 ClientOnResponseProcessor 中被设置 + sendChannel = clientChannelManager.acquireChannel(address); + // 内部将 mergeMessage 封装为一个普通的 RpcMessage 发送 + AbstractNettyRemotingClient.this.sendAsyncRequest(sendChannel, mergeMessage); + } catch (FrameworkException e) { + if (e.getErrorCode() == FrameworkErrorCode.ChannelIsNotWritable && sendChannel != null) { + destroyChannel(address, sendChannel); + } + // fast fail + for (Integer msgId : mergeMessage.msgIds) { + MessageFuture messageFuture = futures.remove(msgId); + if (messageFuture != null) { + messageFuture.setResultMessage(new RuntimeException(String.format("%s is unreachable", address), e)); + } + } + LOGGER.error("client merge call failed: {}", e.getMessage(), e); + } + }); + isSending = false; + } + } +} +``` + +那么,与之相关的批量发送代码如下: + +```java +public Object sendSyncRequest(Object msg) throws TimeoutException { + String serverAddress = loadBalance(getTransactionServiceGroup(), msg); + long timeoutMillis = this.getRpcRequestTimeout(); + RpcMessage rpcMessage = buildRequestMessage(msg, ProtocolConstants.MSGTYPE_RESQUEST_SYNC); + // send batch message + // put message into basketMap, @see MergedSendRunnable + if (this.isEnableClientBatchSendRequest()) { + // 如果允许客户端批量消息发送 + // send batch message is sync request, needs to create messageFuture and put it in futures. + MessageFuture messageFuture = new MessageFuture(); + messageFuture.setRequestMessage(rpcMessage); + messageFuture.setTimeout(timeoutMillis); + futures.put(rpcMessage.getId(), messageFuture); + + // put message into basketMap + // 拿到 serverAddress 对应的发送队列 + BlockingQueue basket = CollectionUtils.computeIfAbsent(basketMap, serverAddress, + key -> new LinkedBlockingQueue<>()); + // 将报文添加到队列中,等待 mergeSendExecutorService 进行实际的发送 + if (!basket.offer(rpcMessage)) { + LOGGER.error("put message into basketMap offer failed, serverAddress: {}, rpcMessage: {}", serverAddress, rpcMessage); + return null; + } + if (!isSending) { + // 保证队列中一有数据,就唤醒线程,进行批量发送 + synchronized (mergeLock) { + mergeLock.notifyAll(); + } + } + try { + // 线程阻塞等待响应 + return messageFuture.get(timeoutMillis, TimeUnit.MILLISECONDS); + } catch (Exception exx) { + LOGGER.error("wait response error: {}, ip: {}, request: {}", exx.getMessage(), serverAddress, rpcMessage.getBody()); + if (exx instanceof TimeoutException) { + throw (TimeoutException) exx; + } else { + throw new RuntimeException(exx); + } + } + } else { + // 普通发送,拿到 channel 调父类的同步调用方法即可 + Channel channel = clientChannelManager.acquireChannel(serverAddress); + return super.sendSync(channel, rpcMessage, timeoutMillis); + } +} +``` + +可以看到,这里面也用到了对象锁的同步-等待机制,那么实现的效果就是: + +1. 最多隔 1ms 会遍历 basketMap 进行报文发送。 +2. 在 mergeSendExecutorService 内部的线程阻塞期间(mainLock.wait),如果来了需要发送的报文,那么会唤醒 mainLock 上的线程,继续进行发送。 + +那 Server 是怎么处理的呢?主要看 MergedWarpMessage 报文的 TypeCode,实际上就是 TYPE_SEATA_MERGE,再看 Server 启动的时候对这个 Code 注册哪个处理器,实际上就是 ServerOnRequestProcessor。 + +> 这里其实就向你展示了,如何去找某个报文是怎么处理的,授人以鱼不如授人以渔! + +在 ServerOnRequestProcessor 这边,实际上对应了两种处理 MergedWarpMessage 报文的方式: + +1. MergedWarpMessage 中的所有独立请求全部处理完毕之后,统一发送 MergeResultMessage。 +2. 由 batchResponseExecutorService 线程池处理发送任务,可以保证两点,一是当有报文结果就响应,即使线程 wait,也会将它 notify,二是至少 1ms 会响应一次,因为 batchResponseExecutorService 中执行的线程最多 wait 1ms。 + +注意,这两种方式响应的报文类型是不同的,第一种响应的是 MergeResultMessage,第二种是 BatchResultMessage,在 Client 也会有不同的处理。 + +ServerOnRequestProcessor 中核心处理方法如下: + +```java +private void onRequestMessage(ChannelHandlerContext ctx, RpcMessage rpcMessage) { + Object message = rpcMessage.getBody(); + RpcContext rpcContext = ChannelManager.getContextFromIdentified(ctx.channel()); + // the batch send request message + if (message instanceof MergedWarpMessage) { + final List msgs = ((MergedWarpMessage) message).msgs; + final List msgIds = ((MergedWarpMessage) message).msgIds; + // 允许 TC 服务端批量返回结果 && 客户端版本号 >= 1.5.0 + if (NettyServerConfig.isEnableTcServerBatchSendResponse() && StringUtils.isNotBlank(rpcContext.getVersion()) + && Version.isAboveOrEqualVersion150(rpcContext.getVersion())) { + // 由 batchResponseExecutorService 单独处理,无需等到批量请求全部处理完毕 + for (int i = 0; i < msgs.size(); i++) { + if (PARALLEL_REQUEST_HANDLE) { + int finalI = i; + CompletableFuture.runAsync( + () -> handleRequestsByMergedWarpMessageBy150(msgs.get(finalI), msgIds.get(finalI), rpcMessage, ctx, rpcContext)); + } else { + handleRequestsByMergedWarpMessageBy150(msgs.get(i), msgIds.get(i), rpcMessage, ctx, rpcContext); + } + } + } else { + // 每个请求都处理完毕,才能向客户端发出响应 + List results = new ArrayList<>(); + List> futures = new ArrayList<>(); + for (int i = 0; i < msgs.size(); i++) { + if (PARALLEL_REQUEST_HANDLE) { + int finalI = i; + futures.add(CompletableFuture.supplyAsync(() -> handleRequestsByMergedWarpMessage(msgs.get(finalI), rpcContext))); + } else { + results.add(i, handleRequestsByMergedWarpMessage(msgs.get(i), rpcContext)); + } + } + if (CollectionUtils.isNotEmpty(futures)) { + try { + for (CompletableFuture future : futures) { + results.add(future.get()); // 阻塞等待处理结果 + } + } catch (InterruptedException | ExecutionException e) { + LOGGER.error("handle request error: {}", e.getMessage(), e); + } + } + MergeResultMessage resultMessage = new MergeResultMessage(); + resultMessage.setMsgs(results.toArray(new AbstractResultMessage[0])); + remotingServer.sendAsyncResponse(rpcMessage, ctx.channel(), resultMessage); + } + } else { + // 处理单个报文响应 + } +} +``` + +而 handleRequestsByMergedWarpMessage 和 handleRequestsByMergedWarpMessageBy150 的区别就在于后者会将结果封装为 QueueItem 加入到阻塞队列由 batchResponseExecutorService 中的线程进行实际的发送,而前者仅仅是返回处理的结果。 + +```java +private AbstractResultMessage handleRequestsByMergedWarpMessage(AbstractMessage subMessage, RpcContext rpcContext) { + AbstractResultMessage resultMessage = transactionMessageHandler.onRequest(subMessage, rpcContext); + return resultMessage; +} + +private void handleRequestsByMergedWarpMessageBy150(AbstractMessage msg, int msgId, RpcMessage rpcMessage, + ChannelHandlerContext ctx, RpcContext rpcContext) { + AbstractResultMessage resultMessage = transactionMessageHandler.onRequest(msg, rpcContext); + // 拿到 channel 对应的发送队列 + BlockingQueue msgQueue = CollectionUtils.computeIfAbsent(basketMap, ctx.channel(), key -> new LinkedBlockingQueue<>()); + // 将结果添加到队列中,等待 batchResponseExecutorService 线程池实际进行发送 + if (!msgQueue.offer(new QueueItem(resultMessage, msgId, rpcMessage))) { + LOGGER.error("put message into basketMap offer failed, channel: {}, rpcMessage: {}, resultMessage: {}", ctx.channel(), rpcMessage, resultMessage); + } + if (!isResponding) { + // 保证队列中一有数据,就唤醒线程,进行批量发送 + synchronized (batchResponseLock) { + batchResponseLock.notifyAll(); + } + } +} +``` + +再来看 batchResponseExecutorService 线程池是怎么处理批量发送的任务的? + +```java +private class BatchResponseRunnable implements Runnable { + @Override + public void run() { + while (true) { + synchronized (batchResponseLock) { + try { + // 最多空闲 1ms + batchResponseLock.wait(MAX_BATCH_RESPONSE_MILLS); + } catch (InterruptedException e) { + LOGGER.error("BatchResponseRunnable Interrupted error", e); + } + } + isResponding = true; + // 遍历 basketMap 处理 + basketMap.forEach((channel, msgQueue) -> { + if (msgQueue.isEmpty()) { + return; + } + // Because the [serialization,compressor,rpcMessageId,headMap] of the response + // needs to be the same as the [serialization,compressor,rpcMessageId,headMap] of the request. + // Assemble by grouping according to the [serialization,compressor,rpcMessageId,headMap] dimensions. + // 将队列中的响应封装为 BatchResultMessage,但是注意并不是将所有的响应报文一次发送出去 + // 需要按照 [serialization,compressor,rpcMessageId,headMap] 进行分组,然后按组进行异步发送 + Map batchResultMessageMap = new HashMap<>(); + while (!msgQueue.isEmpty()) { + QueueItem item = msgQueue.poll(); + BatchResultMessage batchResultMessage = CollectionUtils.computeIfAbsent(batchResultMessageMap, + new ClientRequestRpcInfo(item.getRpcMessage()), + key -> new BatchResultMessage()); + batchResultMessage.getResultMessages().add(item.getResultMessage()); + batchResultMessage.getMsgIds().add(item.getMsgId()); + } + batchResultMessageMap.forEach((clientRequestRpcInfo, batchResultMessage) -> + remotingServer.sendAsyncResponse(buildRpcMessage(clientRequestRpcInfo), channel, batchResultMessage)); + }); + isResponding = false; + } + } +} +``` + +最后我们来看 Client 这边是怎么处理 Server 的批量响应报文的,根据 Client 注册的处理器,处理批量报文的处理器是 ClientOnResponseProcessor,如下: + +```java +public void process(ChannelHandlerContext ctx, RpcMessage rpcMessage) throws Exception { + // 处理 MergeResultMessage + if (rpcMessage.getBody() instanceof MergeResultMessage) { + MergeResultMessage results = (MergeResultMessage) rpcMessage.getBody(); + MergedWarpMessage mergeMessage = (MergedWarpMessage) mergeMsgMap.remove(rpcMessage.getId()); + for (int i = 0; i < mergeMessage.msgs.size(); i++) { + int msgId = mergeMessage.msgIds.get(i); + MessageFuture future = futures.remove(msgId); + if (future == null) { + LOGGER.error("msg: {} is not found in futures, result message: {}", msgId, results.getMsgs()[i]); + } else { + future.setResultMessage(results.getMsgs()[i]); + } + } + } else if (rpcMessage.getBody() instanceof BatchResultMessage) { + // 处理 BatchResultMessage + try { + BatchResultMessage batchResultMessage = (BatchResultMessage) rpcMessage.getBody(); + for (int i = 0; i < batchResultMessage.getMsgIds().size(); i++) { + int msgId = batchResultMessage.getMsgIds().get(i); + MessageFuture future = futures.remove(msgId); + if (future == null) { + LOGGER.error("msg: {} is not found in futures, result message: {}", msgId, batchResultMessage.getResultMessages().get(i)); + } else { + future.setResultMessage(batchResultMessage.getResultMessages().get(i)); + } + } + } finally { + // In order to be compatible with the old version, in the batch sending of version 1.5.0, + // batch messages will also be placed in the local cache of mergeMsgMap, + // but version 1.5.0 no longer needs to obtain batch messages from mergeMsgMap + mergeMsgMap.clear(); + } + } else { + // 处理非批量发送报文 + MessageFuture messageFuture = futures.remove(rpcMessage.getId()); + if (messageFuture != null) { + messageFuture.setResultMessage(rpcMessage.getBody()); + } else { + if (rpcMessage.getBody() instanceof AbstractResultMessage) { + if (transactionMessageHandler != null) { + transactionMessageHandler.onResponse((AbstractResultMessage) rpcMessage.getBody(), null); + } + } + } + } +} +``` + +当然,这里处理的逻辑很简单,就是将结果塞到对应的 MessageFuture 中,那么最开始发送请求的、阻塞的线程就可以拿到结果了,这样一次批量发送和响应就算处理完毕了。 + +我们再做一些额外的思考,Seata 的批量发送为什么有两种方式,孰优孰劣? + +对于 MergeResultMessage 的这种方式来说,它必须等到所有的报文都处理完毕之后才会发送出去,所以其实它的响应速度受限于处理最长时间的报文,即使其他报文在很短时间内就可以发送出去。 + +而 BatchResultMessage 这种方式则不然,配合 CompletableFuture 进行并行处理,它就可以实现一有报文处理完毕就发送,而不需要等其他报文的处理,它的响应速度肯定是更快的。 + +而后面这种方式是 Seata 1.5 版本之后才有的,其实也可以看出来这是一种更好地处理方式。 + +最后,再分享一张 Seata RPC 重构作者的全局事务提交请求的交互流程图: + +![image-20241217222048505](/img/blog/seata-rpc.png) + +## Seata 如何管理 Channel + +在整个 TC、TM、RM 的网络通信的过程中,Channel 是一个至关重要的通信组件,而要想知道 Seata 是怎么管理 Channel 的,最容易想到的入口就是看 Server 和 Client 发送报文时是从哪里拿到到 Channel 的。 + +在 AbstractNettyRemotingClient 类的 sendSyncRequest 中,我们可以看到下面的代码: + +```java +public Object sendSyncRequest(Object msg) throws TimeoutException { + // ... + // Client 通过 NettyClientChannelManager 获取 Channel + Channel channel = clientChannelManager.acquireChannel(serverAddress); + return super.sendSync(channel, rpcMessage, timeoutMillis); +} +``` + +而在 AbstractNettyRemotingServer 类的 sendSyncRequest 中,我们可以看到下面的代码: + +```java +public Object sendSyncRequest(String resourceId, String clientId, Object msg, boolean tryOtherApp) throws TimeoutException { + // Server 通过 ChannelManager 拿到 Channel + Channel channel = ChannelManager.getChannel(resourceId, clientId, tryOtherApp); + if (channel == null) { + throw new RuntimeException("rm client is not connected. dbkey:" + resourceId + ",clientId:" + clientId); + } + RpcMessage rpcMessage = buildRequestMessage(msg, ProtocolConstants.MSGTYPE_RESQUEST_SYNC); + return super.sendSync(channel, rpcMessage, NettyServerConfig.getRpcRequestTimeout()); +} +``` + +所以 Client 主要是通过 NettyClientChannelManager 中获取 Channel,而 Server 则是根据 resourceId 和 clientId 从 ChannelManager 中获取 Channel。 + +所以下面我们主要研究的就是这两个类,以及相关的一些逻辑。 + +### Client Channel + +我们先来看 Client 这边是怎么管理 Channel 的,核心类是 NettyClientChannelManager。 + +先简单看一下这个类的属性, + +```java +// serverAddress -> lock +private final ConcurrentMap channelLocks = new ConcurrentHashMap<>(); +// serverAddress -> NettyPoolKey +private final ConcurrentMap poolKeyMap = new ConcurrentHashMap<>(); +// serverAddress -> Channel +private final ConcurrentMap channels = new ConcurrentHashMap<>(); +// 对象池,NettyPoolKey -> Channel +private final GenericKeyedObjectPool nettyClientKeyPool; +// 函数式接口,封装了通过 serverAddress 获取 NettyPoolKey 的逻辑 +private final Function poolKeyFunction; +``` + +#### 对象池的核心类 + +Seata 使用了 GenericKeyedObjectPool 作为管理 Channel 的对象池。 + +GenericKeyedObjectPool 作为 Apache Commons Pool 库中的一个实现,它主要用于管理一组对象池,每个对象通过唯一的 Key 进行区分,可以支持多类型的对象池化需求。 + +在使用 GenericKeyedObjectPool 时,通常还需要配置 KeyedPoolableObjectFactory 工厂,这个工厂定义了如何创建、验证、激活、钝化以及销毁池中的对象。 + +当 GenericKeyedObjectPool 需要创建对象时会调用 KeyedPoolableObjectFactory 工厂的 makeObject 方法,当需要销毁时会调用 destroyObject 方法进行销毁 …… + +#### 如何池化 Channel + +被池化的对象就是 Channel,而对应的 Key 是 NettyPoolKey,如下: + +```java +public class NettyPoolKey { + + private TransactionRole transactionRole; + private String address; + private AbstractMessage message; + + // ... +} +``` + +在 NettyPoolKey 中,维护了三个信息,事务角色(TM、RM、Server),目的 TC Server 地址,以及在 Client 连接 Server 时发送的 RPC 报文。 + +如何创建这个 NettyPoolKey 呢?在 Seata 中,客户端其实是有两种角色的,TM 和 RM,创建的逻辑肯定是不一样的,所以,Seata 在 AbstractNettyRemotingClient 中抽象了一个方法,它的返回值是一个函数式接口,这个函数式接口就封装了根据 serverAddress 创建 NettyPoolKey 的逻辑。 + +```java +// org.apache.seata.core.rpc.netty.AbstractNettyRemotingClient#getPoolKeyFunction +protected abstract Function getPoolKeyFunction(); +``` + +比如在 TM 中的实现是: + +```java +protected Function getPoolKeyFunction() { + return severAddress -> { + RegisterTMRequest message = new RegisterTMRequest(applicationId, transactionServiceGroup, getExtraData()); + return new NettyPoolKey(NettyPoolKey.TransactionRole.TM_ROLE, severAddress, message); + }; +} +``` + +而在 RM 中的实现是: + +```java +protected Function getPoolKeyFunction() { + return serverAddress -> { + String resourceIds = getMergedResourceKeys(); + if (resourceIds != null && LOGGER.isInfoEnabled()) { + LOGGER.info("RM will register: {}", resourceIds); + } + RegisterRMRequest message = new RegisterRMRequest(applicationId, transactionServiceGroup); + message.setResourceIds(resourceIds); + return new NettyPoolKey(NettyPoolKey.TransactionRole.RM_ROLE, serverAddress, message); + }; +} +``` + +从这里就可以看到,TM 在连接 Server 后发送的报文是 RegisterTMRequest,而 RM 是 RegisterRMRequest。 + +那这个函数式接口在什么时候被调用呢,后面再看。 + +我们前面也说到了,一个对象池,会配备对应的对象创建工厂 KeyedPoolableObjectFactory,在 Seata 中,以 NettyPoolableFactory 继承 KeyedPoolableObjectFactory 来实现。 + +```java +/** + * Netty Channel 创建工厂,通过 NettyPoolKey 创建 Channel,该类的方法必须是线程安全的 + */ +public class NettyPoolableFactory implements KeyedPoolableObjectFactory { + + // ... + + /** + * 需要一个新的实例则调用该方法 + */ + @Override + public Channel makeObject(NettyPoolKey key) { + InetSocketAddress address = NetUtil.toInetSocketAddress(key.getAddress()); + // 创建 Channel,本质上就是通过 bootstrap.connect 连接到 Seata Server 返回 Channel + Channel tmpChannel = clientBootstrap.getNewChannel(address); + long start = System.currentTimeMillis(); + Object response; + Channel channelToServer = null; + if (key.getMessage() == null) { + throw new FrameworkException("register msg is null, role:" + key.getTransactionRole().name()); + } + try { + // 发送 Message,TM 就是 RegisterTMRequest,RM 就是 RegisterRMRequest + response = rpcRemotingClient.sendSyncRequest(tmpChannel, key.getMessage()); + // 根据 response 判断是否注册成功 + if (!isRegisterSuccess(response, key.getTransactionRole())) { + rpcRemotingClient.onRegisterMsgFail(key.getAddress(), tmpChannel, response, key.getMessage()); + } else { + // 注册成功 + channelToServer = tmpChannel; + // 将 serverAddress 作为 key,Channel 作为 value,添加到 NettyClientChannelManager.channels 中 + // 如果是 RM 可能还需要将 Server 注册 resources + rpcRemotingClient.onRegisterMsgSuccess(key.getAddress(), tmpChannel, response, key.getMessage()); + } + } catch (Exception exx) { + if (tmpChannel != null) { + tmpChannel.close(); + } + throw new FrameworkException("register " + key.getTransactionRole().name() + " error, errMsg:" + exx.getMessage()); + } + return channelToServer; + } + + // ... + + @Override + public void destroyObject(NettyPoolKey key, Channel channel) throws Exception { + if (channel != null) { + channel.disconnect(); + channel.close(); + } + } + + /** + * 需要借用对象时会调用该方法校验对象有效性(可选) + */ + @Override + public boolean validateObject(NettyPoolKey key, Channel obj) { + if (obj != null && obj.isActive()) { + return true; + } + return false; + } + + /** + * 需要借用对象时会调用该方法激活对象 + */ + @Override + public void activateObject(NettyPoolKey key, Channel obj) throws Exception {} + + /** + * 归还对象时会调用该方法钝化对象 + */ + @Override + public void passivateObject(NettyPoolKey key, Channel obj) throws Exception {} +} +``` + +#### 获取 Channel + +在整个 Seata 客户端,有三个口径可以获取 Channel,即初始化、定时重连,发送报文时获取 Channel。 + +```java +// 口径一 +private void initConnection() { + boolean failFast = + ConfigurationFactory.getInstance().getBoolean(ConfigurationKeys.ENABLE_TM_CLIENT_CHANNEL_CHECK_FAIL_FAST, DefaultValues.DEFAULT_CLIENT_CHANNEL_CHECK_FAIL_FAST); + getClientChannelManager().initReconnect(transactionServiceGroup, failFast); +} + +// 口径二 +public void init() { + // 默认延时 60s 定时 10s 周期重连 + timerExecutor.scheduleAtFixedRate(() -> { + try { + clientChannelManager.reconnect(getTransactionServiceGroup()); + } catch (Exception ex) { + LOGGER.warn("reconnect server failed. {}", ex.getMessage()); + } + }, SCHEDULE_DELAY_MILLS, SCHEDULE_INTERVAL_MILLS, TimeUnit.MILLISECONDS); + // ... +} + +// 口径三 +public Object sendSyncRequest(Object msg) throws TimeoutException { + // ... + // Client 通过 NettyClientChannelManager 获取 Channel + Channel channel = clientChannelManager.acquireChannel(serverAddress); + return super.sendSync(channel, rpcMessage, timeoutMillis); +} +``` + +不过,这三个口径最后都会调用到 clientChannelManager 的 acquireChannel 方法获取 Channel。 + +```java +/** + * 根据 serverAddress 拿到 Channel,如果 Channel 不存在或者连接已死则需要重新建立连接 + */ +Channel acquireChannel(String serverAddress) { + // 从 channels 中根据 serverAddress 拿到 Channel + Channel channelToServer = channels.get(serverAddress); + if (channelToServer != null) { + channelToServer = getExistAliveChannel(channelToServer, serverAddress); + if (channelToServer != null) { + return channelToServer; + } + } + // 如果 channels 没有这个 Channel 或者这个 Channel 已死,则需要对这个地址建立连接 + Object lockObj = CollectionUtils.computeIfAbsent(channelLocks, serverAddress, key -> new Object()); + synchronized (lockObj) { + // 建立连接 + return doConnect(serverAddress); + } +} + +private Channel doConnect(String serverAddress) { + // 再尝试拿一次 + Channel channelToServer = channels.get(serverAddress); + if (channelToServer != null && channelToServer.isActive()) { + return channelToServer; + } + Channel channelFromPool; + try { + // 这里就调用了函数式接口 + NettyPoolKey currentPoolKey = poolKeyFunction.apply(serverAddress); + poolKeyMap.put(serverAddress, currentPoolKey); + // 从对象池中 borrowObject,如果需要创建对象,则会调用工厂的 makeObject 方法, + // 该方法内部就会向 Server 进行 connect,并且发送 currentPoolKey.message 的报文 + channelFromPool = nettyClientKeyPool.borrowObject(currentPoolKey); + channels.put(serverAddress, channelFromPool); + } catch (Exception exx) { + LOGGER.error("{} register RM failed.", FrameworkErrorCode.RegisterRM.getErrCode(), exx); + throw new FrameworkException("can not register RM,err:" + exx.getMessage()); + } + return channelFromPool; +} +``` + +### Server Channel + +而在 Server 这边,基本上有关 Channe 管理的核心逻辑都在 ChannelManager 中,那 Server 这边的 Channel 是怎么来的呢?还记得在 Client 那边向 Server 发起连接,成功之后还会发送 TM 和 RM 的一个注册请求。 + +这里先来看看 Server 是怎么处理这些 registerRequest 的。 + +#### 处理 Client 注册 + +与之相关的处理器是 RegRmProcessor 和 RegTmProcessor,在这两个处理器中,最核心的逻辑就是调用 ChannelManager 的 registerTMChannel 和 registerRMChannel 方法。 + +```java +public static void registerTMChannel(RegisterTMRequest request, Channel channel) throws IncompatibleVersionException { + // 构建 RpcContext,这个 RpcContext 就是维护了客户端连接信息上下文 + RpcContext rpcContext = buildChannelHolder(NettyPoolKey.TransactionRole.TM_ROLE, request.getVersion(), + request.getApplicationId(), + request.getTransactionServiceGroup(), + null, channel); + // 将 Channel 作为 key,rpcContext 作为 value,put 到 IDENTIFIED_CHANNELS 中 + rpcContext.holdInIdentifiedChannels(IDENTIFIED_CHANNELS); + // applicationId:clientIp + String clientIdentified = rpcContext.getApplicationId() + Constants.CLIENT_ID_SPLIT_CHAR + ChannelUtil.getClientIpFromChannel(channel); + // 将 Channel 信息存储到 TM_CHANNELS 中 + ConcurrentMap clientIdentifiedMap = CollectionUtils.computeIfAbsent(TM_CHANNELS, clientIdentified, key -> new ConcurrentHashMap<>()); + rpcContext.holdInClientChannels(clientIdentifiedMap); +} + +public static void registerRMChannel(RegisterRMRequest resourceManagerRequest, Channel channel) throws IncompatibleVersionException { + Set dbkeySet = dbKeytoSet(resourceManagerRequest.getResourceIds()); + RpcContext rpcContext; + if (!IDENTIFIED_CHANNELS.containsKey(channel)) { + // 构建 RpcContext 和 IDENTIFIED_CHANNELS + rpcContext = buildChannelHolder(NettyPoolKey.TransactionRole.RM_ROLE, resourceManagerRequest.getVersion(), + resourceManagerRequest.getApplicationId(), resourceManagerRequest.getTransactionServiceGroup(), + resourceManagerRequest.getResourceIds(), channel); + rpcContext.holdInIdentifiedChannels(IDENTIFIED_CHANNELS); + } else { + rpcContext = IDENTIFIED_CHANNELS.get(channel); + rpcContext.addResources(dbkeySet); + } + if (dbkeySet == null || dbkeySet.isEmpty()) { + return; + } + for (String resourceId : dbkeySet) { + String clientIp; + // 维护 RM_CHANNELS 信息 + ConcurrentMap portMap = CollectionUtils.computeIfAbsent(RM_CHANNELS, resourceId, key -> new ConcurrentHashMap<>()) + .computeIfAbsent(resourceManagerRequest.getApplicationId(), key -> new ConcurrentHashMap<>()) + .computeIfAbsent(clientIp = ChannelUtil.getClientIpFromChannel(channel), key -> new ConcurrentHashMap<>()); + rpcContext.holdInResourceManagerChannels(resourceId, portMap); + updateChannelsResource(resourceId, clientIp, resourceManagerRequest.getApplicationId()); + } +} +``` + +这两个方法逻辑很简单,就是基于注册请求和 Channel 的信息构建 RpcContext,维护 Server 内的相关 Map 集合,IDENTIFIED_CHANNELS、RM_CHANNELS、TM_CHANNELS。 + +但是,说实话,这几个集合实在是嵌套的有点深,不知道能不能优化一下。 + +```java +/** + * Channel -> RpcContext + */ +private static final ConcurrentMap IDENTIFIED_CHANNELS = new ConcurrentHashMap<>(); + +/** + * resourceId -> applicationId -> ip -> port -> RpcContext + */ +// resourceId applicationId ip +private static final ConcurrentMap>>> RM_CHANNELS = new ConcurrentHashMap<>(); + +/** + * applicationId:clientIp -> port -> RpcContext + */ +private static final ConcurrentMap> TM_CHANNELS = new ConcurrentHashMap<>(); +``` + +#### 获取 Channel + +在 Server 这边,获取 Channel 的逻辑,真的是超长,感兴趣自己看看吧,本质上就是从 map 中拿到一个有效的 Channel。 + +```java +public static Channel getChannel(String resourceId, String clientId, boolean tryOtherApp) { + Channel resultChannel = null; + // 解析 ClientId,三部分组成:applicationId + clientIp + clientPort + String[] clientIdInfo = parseClientId(clientId); + if (clientIdInfo == null || clientIdInfo.length != 3) { + throw new FrameworkException("Invalid Client ID: " + clientId); + } + if (StringUtils.isBlank(resourceId)) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("No channel is available, resourceId is null or empty"); + } + return null; + } + // applicationId + String targetApplicationId = clientIdInfo[0]; + // clientIp + String targetIP = clientIdInfo[1]; + // clientPort + int targetPort = Integer.parseInt(clientIdInfo[2]); + // 下面就是不断取出内层的 ConcurrentHashMap + ConcurrentMap>> applicationIdMap = RM_CHANNELS.get(resourceId); + if (targetApplicationId == null || applicationIdMap == null || applicationIdMap.isEmpty()) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("No channel is available for resource[{}]", resourceId); + } + return null; + } + ConcurrentMap> ipMap = applicationIdMap.get(targetApplicationId); + if (ipMap != null && !ipMap.isEmpty()) { + // Firstly, try to find the original channel through which the branch was registered. + // 端口 -> RpcContext + ConcurrentMap portMapOnTargetIP = ipMap.get(targetIP); + /** + * 在 targetIp 上拿 Channel + */ + if (portMapOnTargetIP != null && !portMapOnTargetIP.isEmpty()) { + RpcContext exactRpcContext = portMapOnTargetIP.get(targetPort); + if (exactRpcContext != null) { + Channel channel = exactRpcContext.getChannel(); + if (channel.isActive()) { + // Channel 有效,则跳过下面所有的 if 返回这个 Channel + resultChannel = channel; + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Just got exactly the one {} for {}", channel, clientId); + } + } else { + if (portMapOnTargetIP.remove(targetPort, exactRpcContext)) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Removed inactive {}", channel); + } + } + } + } + // The original channel was broken, try another one. + if (resultChannel == null) { + // 尝试当前节点上的其他端口 + for (ConcurrentMap.Entry portMapOnTargetIPEntry : portMapOnTargetIP.entrySet()) { + Channel channel = portMapOnTargetIPEntry.getValue().getChannel(); + if (channel.isActive()) { + resultChannel = channel; + if (LOGGER.isInfoEnabled()) { + LOGGER.info( + "Choose {} on the same IP[{}] as alternative of {}", channel, targetIP, clientId); + } + break; + } else { + if (portMapOnTargetIP.remove(portMapOnTargetIPEntry.getKey(), + portMapOnTargetIPEntry.getValue())) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Removed inactive {}", channel); + } + } + } + } + } + } + /** + * 在 targetApplicationId 上拿 Channel + */ + // No channel on the app node, try another one. + if (resultChannel == null) { + for (ConcurrentMap.Entry> ipMapEntry : ipMap.entrySet()) { + if (ipMapEntry.getKey().equals(targetIP)) { + continue; + } + ConcurrentMap portMapOnOtherIP = ipMapEntry.getValue(); + if (portMapOnOtherIP == null || portMapOnOtherIP.isEmpty()) { + continue; + } + for (ConcurrentMap.Entry portMapOnOtherIPEntry : portMapOnOtherIP.entrySet()) { + Channel channel = portMapOnOtherIPEntry.getValue().getChannel(); + if (channel.isActive()) { + resultChannel = channel; + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Choose {} on the same application[{}] as alternative of {}", channel, targetApplicationId, clientId); + } + break; + } else { + if (portMapOnOtherIP.remove(portMapOnOtherIPEntry.getKey(), portMapOnOtherIPEntry.getValue())) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Removed inactive {}", channel); + } + } + } + } + if (resultChannel != null) { + break; + } + } + } + } + if (resultChannel == null && tryOtherApp) { + // 尝试其他 applicationId + resultChannel = tryOtherApp(applicationIdMap, targetApplicationId); + if (resultChannel == null) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("No channel is available for resource[{}] as alternative of {}", resourceId, clientId); + } + } else { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Choose {} on the same resource[{}] as alternative of {}", resultChannel, resourceId, clientId); + } + } + } + return resultChannel; +} + +private static Channel tryOtherApp(ConcurrentMap>> applicationIdMap, String myApplicationId) { + Channel chosenChannel = null; + for (ConcurrentMap.Entry>> applicationIdMapEntry : applicationIdMap.entrySet()) { + if (!StringUtils.isNullOrEmpty(myApplicationId) && applicationIdMapEntry.getKey().equals(myApplicationId)) { + continue; + } + ConcurrentMap> targetIPMap = applicationIdMapEntry.getValue(); + if (targetIPMap == null || targetIPMap.isEmpty()) { + continue; + } + for (ConcurrentMap.Entry> targetIPMapEntry : targetIPMap.entrySet()) { + ConcurrentMap portMap = targetIPMapEntry.getValue(); + if (portMap == null || portMap.isEmpty()) { + continue; + } + for (ConcurrentMap.Entry portMapEntry : portMap.entrySet()) { + Channel channel = portMapEntry.getValue().getChannel(); + if (channel.isActive()) { + chosenChannel = channel; + break; + } else { + if (portMap.remove(portMapEntry.getKey(), portMapEntry.getValue())) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Removed inactive {}", channel); + } + } + } + } + if (chosenChannel != null) { + break; + } + } + if (chosenChannel != null) { + break; + } + } + return chosenChannel; +} +``` + +### 一图总结 + +最后,再以一个时序图来总结一下 Channel 的管理过程。 + +![image-20241217222155609](/img/blog/seata-channel.png) + +## Seata 如何设计协议 + +对于一个网络程序而言,通信协议是必不可少的,Seata 也不例外,这里我们就看看 Seata V1 版本的协议是如何实现的。 + +与之相关类主要有 ProtocolEncoderV1、ProtocolDecoderV1。 + +当然,我们前面也知道 Seata Server 启动时加入的处理器其实是 MultiProtocolDecoder,在这个类的 decode 方法中,如下: + +```java +protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { + ByteBuf frame; + Object decoded; + byte version; + try { + if (isV0(in)) { + decoded = in; + version = ProtocolConstants.VERSION_0; + } else { + decoded = super.decode(ctx, in); + version = decideVersion(decoded); + } + if (decoded instanceof ByteBuf) { + frame = (ByteBuf) decoded; + // 通过 MultiProtocolDecoder 进行多版本协议识别 + // 通过 version 选择对应的编解码器 + ProtocolDecoder decoder = protocolDecoderMap.get(version); + ProtocolEncoder encoder = protocolEncoderMap.get(version); + try { + if (decoder == null || encoder == null) { + throw new UnsupportedOperationException("Unsupported version: " + version); + } + return decoder.decodeFrame(frame); + } finally { + if (version != ProtocolConstants.VERSION_0) { + frame.release(); + } + // 将选定的编解码器加入到 pipeline,并且移除 MultiProtocolDecoder + ctx.pipeline().addLast((ChannelHandler) decoder); + ctx.pipeline().addLast((ChannelHandler) encoder); + if (channelHandlers != null) { + ctx.pipeline().addLast(channelHandlers); + } + ctx.pipeline().remove(this); + } + } + } catch (Exception exx) { + LOGGER.error("Decode frame error, cause: {}", exx.getMessage()); + throw new DecodeException(exx); + } + return decoded; +} +``` + +所以,这里选择好与 version 对应的编解码器,然后加入到 pipeline 中,就会将 MultiProtocolDecoder 移除。 + +### V1 版本协议 + +Seata 的协议设计是比较周全并且通用的,也是主流的解决粘包半包问题的解决方案,即消息长度 + 消息内容。 + +协议的格式如下: + +![image-20241217222155609](/img/blog/seata-protocol.png) + +可以看到,包括魔数、协议版本号、长度域、头长度、报文类型、序列化算法、压缩算法、请求 id、可选的 map 扩展以及报文体。 + +### 如何进行编解码 + +Seata 解码器使用了 Netty 内置的 LengthFieldBasedFrameDecoder,不熟悉的可以看看。 + +不过编解码并不难,所以简单给出代码,不过多解释。 + +```java +package org.apache.seata.core.rpc.netty.v1; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; +import org.apache.seata.core.rpc.netty.ProtocolEncoder; +import org.apache.seata.core.serializer.Serializer; +import org.apache.seata.core.compressor.Compressor; +import org.apache.seata.core.compressor.CompressorFactory; +import org.apache.seata.core.protocol.ProtocolConstants; +import org.apache.seata.core.protocol.RpcMessage; +import org.apache.seata.core.serializer.SerializerServiceLoader; +import org.apache.seata.core.serializer.SerializerType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +/** + *
    + * 0     1     2     3     4     5     6     7     8     9    10     11    12    13    14    15    16
    + * +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    + * |   magic   |proto|     full length       |    head   | Msg |Seria|Compr|      RequestId        |
    + * |   code    |versi|     (head+body)       |   length  |Type |lizer|ess  |                       |
    + * +-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
    + * |                                   Head Map [Optional]                                         |
    + * +-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
    + * |                                         body                                                  |
    + * +-----------------------------------------------------------------------------------------------+
    + * 
    + *

    + *

  • Full Length: include all data
  • + *
  • Head Length: include head data from magic code to head map.
  • + *
  • Body Length: Full Length - Head Length
  • + *

    + */ +public class ProtocolEncoderV1 extends MessageToByteEncoder implements ProtocolEncoder { + + private static final Logger LOGGER = LoggerFactory.getLogger(ProtocolEncoderV1.class); + + public void encode(RpcMessage message, ByteBuf out) { + try { + ProtocolRpcMessageV1 rpcMessage = new ProtocolRpcMessageV1(); + rpcMessage.rpcMsgToProtocolMsg(message); + int fullLength = ProtocolConstants.V1_HEAD_LENGTH; + int headLength = ProtocolConstants.V1_HEAD_LENGTH; + byte messageType = rpcMessage.getMessageType(); + out.writeBytes(ProtocolConstants.MAGIC_CODE_BYTES); + out.writeByte(ProtocolConstants.VERSION_1); + // full Length(4B) and head length(2B) will fix in the end. + out.writerIndex(out.writerIndex() + 6); // 这里跳过 full length 和 head length 的位置,最后在补 + out.writeByte(messageType); + out.writeByte(rpcMessage.getCodec()); + out.writeByte(rpcMessage.getCompressor()); + out.writeInt(rpcMessage.getId()); + // direct write head with zero-copy + Map headMap = rpcMessage.getHeadMap(); + if (headMap != null && !headMap.isEmpty()) { + int headMapBytesLength = HeadMapSerializer.getInstance().encode(headMap, out); + headLength += headMapBytesLength; + fullLength += headMapBytesLength; + } + byte[] bodyBytes = null; + // heartbeat don't have body + if (messageType != ProtocolConstants.MSGTYPE_HEARTBEAT_REQUEST && messageType != ProtocolConstants.MSGTYPE_HEARTBEAT_RESPONSE) { + Serializer serializer = SerializerServiceLoader.load(SerializerType.getByCode(rpcMessage.getCodec()), ProtocolConstants.VERSION_1); + bodyBytes = serializer.serialize(rpcMessage.getBody()); + Compressor compressor = CompressorFactory.getCompressor(rpcMessage.getCompressor()); + bodyBytes = compressor.compress(bodyBytes); + fullLength += bodyBytes.length; + } + if (bodyBytes != null) { + out.writeBytes(bodyBytes); + } + // fix fullLength and headLength + int writeIndex = out.writerIndex(); + // skip magic code(2B) + version(1B) + out.writerIndex(writeIndex - fullLength + 3); + out.writeInt(fullLength); + out.writeShort(headLength); + out.writerIndex(writeIndex); + } catch (Throwable e) { + LOGGER.error("Encode request error!", e); + throw e; + } + } + + @Override + protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception { + try { + if (msg instanceof RpcMessage) { + this.encode((RpcMessage) msg, out); + } else { + throw new UnsupportedOperationException("Not support this class:" + msg.getClass()); + } + } catch (Throwable e) { + LOGGER.error("Encode request error!", e); + } + } +} +``` + +```java +package org.apache.seata.core.rpc.netty.v1; + +import java.util.List; +import java.util.Map; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.apache.seata.core.compressor.Compressor; +import org.apache.seata.core.compressor.CompressorFactory; +import org.apache.seata.core.exception.DecodeException; +import org.apache.seata.core.protocol.HeartbeatMessage; +import org.apache.seata.core.protocol.ProtocolConstants; +import org.apache.seata.core.protocol.RpcMessage; +import org.apache.seata.core.rpc.netty.ProtocolDecoder; +import org.apache.seata.core.serializer.Serializer; +import org.apache.seata.core.serializer.SerializerServiceLoader; +import org.apache.seata.core.serializer.SerializerType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + *
    + * 0     1     2     3     4     5     6     7     8     9    10     11    12    13    14    15    16
    + * +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    + * |   magic   |proto|     full length       |    head   | Msg |Seria|Compr|      RequestId        |
    + * |   code    |versi|     (head+body)       |   length  |Type |lizer|ess  |                       |
    + * +-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
    + * |                                   Head Map [Optional]                                         |
    + * +-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
    + * |                                         body                                                  |
    + * +-----------------------------------------------------------------------------------------------+
    + * 
    + *

    + *

  • Full Length: include all data
  • + *
  • Head Length: include head data from magic code to head map.
  • + *
  • Body Length: Full Length - Head Length
  • + *

    + */ +public class ProtocolDecoderV1 extends LengthFieldBasedFrameDecoder implements ProtocolDecoder { + + private static final Logger LOGGER = LoggerFactory.getLogger(ProtocolDecoderV1.class); + + private final List supportDeSerializerTypes; + + public ProtocolDecoderV1() { + /** + * int maxFrameLength, + * int lengthFieldOffset, 魔术 2B、版本号 1B 所以长度偏移 3B + * int lengthFieldLength, FullLength is int(4B). so values is 4 + * int lengthAdjustment, FullLength include all data and read 7 bytes before, so the left length is (FullLength-7). so values is -7 + * int initialBytesToStrip we will check magic code and version self, so do not strip any bytes. so values is 0 + */ + super(ProtocolConstants.MAX_FRAME_LENGTH, 3, 4, -7, 0); + supportDeSerializerTypes = SerializerServiceLoader.getSupportedSerializers(); + if (supportDeSerializerTypes.isEmpty()) { + throw new IllegalArgumentException("No serializer found"); + } + } + + @Override + public RpcMessage decodeFrame(ByteBuf frame) { + byte b0 = frame.readByte(); + byte b1 = frame.readByte(); + if (ProtocolConstants.MAGIC_CODE_BYTES[0] != b0 || ProtocolConstants.MAGIC_CODE_BYTES[1] != b1) { + throw new IllegalArgumentException("Unknown magic code: " + b0 + ", " + b1); + } + byte version = frame.readByte(); + int fullLength = frame.readInt(); + short headLength = frame.readShort(); + byte messageType = frame.readByte(); + byte codecType = frame.readByte(); + byte compressorType = frame.readByte(); + int requestId = frame.readInt(); + ProtocolRpcMessageV1 rpcMessage = new ProtocolRpcMessageV1(); + rpcMessage.setCodec(codecType); + rpcMessage.setId(requestId); + rpcMessage.setCompressor(compressorType); + rpcMessage.setMessageType(messageType); + // direct read head with zero-copy + int headMapLength = headLength - ProtocolConstants.V1_HEAD_LENGTH; + if (headMapLength > 0) { + Map map = HeadMapSerializer.getInstance().decode(frame, headMapLength); + rpcMessage.getHeadMap().putAll(map); + } + // read body + if (messageType == ProtocolConstants.MSGTYPE_HEARTBEAT_REQUEST) { + rpcMessage.setBody(HeartbeatMessage.PING); + } else if (messageType == ProtocolConstants.MSGTYPE_HEARTBEAT_RESPONSE) { + rpcMessage.setBody(HeartbeatMessage.PONG); + } else { + int bodyLength = fullLength - headLength; + if (bodyLength > 0) { + byte[] bs = new byte[bodyLength]; + frame.readBytes(bs); + Compressor compressor = CompressorFactory.getCompressor(compressorType); + bs = compressor.decompress(bs); + SerializerType protocolType = SerializerType.getByCode(rpcMessage.getCodec()); + if (this.supportDeSerializerTypes.contains(protocolType)) { + Serializer serializer = SerializerServiceLoader.load(protocolType, ProtocolConstants.VERSION_1); + rpcMessage.setBody(serializer.deserialize(bs)); + } else { + throw new IllegalArgumentException("SerializerType not match"); + } + } + } + return rpcMessage.protocolMsgToRpcMsg(); + } + + @Override + protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { + Object decoded; + try { + decoded = super.decode(ctx, in); + if (decoded instanceof ByteBuf) { + ByteBuf frame = (ByteBuf) decoded; + try { + return decodeFrame(frame); + } finally { + frame.release(); + } + } + } catch (Exception exx) { + LOGGER.error("Decode frame error, cause: {}", exx.getMessage()); + throw new DecodeException(exx); + } + return decoded; + } +} +``` + +## 总结 + +就目前看来,Seata 的网络通信实现的是比较容易看懂的,不过,这篇文章的分析也仅仅只是浮于表面,对深层次的更加重要的代码健壮性、异常处理、优雅关闭等问题都没有聊到,看后面有新的理解再分析分析。 + +[原文链接](https://blog.hein-hp.click/article/5p94ivva/) \ No newline at end of file diff --git a/static/img/blog/class-level.png b/static/img/blog/class-level.png new file mode 100644 index 0000000000000000000000000000000000000000..a1e24768ed38bc6006231b33f83adc02b2ed712c GIT binary patch literal 70810 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ð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 F{{RLFR>%MV literal 0 HcmV?d00001 diff --git a/static/img/blog/seata-channel.png b/static/img/blog/seata-channel.png new file mode 100644 index 0000000000000000000000000000000000000000..35fd57a4de19deb8bc6f42f29a2aa2a627a36ef5 GIT binary patch literal 91113 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⁡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 ZIo?q_@!pZ9mEmFwd2m?J%^fix`~zmV!r1@- literal 0 HcmV?d00001