微服务客户端确认和事件来源

时间:2019-01-30 23:15:56

标签: asynchronous design-patterns architecture event-handling microservices

场景

我正在使用微服务构建快递服务系统。我不确定几件事,这是我的场景

  1. Booking API-这是客户下订单的地方
  2. 付款API-这是我们根据预订处理付款的地方
  3. Notification API-一切完成后,有服务负责发送通知。

系统正在使用事件驱动的体系结构。当客户下订单时,我会在预订API中提交本地交易并发布事件。支付API和通知API已订阅各自的事件。完成付款和通知API后,需要确认返回到Booking API。

我的问题是

发布活动后,我的预订服务无法阻止该呼叫并返回到客户端(前端)。我的客户端应用程序将如何检查交易状态或知道交易已完成?是否每隔几秒钟轮询一次?由于这是分布式事务,任何服务都可能中断并且无法确认。在那种情况下,我的客户(前端)将如何知道,因为它将一直等待。我正在考虑佐贺分布式交易。

实现所有这些的最佳方法是什么?

事件来源

我想实施事件采购以跟踪预订单的完整跟踪。我必须在活动商店的预订API中实现此功能吗?或者事件存储在服务之间共享,因为我应该从不同的服务中捕获所有事件。实现此目的的最佳方法是什么?

非常感谢,

3 个答案:

答案 0 :(得分:1)

我对此的可视化方式如下(受马丁·克莱普曼的演讲herehere的影响)。

  1. 最终用户下订单。该订单已写入Kafka主题。由于Kafka具有日志结构的存储,因此将在尽可能短的时间内保存订单详细信息。这是一个原子操作(“ ACID”中为“ A”)-全部或不包含
  2. 现在,用户一旦下订单,用户便想读回它(读-写)。为此,我们也可以将订单数据写入分布式缓存中。尽管双重写入通常不是一个好主意,因为它可能会导致部分失败(例如,写入Kafka成功,但是写入缓存失败),但是我们可以通过确保其中一位Kafka使用者将数据写入数据库来减轻这种风险。因此,即使在极少数情况下发生高速缓存失败的情况下,用户也可以最终从数据库读回数据。
  3. 创建订单时写入缓存的订单状态为“进行中”
  4. 然后使用一个或多个kafka消费者组按以下方式处理事件:付款和通知得到正确处理,最终状态将写回到缓存和数据库中
  5. 然后,一个单独的Kafka使用者将从付款和通知api接收响应,并将更新写入缓存,数据库和Web套接字

  6. 然后,网络套接字将更新UI模型,然后通过事件源将更改反映在UI中。

基于评论的进一步说明

  1. 这里的基本思想是,我们使用流技术为每个需要其数据的服务构建缓存。例如帐户服务需要付款和通知服务的反馈。因此,我们让这些服务将他们对某个Kafka主题的响应写回去,该主题使一些使用者将响应写回到订单服务的缓存中

  2. 基于Kafka(或任何类似技术)的ACID属性,该消息将永远不会丢失。最终,我们将一无所获。那是原子性。如果订单服务无法写入订单,则会以同步方式将错误响应发送回客户端,并且用户可能会在一段时间后重试。如果订单服务成功,则对其他服务的响应必须最终流回到其缓存中。如果其中一项服务关闭一段时间,响应将被延迟,但最终将在服务恢复时发送

  3. 客户端不需要轮询。结果将通过使用websocket的流媒体传播到它。 UI页面将侦听websocket,当使用者将反馈写入缓存时,它也可以写入websocket。这将通知UI。然后,如果您使用Angular或ReactJS之类的东西,则可以使用websocket上收到的值刷新UI的相应部分。在此之前,用户一直看到在创建订单时写入缓存的状态“进行中”。即使用户刷新页面,也会从缓存中检索相同的状态。如果缓存值过期并遵循LRU机制,则将从DB中提取相同的值,并将其写回到缓存中以服务将来的请求。一旦获得其他服务的反馈,将使用websocket传输新结果。在页面刷新时,可以从缓存或数据库中获得新状态

答案 1 :(得分:1)

完成预订后,您可以将标识符传递回客户端,并且如果可以在后端将其连接,客户端可以使用该标识符查询后续操作的状态。其他事件完成后,您也可以将通知发送回客户端。您可以进行长时间轮询,也可以进行通知。

  

感谢斯卡吉尼。我的问题的一部分是处理其他情况   微服务不会及时返回或永远不会返回。可以说付款api是   完成工作并向客户收费,但未通知我的订单服务   及时或很长一段时间后。我的客户如何等待?如果我们超时   客户端可能在超时后对其进行了处理

在CQRS中,您将命令和查询分开。也就是说,考虑到您的情况,您可以使用Queues进行所有交互。 (具有事件源的CQRS有多种实现方式,但以最简单的形式):

客户发送请求->支付API接收请求->验证请求(如果验证失败将错误返回给用户)->验证成功后->生成GUID并将消息请求写入队列->将GUID传递给用户

付款API订阅付款队列->处理请求后->写入订单队列或任何其他队列

Order APi订阅Order Queue并处理请求。

用户有一个GUID,可以获取所有交互的数据。

如果像在Kafka中那样使用pub / sub而不是Kafka(所有其他后续系统都可以从同一主题读取,则无需为每个队列进行写操作)

如果任何服务无法处理,则一旦重新启动服务,只要它们在系统中回滚其响应更改,则它们应该能够选择中断的位置,如果服务在事务处理过程中处于关闭状态应该保持稳定状态

答案 2 :(得分:0)

我不确定您要问什么。但是听起来您应该使用消息传递服务。正如@Saptarshi Basu提到的kafka很好。我真的会推荐NATS-尽管我有偏见,因为那是我与之合作的

使用NATS,您可以创建请求-答复消息,以在客户端和预订服务之间建立接口。那是1-1的交流

如果您的每个服务都具有多个实例,则可以使用队列服务来自动进行负载平衡。 NATS会为您随机选择一台服务器

然后,您可以使用发布订阅源在所有服务之间进行通信。

这将为您提供一个非常灵活和可扩展的体系结构,而NATS则使这一切变得异常简单

相关问题