【问题标题】:Event Driven Architecture - Response to Mobile/Web Clients事件驱动架构 - 对移动/Web 客户端的响应
【发布时间】:2022-02-14 00:02:23
【问题描述】:

我的微服务中有以下用例

用户体验:联系人详细信息弹出窗口要求用户在 UI 上确认联系人详细信息、电子邮件地址和其他相关详细信息。一旦用户提交数据 - 用户应该会在屏幕上看到联系人详细信息保存成功/失败消息。

每当更新联系方式时,还应在后台添加独特的评论。

下游系统公开了几个用于创建、检索、更新和删除联系人详细信息的 CRUD API 端点以及用于 cmets 的类似 CRUD API 端点。

因为这些 API 端点中的每一个都是独立的。我正在考虑通过事件来实现 SAGA(编排/编排)以确保原子性。

我这边的 REST API 端点(Spring Boot)将用户从 UI 修改的所有数据作为 JSON 捕获,并将事件 Update_Contact_Details 发布到 Kafka 消息主题。

Update_Contact_Details 消费者将从主题中读取消息,调用下游更新联系人详细信息 API,并写回 Contact_Details_Updated/Contact_Details_Update_Failed 事件。

在幸福的道路场景中: Contact_Details_Updated Message 将被 Comments Listener 读取并调用下游 API 添加评论。

在失败场景中: Contact_Details_Update_Failed 将被联系人详细失败监听器读取并调用删除联系人详细信息 API。

在任何一种情况下,由于从 UI 到 API 端点的第一个捕获是 REST API - 我如何将成功/失败响应发送回客户端(网络/移动),因为与编排上述流程相关的整个过程是异步。

【问题讨论】:

  • 我认为除了存储临时本地状态之外,您能做的最好的事情就是显示进度微调器或“消息已接受”响应。不是直接的成功/失败。然后,您需要在后台轮询 API 以最终获取真实数据。假设最初的 POST API 调用不是错误,您需要设置一些超时以向前端显示任何错误

标签: rest microservices saga event-driven-design


【解决方案1】:

您基本上是在尝试使 request-response(同步)模型适应异步。我们有多种选择:

  1. 阻止向客户端发送响应,直到流程完成。 这是非常直接且易于实施的,但它会带来成本,并且取决于整个系统处理事件链所花费的时间。

  2. 使用回调并通过回调 API 通知消费者。 在这种情况下,侦听器将向调用Update_Contact_Details API 端点的感兴趣的客户端发送回调。这需要更改您的客户端代码。

  3. 使用轮询。编写一个端点来查询更新的状态(失败/成功),具体取决于您的失败/成功侦听器是否接收到消息,并让您的客户端定期轮询端点。这需要更改您的客户端代码。

如果您曾经使用过 Kinesis (AWS),您可能已经注意到资源的创建/更新不会立即发生。您会在顶部看到一个通知栏,上面写着“正在创建 kinesis 流”,并且 gif 一直在旋转,一段时间后,您会看到流已成功创建的消息。

对于如此长的或异步的进程,服务器通常应该给出回调或者客户端应该轮询结果而不是无限期地阻塞响应。

在 AWS 的情况下,用户了解资源的创建或更改不会像 Google 搜索那样在几毫秒内发生,因此 [s] 他并不期望立即得到响应。

不管怎样,到了设计的根源,你也可以考虑提出以下问题:

1.你真的需要 2 个数据库吗? 您有联系方式和 cmets(要添加到联系人中),为什么需要两个数据库来存储联系方式和 cmets?如果您使用单一数据库 (RDBMS),则不需要 SAGA 模式。

此模式仅适用于存在多个数据库的情况(因为数据库之前已经存在或存在特殊用例)。

2。您的用例真的需要 Kafka 吗? 您在问题中标记了,所以我想您有下游消费者需要将此信息作为“事件”,如果没有,则没有使用Kafka,所以问题是“如果您真的需要kafka?”

在这种情况下,您可以在面向 UI 的 REST 中更新 DB,在数据成功存储在 DB 中后将响应返回给 UI,并使用 CDC(Changed-Data-Capture)将 DB 更改流式传输到卡夫卡。

这可确保您的数据库和 Kafka 保持同步,因此您的 Kafka 下游消费者会收到更改通知,并且您也会立即更新 UI。如果使用 CDC 不可行,那么您可以安排一个后台线程来轮询数据库以获取新更新并将它们推送到 Kafka。

【讨论】: