如何解决不同数据库和服务之间的事务问题?


在我这个项目中,有多个数据库和服务需要无缝通信和交换数据。然而,在这些不同的系统中保持交易的完整性已被证明是一个相当大的障碍。我想确保所有相关操作要么成功,要么失败,避免任何不一致或数据差异。

我正在使用的一些数据库和服务包括(但不限于):- PostgreSQL - 亚马逊网络服务(AWS)服务(如S3、DynamoDB)。

我很想听听你在处理类似情况时的经验和最佳做法。这里有一些问题来指导讨论,但请随时分享你认为可能有帮助的任何见解:

  • 你是否面临过不同数据库和服务之间的交易挑战?你是如何处理这些问题的?
  • 你发现哪些工具、库或框架在实现不同系统间的交易一致性方面是有效的?
  • 你是否实施了任何特定的架构模式或设计原则来促进交易的顺利进行?
  • 你是如何处理交易的一个部分失败,而需要后续回滚或补偿行动的情况的?
  • 在处理这个问题时,你是否遇到过任何陷阱或教训?

请分享你的想法、经验,以及你可能有的任何其他建议。

网友回应:
1、使用Saga
Saga模式有Orchestration 和Choreography 两种
Choreography 远比Orchestration 复杂。

Orchestration 是一种服务,它管理其他服务之间的调用并将其回滚(如果需要的话),只有Orchestration编排者需要保持状态。

Choreography 是让你的服务意识到事务的发生,并对之前发生的事件和之后发生的故障做出反应。每个服务都必须为该事务保留状态。

也就是说(在Choreography中)我的微服务会看到一个事件,说 "为事务Foo做X",如果它失败了,它必须说 "事务Foo的X失败了",然后它还必须提醒 "事务Foo的Y失败了,这导致它'撤销'X,然后为之前的任何行动发送一个事件(你可以直接转发 "事务Foo失败了--所有人都回滚",但这也很棘手)部分失败甚至更糟。

2、这远远超出了Go的范畴,是一个合理的难题。这是一个多年来一直在研究最终一致的分布式数据存储的人说的话。

其中一个问题是,当 "事务 "进行时,其他变化正在发生,所以回滚会抹去或使之无效或影响中间的变化。即使是一个成功的事务也有可能对那些在大事务生命周期内开始和结束的小变化造成影响。你基本上有和git中的合并冲突一样的问题,只是你不能像git那样放弃,说 "让人类来解决"。

解决这个问题的一个方法是把你的操作限制在交换性的操作上:无论操作的顺序如何,最终都会得到相同的结果。这对可用的数据模型有影响--你不能有序列(两个 "插入索引3 "的操作会互相覆盖,所以最后一个会赢,所以顺序总是很重要),但你可以有集合插入(连续插入两个元素,无论顺序如何,这两个项目总是在集合中),等等。

为了使结果正确,你还需要确保成功的操作和它的逆操作(回滚)都是换元的,这样你就可以混合和匹配所有这些操作。

而这都是在你考虑到不同的服务会有不同的可用性之前--一个服务可能会出现故障,需要重试,而其他服务则处于停顿状态。导致一些不同的系统独立地收敛在最终的一致性上......那是一个巨大的问题。

这个问题没有通用的解决方案--你需要权衡。

3、欢迎来到强一致性模型的世界(不等同于最终一致,正如这里有人建议的那样)。注意CAP定理和你的权衡是什么。

在具有不同一致性模型的异构系统之上建立强一致性事务的最简单方法是使用一个中央强一致性数据存储(例如etcd,Postgres可以这样做)来保存一个历史计数器。只有一个单调增长的数字。你系统中的所有状态都有一个相关的历史数字。如果这个数字低于(或等于)中央计数器,这个数据就被确认复制和实现。如果它高于,则是未确认的,正在复制。