Fescar example解析 - TM傳送邏輯
開篇
這篇文章的目的主要是理清楚Fescar的TM傳送部分的邏輯,從時序圖和原始碼兩個層面進行分析。
文章中間會解答兩個自己閱讀程式碼中遇到的困惑(估計大部分人看程式碼的時候也會遇到這個困惑),包括TmRpcClient的初始化過程和配置載入過程。
文章的最後會附上GlobalAction相關Request的類關係圖,便於理解依賴關係。
Fescar TM傳送流程
說明:
1.DefaultGlobalTransaction執行begin/commit/rollback等呼叫DefaultTransactionManager。
2.DefaultTransactionManager內部呼叫syncCall()方法,進而呼叫TmRpcClient的sendMsgWithResponse()方法。
3.TmRpcClient呼叫父類AbstractRpcRemoting的sendAsyncRequest()方法構建傳送佇列。
4.AbstractRpcRemotingClient的MergedSendRunnable執行緒消費傳送佇列構建MergedWarpMessage呼叫sendRequest傳送。
5.sendRequest()方法內部呼叫writeAndFlush完成訊息傳送。
說明:
TmRpcClient的類依賴關係圖如上。
TmRpcClient繼承自AbstractRpcRemotingClient類。
Fescar TM傳送原始碼分析
public class DefaultTransactionManager implements TransactionManager {
private static class SingletonHolder {
private static final TransactionManager INSTANCE = new DefaultTransactionManager();
}
/**
* Get transaction manager.
*
* @return the transaction manager
*/
public static TransactionManager get() {
return SingletonHolder.INSTANCE;
}
private DefaultTransactionManager() {
}
@Override
public String begin(String applicationId, String transactionServiceGroup, String name, int timeout)
throws TransactionException {
GlobalBeginRequest request = new GlobalBeginRequest();
request.setTransactionName(name);
request.setTimeout(timeout);
GlobalBeginResponse response = (GlobalBeginResponse) syncCall(request);
return response.getXid();
}
@Override
public GlobalStatus commit(String xid) throws TransactionException {
long txId = XID.getTransactionId(xid);
GlobalCommitRequest globalCommit = new GlobalCommitRequest();
globalCommit.setTransactionId(txId);
GlobalCommitResponse response = (GlobalCommitResponse) syncCall(globalCommit);
return response.getGlobalStatus();
}
@Override
public GlobalStatus rollback(String xid) throws TransactionException {
long txId = XID.getTransactionId(xid);
GlobalRollbackRequest globalRollback = new GlobalRollbackRequest();
globalRollback.setTransactionId(txId);
GlobalRollbackResponse response = (GlobalRollbackResponse) syncCall(globalRollback);
return response.getGlobalStatus();
}
@Override
public GlobalStatus getStatus(String xid) throws TransactionException {
long txId = XID.getTransactionId(xid);
GlobalStatusRequest queryGlobalStatus = new GlobalStatusRequest();
queryGlobalStatus.setTransactionId(txId);
GlobalStatusResponse response = (GlobalStatusResponse) syncCall(queryGlobalStatus);
return response.getGlobalStatus();
}
private AbstractTransactionResponse syncCall(AbstractTransactionRequest request) throws TransactionException {
try {
return (AbstractTransactionResponse) TmRpcClient.getInstance().sendMsgWithResponse(request);
} catch (TimeoutException toe) {
throw new TransactionException(TransactionExceptionCode.IO, toe);
}
}
}
說明:
DefaultTransactionManager的beigin/commit/rollback方法內部最終呼叫syncCall()方法。
syncCall方法內部執行TmRpcClient.getInstance().sendMsgWithResponse(request)呼叫TmRpcClient方法。
public final class TmRpcClient extends AbstractRpcRemotingClient {
@Override
public Object sendMsgWithResponse(Object msg) throws TimeoutException {
return sendMsgWithResponse(msg, NettyClientConfig.getRpcRequestTimeout());
}
@Override
public Object sendMsgWithResponse(String serverAddress, Object msg, long timeout)
throws TimeoutException {
return sendAsyncRequestWithResponse(serverAddress, connect(serverAddress), msg, timeout);
}
}
說明:
- TmRpcClient內部執行傳送sendMsgWithResponse呼叫sendAsyncRequestWithResponse。
- sendAsyncRequestWithResponse的實現在父類AbstractRpcRemoting當中。
public abstract class AbstractRpcRemoting extends ChannelDuplexHandler {
protected Object sendAsyncRequestWithResponse(String address, Channel channel, Object msg, long timeout) throws
TimeoutException {
if (timeout <= 0) {
throw new FrameworkException("timeout should more than 0ms");
}
return sendAsyncRequest(address, channel, msg, timeout);
}
private Object sendAsyncRequest(String address, Channel channel, Object msg, long timeout)
throws TimeoutException {
if (channel == null) {
LOGGER.warn("sendAsyncRequestWithResponse nothing, caused by null channel.");
return null;
}
// 構建RpcMessage物件
final RpcMessage rpcMessage = new RpcMessage();
rpcMessage.setId(RpcMessage.getNextMessageId());
rpcMessage.setAsync(false);
rpcMessage.setHeartbeat(false);
rpcMessage.setRequest(true);
rpcMessage.setBody(msg);
// 通過MessageFuture包裝實現超時
final MessageFuture messageFuture = new MessageFuture();
messageFuture.setRequestMessage(rpcMessage);
messageFuture.setTimeout(timeout);
futures.put(rpcMessage.getId(), messageFuture);
// 測試程式碼走的是這個分支
if (address != null) {
// 根據address進行hash放置到不同的Map當中
ConcurrentHashMap<String, BlockingQueue<RpcMessage>> map = basketMap;
BlockingQueue<RpcMessage> basket = map.get(address);
if (basket == null) {
map.putIfAbsent(address, new LinkedBlockingQueue<RpcMessage>());
basket = map.get(address);
}
basket.offer(rpcMessage);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("offer message: " + rpcMessage.getBody());
}
// 傳送其實是另外一個執行緒單獨執行傳送操作的
if (!isSending) {
synchronized (mergeLock) {
mergeLock.notifyAll();
}
}
} else {
ChannelFuture future;
channelWriteableCheck(channel, msg);
future = channel.writeAndFlush(rpcMessage);
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
if (!future.isSuccess()) {
MessageFuture messageFuture = futures.remove(rpcMessage.getId());
if (messageFuture != null) {
messageFuture.setResultMessage(future.cause());
}
destroyChannel(future.channel());
}
}
});
}
// 通過Future實現限時超時機制
if (timeout > 0) {
try {
return messageFuture.get(timeout, TimeUnit.MILLISECONDS);
} catch (Exception exx) {
LOGGER.error("wait response error:" + exx.getMessage() + ",ip:" + address + ",request:" + msg);
if (exx instanceof TimeoutException) {
throw (TimeoutException)exx;
} else {
throw new RuntimeException(exx);
}
}
} else {
return null;
}
}
}
說明:
- 構建RpcMessage物件,包裝Request。
- 構建MessageFuture物件,包裝RpcMessage,實現超時等待功能。
- 通過basket進行分桶操作,真正執行傳送的程式碼在AbstractRpcRemotingClient類的MergedSendRunnable。
- Request的傳送類似生成消費者模型,上述程式碼只是生產者部分。
public abstract class AbstractRpcRemotingClient extends AbstractRpcRemoting
implements RemotingService, RegisterMsgListener, ClientMessageSender {
public class MergedSendRunnable implements Runnable {
@Override
public void run() {
while (true) {
synchronized (mergeLock) {
try {
mergeLock.wait(MAX_MERGE_SEND_MILLS);
} catch (InterruptedException e) {}
}
isSending = true;
for (String address : basketMap.keySet()) {
BlockingQueue<RpcMessage> basket = basketMap.get(address);
if (basket.isEmpty()) { continue; }
MergedWarpMessage mergeMessage = new MergedWarpMessage();
while (!basket.isEmpty()) {
RpcMessage msg = basket.poll();
mergeMessage.msgs.add((AbstractMessage)msg.getBody());
mergeMessage.msgIds.add(msg.getId());
}
if (mergeMessage.msgIds.size() > 1) {
printMergeMessageLog(mergeMessage);
}
Channel sendChannel = connect(address);
try {
sendRequest(sendChannel, mergeMessage);
} catch (FrameworkException e) {
if (e.getErrcode() == FrameworkErrorCode.ChannelIsNotWritable
&& address != null) {
destroyChannel(address, sendChannel);
}
LOGGER.error("", "client merge call failed", e);
}
}
isSending = false;
}
}
}
說明:
- MergedSendRunnable 負責消費待傳送訊息體並組裝成MergedWarpMessage物件。
- sendRequest()方法內部將MergedWarpMessage再次包裝成RpcMessage進行傳送。
public abstract class AbstractRpcRemoting extends ChannelDuplexHandler {
protected void sendRequest(Channel channel, Object msg) {
RpcMessage rpcMessage = new RpcMessage();
rpcMessage.setAsync(true);
rpcMessage.setHeartbeat(msg instanceof HeartbeatMessage);
rpcMessage.setRequest(true);
rpcMessage.setBody(msg);
rpcMessage.setId(RpcMessage.getNextMessageId());
if (msg instanceof MergeMessage) {
mergeMsgMap.put(rpcMessage.getId(), (MergeMessage)msg);
}
channelWriteableCheck(channel, msg);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("write message:" + rpcMessage.getBody() + ", channel:" + channel + ",active?"
+ channel.isActive() + ",writable?" + channel.isWritable() + ",isopen?" + channel.isOpen());
}
channel.writeAndFlush(rpcMessage);
}
}
說明:
- RpcMessage再次包裝MergeMessage進行傳送。
TmRpcClient初始化
public class GlobalTransactionScanner extends AbstractAutoProxyCreator implements InitializingBean {
public GlobalTransactionScanner(String applicationId, String txServiceGroup, int mode,
FailureHandler failureHandlerHook) {
setOrder(ORDER_NUM);
setProxyTargetClass(true);
this.applicationId = applicationId;
this.txServiceGroup = txServiceGroup;
this.mode = mode;
this.failureHandlerHook = failureHandlerHook;
}
private void initClient() {
TMClient.init(applicationId, txServiceGroup);
if ((AT_MODE & mode) > 0) {
RMClientAT.init(applicationId, txServiceGroup);
}
}
public void afterPropertiesSet() {
initClient();
}
}
說明:
- GlobalTransactionScanner的建構函式執行後執行afterPropertiesSet並執行initClient()操作。
- initClient()內部執行TMClient.init(applicationId, txServiceGroup)進行TMClient的初始化。
public class TMClient {
public static void init(String applicationId, String transactionServiceGroup) {
TmRpcClient tmRpcClient = TmRpcClient.getInstance(
applicationId, transactionServiceGroup);
tmRpcClient.init();
}
}
public final class TmRpcClient extends AbstractRpcRemotingClient {
public void init() {
if (initialized.compareAndSet(false, true)) {
init(SCHEDULE_INTERVAL_MILLS, SCHEDULE_INTERVAL_MILLS);
}
}
public void init(long healthCheckDelay, long healthCheckPeriod) {
// 注意initVars()方法
initVars();
ExecutorService mergeSendExecutorService = new ThreadPoolExecutor(
MAX_MERGE_SEND_THREAD, MAX_MERGE_SEND_THREAD,
KEEP_ALIVE_TIME, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
new NamedThreadFactory(getThreadPrefix(MERGE_THREAD_PREFIX),
MAX_MERGE_SEND_THREAD));
mergeSendExecutorService.submit(new MergedSendRunnable());
timerExecutor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
reconnect();
} catch (Exception ignore) {
LOGGER.error(ignore.getMessage());
}
}
}, healthCheckDelay, healthCheckPeriod, TimeUnit.SECONDS);
}
private void initVars() {
enableDegrade = CONFIG.getBoolean(
ConfigurationKeys.SERVICE_PREFIX + ConfigurationKeys.ENABLE_DEGRADE_POSTFIX);
super.init();
}
}
說明:
- 核心在於關注initVars()方法。
public abstract class AbstractRpcRemotingClient extends AbstractRpcRemoting
implements RemotingService, RegisterMsgListener, ClientMessageSender {
public void init() {
NettyPoolableFactory keyPoolableFactory = new NettyPoolableFactory(this);
// 核心構建傳送的物件的連線池
nettyClientKeyPool = new GenericKeyedObjectPool(keyPoolableFactory);
nettyClientKeyPool.setConfig(getNettyPoolConfig());
serviceManager = new ServiceManagerStaticConfigImpl();
super.init();
}
}
public abstract class AbstractRpcRemoting extends ChannelDuplexHandler {
public void init() {
timerExecutor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
List<MessageFuture> timeoutMessageFutures = new ArrayList<MessageFuture>(futures.size());
for (MessageFuture future : futures.values()) {
if (future.isTimeout()) {
timeoutMessageFutures.add(future);
}
}
for (MessageFuture messageFuture : timeoutMessageFutures) {
futures.remove(messageFuture.getRequestMessage().getId());
messageFuture.setResultMessage(null);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("timeout clear future : " + messageFuture.getRequestMessage().getBody());
}
}
nowMills = System.currentTimeMillis();
}
}, TIMEOUT_CHECK_INTERNAL, TIMEOUT_CHECK_INTERNAL, TimeUnit.MILLISECONDS);
}
}
說明:
- AbstractRpcRemotingClient的init()方法核心構建nettyClientKeyPool工廠。
- nettyClientKeyPool用於獲取連線TC的物件的工廠池。
配置載入分析
public class FileConfiguration implements Configuration {
private static final Logger LOGGER = LoggerFactory.getLogger(FileConfiguration.class);
private static final Config CONFIG = ConfigFactory.load();
}
package com.typesafe.config;
public final class ConfigFactory {
private ConfigFactory() {
}
public static Config load() {
return load(ConfigParseOptions.defaults());
}
}
說明:
- 配置載入使用了JAVA 配置管理庫 typesafe.config
- 預設載入classpath下的application.conf,application.json和application.properties檔案。通過ConfigFactory.load()載入。
Request的類關係圖
相關文章
- 如何使用jMeter傳送兩個邏輯上相關的HTTP請求JMeterHTTP
- 解析jwt實現邏輯JWT
- Scrapy中傳送請求的固定邏輯?為什麼要這樣寫?
- 程式設計師面試邏輯題解析程式設計師面試
- 硬解析物理讀VS軟解析邏輯讀 測試
- iOS 直播間送禮物邏輯(禮物連擊)iOS
- [原始碼解析] Pytorch 如何實現後向傳播 (3)---- 引擎動態邏輯原始碼PyTorch
- visible_windows生成邏輯和解析Windows
- 硬解析和物理讀取與軟解析和邏輯讀取
- 形式邏輯(普通邏輯)7:推理概述
- 電商後臺系統產品邏輯全解析
- 程式碼審計之邏輯上傳漏洞挖掘
- 邏輯分析
- 邏輯題
- Flutter 實現視訊全屏播放邏輯及解析Flutter
- 解析2011年GCT邏輯試題(1)GC
- 讀人工智慧全傳06邏輯程式設計人工智慧程式設計
- Jmeter邏輯控制器之If Controller的使用解析JMeterController
- PostgreSQL邏輯備份pg_dump使用及其原理解析SQL
- Android原生下載(上篇)基本邏輯+斷點續傳Android斷點
- java邏輯控制Java
- java取反邏輯Java
- 邏輯運算子
- Linux Shell 邏輯運算子、邏輯表示式詳解Linux
- 資料讀取之邏輯讀簡單解析--關於BUFFER CACHE
- 傳送陣
- 檔案上傳之解析漏洞編輯器安全
- SCSS 邏輯運算子CSS
- JS邏輯練習JS
- PostgreSQL:邏輯結構SQL
- oracle 邏輯結構Oracle
- RunLoop內部邏輯OOP
- DataGuard搭建邏輯StandBy
- 邏輯備份--mysqldumpMySql
- 邏輯備庫Switchover
- 邏輯卷LVMLVM
- 0504邏輯歸因
- 06--加密邏輯加密