实时前台的事件源模式介绍

68 阅读5分钟

事件驱动的网络应用程序实时通信

假设你正在开发一个与多个客户进行通信的实时网络应用程序。这样的应用通常由一个能够处理双向消息的后端服务组成。

虽然可以使用传统的CRUD模式来实现,但这并不是最有效的方法。

为什么它具有挑战性?

除此之外,这类系统也有一定的注意事项:

  • 一个常见的挑战是工作流的性质。它不完全是请求-回应。你必须同时提交消息和监听(或订阅)以接收通知。
  • 由于向数据存储写入每个消息所需的开销,以消息方式对数据存储进行更新会导致性能低下可扩展性有限
  • 也可能存在并发问题,导致低性能和潜在的数据冲突。
  • 它还限制了事件的可追溯性。

事件源的救援

这就是事件源进入画面的地方。它是一种通过设计来处理事件更新当前状态的方法。

通过这种模式,我们通过处理一系列变化的事件来修改我们数据存储中的实体的状态。

当你在前台做一个动作时,它将产生一个事件并将其发送到后台。由于事件描述的是过去的事件,我们不能对其进行任何修改,因为它们已经发生了。我们只能将新的事件追加到现有的事件队列或日志中,使写操作变得简单,因为在追加一个新的事件时需要最小的锁定

因此,事件不可改变的。然后,当前状态将通过重放系列中的事件来重构。

因此,与CRUD模式相比,事件源提供了一些明显的好处。由于这些原因,一些组织在采用微服务范式时开始采用带有CQRS的事件源。

用于实时前端的事件源?

让我们详细讨论一下我们如何将事件源用于实时前端应用程序。

事件源有一个高效的写入模型。因此,它很适合处理由前端应用程序通过Web Sockets发送的实时事件。然后,这些事件可以被处理,并很容易通过Web Sockets反馈给任何订阅的消费者。

然而,当大量的事件随着时间的推移而增加时,这种方法在通过每次回复所有过去的事件来重新创建当前状态方面并不高效。

处理这个问题的一个方法是使用快照。我们可以在特定的时间间隔内创建快照。例如,可以是每日快照,或者范围取决于特定的事件数量。然后,可以通过重放从快照拍摄时间开始的事件来得出状态,省去了从第0个事件开始重放的需要。

但是,当涉及到实时事件时,快照时间应该降到非常低。

我们可以结合CQRS (命令和查询责任隔离)和流处理来解决这个问题。

CQRS和流处理

CQRS是一种模式,它迫使人们使用不同的模式来读写数据。

因此,当涉及到实时数据时,你的前端可以将数据推送到一个Web Socket通道,该通道将进入事件总线(存储事件流)。然后,事件快照被处理,重建的状态被订阅于事件总线的处理代理存储在数据存储中。

用于查询的REST API

然后,新的状态通过REST API公开,用于完成CQRS流程的数据查询。REST API对于初始数据加载很有帮助。

但是,由于我们谈论的是实时数据,我们是否必须等到最终状态构建完成后再通知订阅者?答案是否定的!

流处理来发布事件

你可以使用另一组订阅者代理来处理事件流,并将事件直接发布到Web Socket通道上。因为它与构建状态并行发生,所以响应会更快。

假设你正在构建一个聊天应用程序。那么,当用户从其前端发送一条消息作为事件时,我们可以将其转发到相关的Web Socket通道。

如果消息是自带目的地的数据,那么在转发到相关通道之前,需要进行最小的处理。

然而,如果你需要查询与每个事件相关的任何元数据,我们可以通过批量处理事件来提高性能。

这样,由于我们可以对数据库进行批量查询,而不是逐一处理消息,所以丰富发布消息变得更快。

正如你所看到的,事件源与CQRS和流处理相结合,由于具有多种优势,最终会使实时应用程序受益。

CRUD vs Event Sourcing

除了上面讨论的内容,让我们来比较一下实时应用程序的CRUD与事件源。

总结

考虑到上述所有情况,我们可以看到,事件源本身有其复杂性。此外,事件源是一个范式的转变,它将给开发者带来很大的认知负担。

但是,从一开始,事件源看起来是对实时前端应用的补充,因为它解决了我们在CRUD方法中的一些问题。

然而,值得评估的是,你的应用程序首先是否需要事件源。如果你的应用程序似乎不需要保持历史状态,审计日志在规模上很高,最好不要用事件源将其复杂化。

然而,如果你遵循微服务范式,它是值得研究的。