最大的问题是对 Web 服务的重复更新是否重要,以及是否可以检测到它们。如果您可以检测到重复(通常使用唯一的事务编号)或者如果重复无关紧要,那么您可以构建一个可靠的两阶段提交样式方法。
如果无法检测到 Web 服务的重复事务并且更新不是幂等的,那么您就不走运了。
这是基本算法:
begin transaction;
do local work;
save information for external call;
set an appropriate time for next attempt;
mark external call as not performed;
commit work;
begin transaction;
make external call;
if successful
mark external call as performed (or delete the record)
else
set the time for the next attempt
commit;
然后,您需要一个常规任务、线程或任何类似这样的东西:
for each record where the time for the next attempt <= now
begin work;
if the remote service has not performed this transaction
make the remote call;
if successful
mark as done;
else if too many attempts
mark the transaction as permanently failed;
alert operator;
else
set the time for the next attempt;
endif
else
mark as done;
endif
commit;
endfor
这种方法可靠地处理所有故障情况,并确保最终完成两项工作。
基本故障:
第一次提交完成之前的失败:一切都回滚。
第一次提交之后但 Web 服务完成之前的故障(这包括 Web 服务本身的暂时故障):远程 Web 服务事务由恢复任务重放。
Web 服务完成后但第二次提交完成之前的故障:恢复任务检测到重复的 Web 服务事务,本地记录出列。
恢复任务中的失败:与第二个事务中的失败基本相同。
其他注意事项:
逐渐退避的方法对于失败很有用。如果您希望减慢重试速度的服务出现暂时性故障。
如果您对外部服务有订购要求,您可能需要一些额外的结构。
根据您实现恢复任务的方式,您可以只将 Web 服务调用留给该任务,而在主应用程序流中没有第二个事务。
对附加要求的回应:“两部分事务必须一起完成,做一个cron作业来同步表是不可取的”
我对这个要求的解读是:“这两个系统永远不应该失败”。
当其中一个或两个系统出现故障时,您需要一些东西来收拾残局并协调事情。您可以使用成熟的 TP 监视器来进行事务协调,或者您可以构建一个简单的监视器,例如我的示例中的监视器来处理您的特定情况。无论哪种方式,都有一些东西可以跟踪正在发生的事情,以便在发生故障后可以正确解决问题。
如果您确实要求事情总是一起发生(并且事务消息队列或两阶段提交方法对您不起作用),那么最好将两个系统的数据存储在同一个数据库中(又名“资源管理器” ) 并拥有一个资源管理器事务。
如果您确实找到了解决此问题的解决方案,该解决方案满足了两个独立系统在多个事务中保持一致的要求,并且在发生故障后不再需要后续协调,您应该将其写下来并发表在 The VLDB Journal、ACM TODS 或 IEEE TKDE .