仅在 Aurora 事务提交时调用 Lambda 函数,但保证调用(ACID)

Chr*_*oph 5 amazon-web-services microservices amazon-aurora

对于新项目中的一个微服务,我目前正在考虑是使用DynamoDB还是Aurora MySQL作为底层数据存储。微服务为用户界面提供了 REST API,并且还会有其他几个微服务。那些其他微服务应该侦听由 UI 连接服务生成的事件流(事件源),以保持其他读取模型同步。

我试图找出一种方法来保证发布到更改事件流的事件与底层数据存储中的数据更改完全匹配。通常,担心的是,如果 REST API 处理程序(例如)在执行过程中被中断,它可能已经更改了数据但尚未创建事件(假设更改事件在数据更改后发布)。我现在正在寻找可以减轻这种担忧的机制。

对于 DynamoDB,有 DynamoDB 流和 AWS Lambda 触发器可以对数据存储级别的数据更改做出反应。触发的 Lambda 可以将低级数据更改转换为有意义的更改事件,然后将事件发布到 SNS、SQS 或 Kinesis。

对于 Aurora MySQL,我还没有想出这样的机制。我看过描述两种机制的文章:

  1. 为 Aurora 启用二进制日志并使用额外的 EC2 实例来处理更改流。从此流中发布其他服务的事件。
  2. 使用本机 lambda_sync 或 lambda_async 函数从 MySQL 触发器调用 Lambda。从此 Lambda 中发布其他服务的事件。

一,我对这两种方法都不太满意:1) 我不想管理额外的 EC2 实例和处理原始 SQL 更改。2) 我打算为 Aurora 使用约束、乐观并发和事务,这意味着事务可以并且将会失败和回滚。但是,无论事务结果如何,都将执行 lambda_(a)sync 调用。

对 Aurora 有什么更好的想法吗?还是我从错误的角度看待这个问题?

我想将这个问题和讨论集中在如何保证底层数据存储和具有更改事件的传出流之间的更改一致性的问题上,而不是在 Aurora 与 DynamoDB 上。

Chr*_*oph 1

我找到了一个适合我们情况的答案,即使用与 MySQL 兼容的 Aurora。在我的研究过程中,我在microservices.io上发现了优秀的信息来源。具体来说,事件驱动架构模式页面引用了四种相关模式来保证更新状态和发布事件的原子性。

  • 事件溯源
  • 应用事件
  • 数据库触发器
  • 事务日志拖尾

事件溯源是不可能的,因为它对于我们想要实现的目标来说太复杂了。我已经在最初的问题中反对 tx 日志拖尾。应用程序事件和数据库触发器非常相似,因为作为事务的一部分,状态会更新,并且条目会写入事件表:Tx 成功提交,状态会保留,事件条目会显示在该表中。Tx 回滚,状态不变,并且没有事件条目显示。两者之间的唯一区别在于事件条目是由应用程序/服务逻辑本身生成还是由数据库触发器生成。

然后,外部进程轮询该表并根据事件条目发布其他微服务的事件(当然,之后会删除已发布的事件)。这两种模式保证状态更改始终会导致至少一个事件(仅一次会导致实现起来稍微复杂一些)。

现在关于如何实现这个...我的第一个想法是使用带有执行轮询的 Node 应用程序的 Fargate 容器,认为我将通过此解决方案保持无服务器状态。然而,事实证明这并不完全正确:为了保证事件的顺序,应该只有一个容器轮询和发布。单个 Fargate 容器被分配给一个可用区域,如果该区域“消失”,容器也会消失。现在,我必须在顶部构建某种监控,以便在需要时在不同的可用区 #2 中实例化新容器 #2。但是如果 AZ #1 和容器 #1 回来怎么办?那么就会有两个实例。这变得太复杂了。

目前,我选择了以下方法:CloudWatch 事件每分钟触发一次轮询 Lambda 函数(CW 的最小间隔)。调用后,该函数将持续轮询数据库,直到一分钟后第二个 Lambda 函数调用接管。为了协调两个 Lambda 函数调用,我在数据库中创建了第二个表“事件轮询状态”,其中最近的 Lambda 函数调用更新该表中的专用行,指示它启动的上一个函数调用(此是在 SELECT ... FOR UPDATE 和 TX 的帮助下完成的,以防止竞争条件)。在每个轮询周期之前,如果同时没有其他函数启动,该函数会检查事件轮询状态中的行。

这种方法的优点(据我所知):

  • 真正的无服务器且不感知可用区、VPC、子网。
  • 事件的顺序是有保证的,因为绝不会超过一个 Lambda 调用并行轮询和发布。
  • 如果轮询 Lambda 函数因任何原因终止(例如,因为可用区消失),则发布间隔最多为 1 分钟,直到 CloudWatch 下次调用 Lambda 函数。这个差距是可以接受的。