事件溯源超越关系数据库 - confluent


我一直觉得事件溯源很吸引人。我们在开发人员的大部分时间里都在将数据保存在数据库表中——以一种完全不同的方式来做这件事似乎几乎是深不可测的。然而,这就是事件溯源。它有明显的好处,但还有许多潜在的问题。
首先,您需要确定事件溯源是否适合您要解决的问题。为您的系统决定是使用事件源还是基于 CRUD 的数据解决方案类似于决定是使用笛卡尔坐标系还是极坐标系来解决数学问题:两者都可以用于解决问题,但有些问题更适合一个坐标系(例如,行星绕太阳的运动最好用极坐标解决)。
 
传统事件溯源(约 2000 年代初)
为了更好地理解传统意义上的事件溯源,您可以首先将其与正常的 CRUD 流程(例如可能与电子商务购物车一起使用)进行考虑。假设您将三条裤子添加到购物车中,稍后改变主意并删除两条,然后继续结账时只带了一条。在 CRUD 模型中,只会将最终结果存储在数据库中,因此您只订购了一条裤子的事实将被记录下来,仅此而已。但是在事件溯源模型中,你在这个过程中所做的每一个动作都会被存储起来,即第一个添加三条裤子的动作,第二个删除两条裤子的动作,以及购买单条裤子的最后一个结账动作. 您正在有效地收集用户活动的时间序列——系统本身的日志。
您几乎可以使用任何数据库执行事件溯源。基本上,您创建一个表并按事件发生的顺序附加事件。最后,您查询最有可能按客户 ID 或会话 ID 聚合的事件,然后执行“按时间顺序减少”以过滤与您想要提供服务的视图相关的事件。
事件溯源优势有几个方面。

  • 首先,有证据优势——“会计师不会用橡皮擦”。事件溯源为您的系统创建了一个类似于版本控制的审计,它允许您确定,例如,为什么在特定时间点出现问题。
  • 这导致了第二个优势:“可重玩性”。如果您的数据被错误损坏,例如,一个可能影响整个应用程序系统的数据,您可以返回到错误出现之前的某个点。收集这么多数据的最后一个好处是,您可以将其输入到分析系统中,无论是用于机器学习还是其他类型的分析。回到购物车的概念,因为购物车给了我们非常真实的用户行为记录,

因此,传统的事件溯源及其优势相对简单,但更复杂的架构(需要使用 Apache Kafka  等工具进行大规模扩展和流式传输的架构)是否也能享受到它的优势?
 
使用 Kafka 和 CQRS 进行事件溯源
当您开始使用像 Kafka 这样的流处理器来推理事件源时,很明显,按时间顺序排列的事件会进入日志。但是当你开始查询时,事情变得有点奇怪:你如何在 Kafka 中执行必要的事件查询,因为它缺乏内部查询 API?(这实际上是互联网上的一个常见问题,启发了许多博客文章。)
解决办法是 CQRS(命令查询责任分离),这是一种事件溯源形式,它将执行“命令”(更改状态)的系统部分与“查询”(返回值)的部分分开。CQRS 的另一个重要方面是在写入时立即完成按时间顺序的缩减,因此视图在提供服务之前异步更新。
所以 Kafka 持有状态,但它被推送到流处理器 API(通常是ksqlDB),在那里创建适合特定用例的物化视图。事件在很大程度上仍然是存储模型,并且可以随时从底层事件重新生成视图。
 
即使使用 CQRS,事件溯源也很困难
在 CRUD 系统中,通常只有一个应用程序和数据库,但在 CQRS 中,有更多活动部件:一个应用程序、一个 Kafka 主题和一个视图——即使是最简单的形式。没有模式迁移,所以随着事件模式随着时间的推移而演变,许多不同的模式最终会出现在日志中。并且复杂性随着模式的数量而增加,因为每个模式需要不同的解析代码。最后,CQRS 的一个关键因素是它只有最终一致,这意味着您不一定能读取自己的写入。
因此,CQRS 有一点额外的复杂性,但该模型适用于许多不同类型的用例。
例如,《纽约时报》将报纸自 1851 年创刊以来的每一次编辑、图像、文章和署名都存储在一个 Kafka 主题中。原始数据存储为事件,然后服务将其转换为要在网站上交付的视图。内容来源的 CMS 实际上并不需要立即与服务层保持一致。如果需要不同的视图,日志会被倒回,并通过重放来创建一个新的视图。
 
什么时候您仍然需要 CRUD 
顺便说一句,如果 CRUD 对您的应用程序有意义,那么有一些方法可以获得事件溯源的一些好处。您可以使用老式触发器,或者您可以更改数据捕获 (CDC) 您的数据,如果您想稍后将其导入 Kafka,这是一个不错的选择。通过这些选项,您将获得一些有益的事件溯源属性,但不是全部 — 它仍然是证据,您可以进行分析,但您将无法获得可重玩性(如果您有一个 Web 应用程序,这可能不会)事情)。您可以尝试的另一个选项是双时态数据库,这是一种通常被低估的数据库。
 
CQRS随着数据的流动而自成一体
单体应用程序受益于事件,但当数据必须移动时,它们真的变得很重要——当应用程序的不同部分需要相互合作并共享数据时,可能在全球范围内。
一个例子是航班预订系统,它的读取次数可能是写入次数的 10,000 倍,并且是全球性的。您可以尝试使用全局分布式数据库来设置系统,但这不一定是最有效的方法,因为无论数据是否来自全局一致的数据库,读取本身最终始终是一致的——因为浏览器缓存和其他因素。最重要的是,当您预订航班时,您肯定会得到预订。因此,将读取和写入分开并让写入到一个一致的地方是有意义的,但让读取去一个最终一致的地方。
 
事件流适合的地方
事件流是事件源和 CQRS超集。它的事件使用共享数据模型,这意味着许多服务可以访问它们。它不仅创建视图,还实时将来自不同来源的数据缝合在一起。
它还具有多语言持久性,这意味着每个服务都可以选择存储数据的位置和方式。这开启了事件驱动处理的可能性,事件由此触发其他动作——这确实是事件流的核心。
总之,使用数据库进行事件溯源显然是一种非常好的模式:它适用于单体应用并且已经存在很长时间了。CQRS 是一种改进,但对于需要在许多服务之间扩展和共享数据的微服务架构来说,具有这两种元素的事件流是最佳选择。
 
banq:其实可以在经典事件溯源与CRUD关系数据库模型之间取得一个平衡,将事件溯源看成是一种明细表、任务表或领域事件集合,这种新的中庸模式没有经典事件溯源的僵化,也就是可以删除条目的,不像事件溯源那样不可以删除,只能追加,这种僵化的教条带来问题是,事件溯源库中有大量人为操作印迹,这种印迹留痕只有在安全追溯有用,这属于大数据统计分析领域,不属于业务模型领域,再者欧洲有隐私法律,用户提出要求后,其操作数据必须不留痕地删除,否则违法。
新的中庸模式可以利用传统关系数据库保存领域事件集合,降低系统复杂性,教条主义会增加复杂性,复杂性是最大敌人。