导语: 微服务架构目前是各互联网系统架构的首选,在使用微服务的过程中,调试一个分布式系统是一项具有挑战的任务, 事件溯源是一种非常好的方式来解决微服务可见性的一种手段。且看大名鼎鼎的couchbase如何使用事件溯源解决微服务的可见性问题。正如我在之前的文章中提到那样,微服务是怎样失败的,调试一个分布式系统是一项具有挑战的任务。 许多东西可能是错的并且是不可控的, 例如网络的不稳定性,临时不可用或者是一些外部的BUG。 用一些工具监控网络能被快速解决(像Service Mesh ),你也可以使用一些额外的工具像OpenTracing 来做分布式的日记记录. 但是当我们谈到理解我们的实体状态时,并没有快速的即插即用的框架。 你的数据可能比你代码存活的时间还要长, 然而我们却忽略了我们的数据随着时间推移而产生的变化。 在大多数系统中,即使是简单的问题, 例如“该实体如何达到这种状态?” 或 “一个月前我的状态是怎样的?” 都无法回答,因为没有保存任何变更的历史记录。 持续追踪这些变更状态对一个系统的健康是极其重要的, 不仅是为了安全或者是调试目的, 而是出于巨大的商业价值(你的产品负责人会很高兴) 解决方案 通过事件溯源|事件记录为服务行为增加可见性是一种很好的方式。 一个比较好的办法是。这个有10年之久的基本概念是让一个应用的每一次变更都应该被记录在一个事件对象并且被有序存储。 如果这听起来很熟悉,那可能是因为任何版本的控制系统或数据库事务日志都是这种模式的重度用户。 让我们来深入理解它是怎么工作的。 假设我们正在为一个电商网站构建一个订单服务(Order Service) , 让我们看一下我们的应用状态和事件看起来是怎样的: 许多作者对于事件的溯源和记录都定义了三个主要的规则:
事件溯源| 事件记录流
这种模式有很多种实现方式, 在Couchbase5.5中使用的“事件服务”就是这种模式的实现之一。 总而言之, 它允许你编写函数, 在一个文档被插入/更新/删除时来触发这些函数。 这个事件机制也能让你生成curl 请求,因此无论何时将给定的文档存储在数据库中,都可以在应用程序中触发一个endpoint来处理它。 让我们看一下它是如何使用事件的: Couchbase Eventing 是异步的, 所以上述套件实现仅适用于你的应用只接收异步调用的情况。 它也可以用来充当额外的安全层以触发通知, 例如,如果有人试图手动更新一个事件。 在某些系统中, 事件的字段和结构可能有很大的不同, 将这些事件存储在一个固定结构的RDBM 中是很难建模的, 出于这个原因, 开发人员通常将它他们用一个varchar类型的字段将这些事件存储为一个json字符串。这种办法存在一个主要的问题: 它使得事件查找变得困难,使你的大部分查询变慢, 变复杂并且充拆着大量的类似'likes'操作。 其中一种可有的解决方案是使用文档数据库, 因为它们大多数将文档存储为json并且具有用于查询它的类似SQL的语言, 如N1QL[1]。 快照-对你的状态进行版本控制 事件溯源世界中添加版本控制/历史记录被称为快照。 当你想要想要知道N天以前的状态是什么样的, 可以避免你重新处理所有的事件。 当你需要快速识别在某时间点时应用的状态与处理一个事件之后的所预期的状态之间的差异。 快照具功能十分好用,成本低,易实现并且非常适合实时的上报。 如果你决定实现一个Event Sourcing, 可以在实现快照中多投入一点努力。 这部份是你的所有的努力得到回报的地方。 一旦你在这个地方有了事件溯源/记录并且具有快照功能, 你就可以使用Retroactive Event 模式的来修复不一致的情况。 我总结一下, 如果你修复了一个BUG并且现在需要调整被影响实体的状态, 而不是手动更新他, 你可以将你的实体的状态设置为BUG之前的状态,并且从那个时刻重放所以与之关联的事件。 无须手动就会自动修改你的状态。
但是,如果事件中有错误数据或者从来没有被触发过,该怎么办?我们可以更新或删除事件并重新处理整个事件吗? 如果你还记得,事件溯源的第一条规则是“事件永远是不变的”,这是一个很好的理由;你需要相信你所看到的日志。但它不能回答我们的问题;只需略微修改一下:我们如何在不更改事件的情况下更改事件日志? 那么,解决这个问题的一个简单方法就是将事件标记为可忽略的,以便在重建过程中我们可以忽略它们: 如果事件是由错误数据或错误顺序触发的呢?使用这种方法,我们不得不做的就是将所有事件标记为可忽略的,并添加一个具有正确值或位置正确的新事件,如下所示: 一个笨办法是为每个实体添加一个浮点计数器。它会让你根据超任务(supertask)的理论在中间无限增加项(实际上,你受到float/double 最大的长度限制),这通常足以容纳所有必要的事件来修复你的状态: 关于外部系统|其他微服务? 微服务不是孤岛,重放事件的副作用之一是你的服务向外部发送消息是合理的。这些消息可能会在其他系统中引发不一致或传播错误,这可能会使情况比以前更糟糕。 不幸的事,由于可能的情况多种多样, 这里没有银弹来解决这个问题, 并且每一个案例不得不单独处理。 下面给出一些普遍的解决方案:
当然,有相当多的情况下,您无法自动修复外部不一致情况,在这种情况下,预计其他系统会输出人为可读的错误和/或触发人工干预的通知。
事件溯源的优点 尽管它是一个简单的模式,但使用它有很多优点:
许多作者还将优先级作为时间查询的能力,但我认为查询多个后续事件不是一项简单的任务。因此,我通常认为时间查询是快照模式的一个优点。 事件溯源的缺点
结论 我已经展示了稍微修改过的事件溯源/事件记录模式,这在过去几年一直很适合我。我第一次听说这种方法是近10年前在Marting Fowler博客文章(必读)中。从那以后,它为我提供了很多帮助,使我的微服务的状态几乎牢不可破。 然而,这种方法也不该在你的所有服务中不分青红皂白地使用。我个人认为只有核心价值才是真正值得的。例如,您可能不需要保留用户在系统中更改自己的姓名的所有时间的历史记录。 如果您有任何问题,请随时在@deniswsrosa推特给我 参考链接 [1] https://query-tutorial./tutorial/#1
|
|