TCC(Try-Confirm-Cancel)作为一种应用层分布式事务解决方案,虽然能有效提升系统性能和可用性,但在实际落地过程中面临诸多挑战。以下是 TCC 模式的核心问题及对应解决方案:
// 伪代码示例 public boolean confirm(String txId) {
// 1. 查询操作状态
OperationStatus status = operationDAO.getStatus(txId);
if (status == COMPLETED)
return true; // 已完成,直接返回成功
// 2. 执行确认逻辑
boolean result = doConfirm(txId);
// 3. 更新状态为COMPLETED(需原子化)
operationDAO.updateStatus(txId, COMPLETED);
return result;
}
CREATE TABLE tcc_operation (
tx_id VARCHAR(64) PRIMARY KEY, -- 事务ID
status TINYINT NOT NULL, -- 状态:0-初始,1-处理中,2-已完成
create_time DATETIME NOT NULL,
update_time DATETIME NOT NULL );
public void cancel(String txId) {
// 检查Try是否执行
if (!operationDAO.exists(txId)) {
// 空回滚处理:记录日志并返回成功
log.info("Empty rollback detected for txId: {}", txId);
return;
}
// 执行正常回滚逻辑
doCancel(txId);
}
public boolean try(String txId) {
// 检查是否已回滚
if (operationDAO.getStatus(txId) == STATUS_CANCELED) {
log.warn("Suspension detected for txId: {}", txId);
return false;
}
// 执行正常Try逻辑
return doTry(txId);
}
public boolean try(Order order) {
// 1. 保存订单快照
orderSnapshotDAO.save(order.getId(), order);
// 2. 预留库存
return inventoryService.reserve(order.getProductId(), order.getQuantity());
}
public void cancel(String orderId) {
// 1. 获取订单快照
Order snapshot = orderSnapshotDAO.get(orderId);
// 2. 释放库存
inventoryService.release(snapshot.getProductId(), snapshot.getQuantity());
}
// Try成功后发送异步确认消息
public boolean try(Order order) {
if (inventoryService.reserve(order.getProductId(), order.getQuantity())) {
confirmMQProducer.send(order.getId()); // 发送确认消息
return true;
}
return false;
}
// 消费确认消息并执行Confirm
@MQConsumer(topic = "order_confirm")
public void handleConfirm(String txId) {
orderService.confirm(txId);
}
// CompletableFuture并行调用示例
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> serviceA.try(txId));
CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> serviceB.try(txId));
CompletableFuture.allOf(future1, future2).join();
// 定时任务检查超时事务
@Scheduled(fixedRate = 60000)
public void checkTimeoutTransactions() {
List<Transaction> timeoutTxs = txDAO.getTimeoutTransactions(300);
// 超过5分钟
for (Transaction tx : timeoutTxs) {
txCoordinator.triggerCancel(tx.getId());
}
}
// 对账逻辑示例
public void reconcile() {
// 1. 对比业务库与事务日志
List<Transaction> inconsistentTxs = txReconciler.checkInconsistent();
// 2. 自动重试或人工干预
for (Transaction tx : inconsistentTxs) {
if (tx.getRetries() < 3) {
txCoordinator.retry(tx.getId());
} else {
alertService.notifyAdmin(tx.getId()); // 通知管理员
}
}
}
public void retryWithBackoff(String txId, int maxRetries) {
int retries = 0;
long delay = 1000; // 初始延迟1秒
while (retries < maxRetries) {
try {
if (service.confirm(txId)) {
return; // 成功返回
}
} catch (Exception e) {
retries++;
delay = delay * 2; // 指数退避
Thread.sleep(delay);
}
} throw new RetryException("Max retries exceeded for txId: " + txId);
}
@HystrixCommand(fallbackMethod = "cancelFallback") public void cancel(String txId) {
remoteService.cancel(txId); } public void cancelFallback(String txId, Throwable e) {
// 记录异常,后续人工处理 log.error("Cancel fallback for txId: {}", txId, e);
}
// 埋点示例
public boolean try(String txId) {
long startTime = System.currentTimeMillis();
try {
boolean result = doTry(txId);
metricsService.recordSuccess("tcc.try", System.currentTimeMillis() - startTime);
return result;
} catch (Exception e) {
metricsService.recordFailure("tcc.try", System.currentTimeMillis() - startTime);
throw e;
}
}
TCC 模式的落地需要综合考虑幂等性、空回滚、悬挂、补偿逻辑等核心问题,并通过状态机、防重表、异步化、监控告警等技术手段构建完整的解决方案。建议使用成熟的开源框架(如 Seata、ByteTCC)降低开发成本,同时结合业务特性进行定制优化。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。