介绍事件源。第2部分

本文的翻译是在“ Java开发人员”课程开始时准备的专业“

阅读第一部分。










事件源实现的功能



从技术角度来看,事件源仅需要实现记录事件并从日志中读取的实现。



在最简单的情况下,可以将文件用作事件存储,其中将每个事件保存到单独的文件时,在每行上记录一个单独的事件,或者在多个文件中记录一个文件。但是通常,在要求并行性和可伸缩性的大型系统中,将使用更可靠的存储方法。



事件日志是与Message Broker(面向消息的中间件)和事件流处理系统结合使用的非常常见的模式。如果需要,用作事件日志的消息代理可以存储整个消息历史记录。



关系和文献模型通常集中在实体建模上。在这样的模型中,通过读取一个或多个行或文档很容易获得当前状态。值得注意的是,事件源和关系模型不是互斥的。事件源系统通常包括两者。 Event Sourcing的主要区别在于实体存储不再被视为原始数据。可以通过事件日志重新处理来替换或重建它。



在更复杂的事件源系统中,必须存在派生的状态存储,以进行有效的读取请求,因为随着时间的推移通过处理整个事件日志来检索当前状态可能会停止扩展。关系数据库和文档数据库都可以用作事件日志和派生实体的存储库,通过它们您可以快速获取当前状态。实际上,这种关注点分离是CQRS(命令查询责任隔离)。所有请求都路由到派生存储,以便可以独立于写操作进行优化。



除技术部分外,还有其他要注意的地方。



潜在的事件来源问题



尽管事件源具有优势,但它也具有劣势。



最大的挑战通常是在开发人员的心态中。开发人员需要超越常规的CRUD应用程序和实体商店。事件现在应该成为主要概念。



使用事件源,在建模事件上花费了大量精力。将事件写入日志后,必须将其视为未更改,否则,历史记录和状态可能已损坏或已损坏。事件日志是原始数据,这意味着您需要非常小心以确保它包含在特定时间点获取系统完整状态所需的所有信息。还应牢记,随着系统(及其代表的业务)随着时间的变化,可以重新解释事件。而且,不要忘记对数据验证进行正确处理的错误和可疑事件。



对于简单的领域模型,这种思想上的改变可能非常容易,但是对于更复杂的领域模型,这可能是一个问题(尤其是实体之间存在很多依赖关系)。与在特定时间点不提供数据的外部系统集成可能很困难。



事件源可以在大型系统上很好地工作,因为事件日志模式自然可以水平扩展。例如,一个实体的事件日志不必物理上与另一实体的事件日志相同。但是,这种易于扩展的方式以异步处理和最终一致的数据的形式导致了其他问题。用于更改状态的命令可以到达任何节点,然后系统需要确定哪些节点负责相应的实体,并将命令发送到这些节点,然后处理该命令,然后将生成的事件复制到存储事件日志的其他节点。并且只有在完成此过程之后,新事件才可以作为系统状态的一部分使用。因此,事件源实际上需要将命令处理与状态请求(即CQRS)分开。



因此,事件源系统需要考虑发出命令和接收有关成功事件记录的通知之间的时间间隔。用户此时看到的系统状态可能是“错误的”。或者说,有点过时了。为了减少该因素的影响,在设计用户界面和其他组件时必须考虑到这一因素。当命令失败,在执行过程中被取消或更新数据时,一个事件被一个新事件代替时,也必须正确处理情况。



当事件随时间累积时,将出现另一个问题,因此有必要与他们合作。在处理后将它们写下来是一回事,而处理整个历史则是另一回事。没有此功能,事件日志将完全失去其价值。对于灾难恢复或迁移派生的存储(当可能需要重新处理所有事件以更新数据时)尤其如此。对于具有大量事件的系统,重新处理整个日志可能会超过允许的恢复时间。定期的系统快照可以为您提供帮助,以便您可以从以后的健康状态开始恢复。



还必须考虑事件的结构。事件的结构会随着时间而改变。字段集可能会更改。在某些情况下,旧事件需要由当前业务逻辑处理。可扩展事件方案的存在将有助于将来在必要时将新事件与旧事件区分开。定期快照还有助于隔离事件结构中的主要变化。



结论



事件采购是一种有好处的强大方法。其中之一是使将来扩展系统变得更加容易。由于事件日志存储所有事件,因此可以在外部系统中使用它们。通过添加新的事件处理程序可以很容易地进行集成。



但是,与任何主要的体系结构决策一样,您需要小心以确保它适合您的情况。与域的复杂性,对数据一致性和可用性的要求以及从长远来看存储数据量的增加和可伸缩性有关的约束,必须考虑所有这些因素(这绝不是详尽的清单)。同样重要的是,要注意将在整个生命周期中开发和维护这样的系统的开发人员。



最后,不要忘了软件工程最重要的原则-力求使一切尽可能简单(KISS原则)。





阅读第一部分




All Articles