微服务+ CQRS实施

时间:2020-06-01 23:53:06

标签: amazon-s3 microservices amazon-sns cqrs event-sourcing

我正在使用CQRS模式实现微服务架构。我有一个使用API​​网关,Lambda和DynamoDB的有效实现,但有一个例外-事件源。

Event Sourcing使应用程序将通知发布到平台上其他服务可以使用的事件流。此通知表示发生在原始HTTP请求中的事件。例如,如果用户使用完整的“将患者送入医院检查”模型进行HTTP POST,则Lambda会将其分解并按顺序发布多个事件。

已签收的患者(包括患者ID,医院ID +访问ID)

已分配房间(包括房间号和访问ID)

已测试患者(包括已测试+访问ID)

患者已签出(访问ID)

此模式的目的是提供对患者在医院期间发生的所有事件的审核跟踪。此示例(不是我实际构建的示例)将存储在可以随时重播的事件源中。如果在所有服务中都删除了VisitId,我们可以按顺序一次重播事件,并复制原始记录的精确副本。您认为所有记录都是不变的,以实现此目的。每个POST都会推送到事件源,然后进入数据库,该数据库将在HTTP GET请求期间提取数据。订阅者还可以获取这些数据并做其他事情-例如“访问调查”服务,该服务将监听“患者已结帐”事件并准备事后调查。

我研究了几种提供此服务的AWS服务。我了解Kinesis Data Streams,但我不喜欢定价结构,也不想处理分片(无自动缩放)。由于我的整个平台都建立在基于消费的定价基础上(Dynamo,Lambda等),因此我想以相同的方式保留事件源。这样一来,我就可以轻松估算出每位用户的费用,就像我只是根据每个用户每月的估计请求数来计算一样。

我一直在对流本身使用SNS,传递通知,这很棒。超快速,在开发时没有任何重大问题。但是,问题在于这不适合重播存储-仅传递事件消息。对于一个重播商店,我认为Kinesis Firehose很有道理...同时将其发送到S3 + SNS。事实证明SNS不是可用的传递目的地。我可以自己放到S3,然后发布到SNS,但是当我可以设置S3触发器来触发Lambda并只有另一个小的Lambda对S3中的事件着陆做出反应并执行插入操作时,这似乎是代码库中的重复工作进入DynamoDB。我已经看到,这可能比通过SNS发布要慢得多。我也不确定关于Put事件的重试策略。尽管我可以重复使用触发的Lambda中的代码来重播存储桶路径中的所有事件,但这简化了重试。

我可以只放置PutObject,然后在同一HTTP POST Lambda中发布到SNS。如果SNS发布失败,那么我现在在S3中有一个从未发布过的对象。我必须写一个不同的Lambda来处理修复和发布。不是世界末日-无论如何,我都有两个Lambda可供部署。我只是不确定哪种方式在AWS服务中更有意义。

有人做过类似的事情并且有什么建议吗?我是否正在进入以后将难以管理的技术漏洞?如果我可以将其保持在基于消费的定价模型中,那么我也会开放其他途径。谢谢!

1 个答案:

答案 0 :(得分:2)

Event Sourcing让应用程序将通知发布到平台上其他服务可以使用的事件流。

您需要在这里稍加注意-至少有两种不同的“事件源”定义。

如果您关心事件的来源(通常与CQRS结合使用)(Greg Young等人),那么您的事件就是您的记录了。这带来的重要复杂之处在于,您的服务在进行更改时需要能够锁定(事件流)(如果没有该锁定,则会遇到“丢失的编辑”场景并必须清理)一团糟)。

因此,“当前更改的指针”需要存在于具有事务性的环境中。 DynamoDB对此应该没问题(根据我对re:Invent 2017的事件采购突破空间的记忆)。在理论中,您可以将锁锁定在dynamo中,该锁包含指向S3中存储的不可变文档的指针。我一直无法说服自己,折衷证明了复杂性是合理的,但最好的是,我可以说该架构中没有任何东西违反物理和因果关系。

如果您的运营团队对Dynamo不满意,则另一个合理的选择是RDS;选择首选的关系数据引擎,向其部署事件存储架构,然后就可以使用了。

关于pub子部分,我相信您在使用SNS方面是正确的。这是将消息从发布者“散布”到多个消费者的正确选择。是的,它不支持重播,但这很好-可以通过从记录簿中拉出 事件来进行重播。请参阅格雷格·杨(Greg Young)Polyglot Data talk的后续部分。是的,有时您会在推式通道和拉式通道上都收到消息,但这很好。当您确定分布式体系结构是一个好主意时,您已经注册了幂等消息处理。

编辑

为什么需要在DynamoDB中存储指针?

因为S3不提供任何锁定;这意味着在不愉快的道路上,如果您的逻辑的两个副本试图写入数据的不同版本,您最终将成为丢失编辑问题的受害者。

您可以使用乐观锁定来管理情况-类似于HTTP的条件PUT;但是S3(我上次检查)不支持条件修改。

可以将S3用作不可变文档的对象存储,但是现在您需要某种机制来确定S3中的哪个文档是“当前”文档。如果尝试在S3中实现该功能,则会再次遇到相同的丢失编辑问题。

因此,您需要一个不同的工具来处理那部分问题。一些适合“状态继承”的工具。因此,DynamoDB就适合在那里。

如果使用DynamoDB进行锁定,还可以将其用于事件存储吗?我没有足够的圈数,无法对我知道那里的答案充满信心。对于小问题,我最有信心答案是肯定的。对于大问题...?

可能有用的讨论: