返回首页
最新
许多团队喜欢不可变事件日志的想法,但由于经典事件溯源需要聚合、每个实体的流和深度领域驱动设计,往往不予采纳。每次写入通常意味着需要重放数千个事件,以在内存中重建聚合,然后才能附加新事件。这确保了完美的一致性,但也提高了入门的门槛。
在领域驱动开发与事件溯源中,你需要设计一个聚合,例如订单(Order)。对于这个聚合,你设计领域事件,如订单创建(OrderCreated)、订单信息更新(OrderInfoUpdated)、订单归档(OrderArchived)和订单完成(OrderCompleted)。这意味着存储在订单聚合中的每个事件都是这些设计好的领域事件之一。在这一点上,你创建订单聚合的实例(系统中每个实际产品订单一个实例),例如 Order-001、Order-002,依此类推。对于每个实例,例如 Order-001,你附加与该订单在其事件流中发生的事件相对应的领域事件。
在将领域事件附加到事件流(即你的真实来源)之前,你必须确保用户操作是有效的。验证用户操作/命令是通过重新加载/重放相关聚合实例的每个过去事件来完成的。对于名为 BankAccount 的聚合及其聚合实例,例如 BankAccount-1234,可能会有数百万个领域事件/事件,这意味着每当有人对其银行账户进行操作时,验证该操作可能需要很长时间,这就是快照(snapshots)概念的用武之地,以加快这一过程。
重新加载整个事件历史的目的是为了重建你的应用程序当前状态,或者更具体地说,重建实体/聚合实例的当前状态,即 BankAccount 或 Order。这样做是为了确保你在验证新的用户操作时是基于最新的应用状态,而不是旧的应用状态。
还有另一种方法可以实现验证(并实现事件溯源的核心概念),它不需要你处理重新加载整个事件流的复杂性,也不需要设计聚合来验证新的用户操作。我将要解释的这种替代方案降低了 CQRS + 事件溯源的入门门槛,因为它消除了领域驱动设计的复杂性,并显著扩大了使用案例和可及性(一些经典用例可能不适合这种方法)。但同时,它需要一种不同且强大的基础设施。
我所建议的方法是重新利用领域事件,使其成为我们所称的事件类型(Event Types)的事件流。与其为每个单独的订单创建事件流,不如将每个创建、更新、归档或完成的订单归类到相应的事件类型中。这意味着在提供的示例中,你将为订单聚合拥有 4 个事件流,而不是为系统中的每个订单拥有一个事件流。
我实现事件溯源的方法是通过对实时读取模型进行简单的 SQL 业务逻辑检查。这些读取模型包含了我应用程序的最新状态,在高吞吐量的关键情况下,延迟为个位数毫秒,而在较小吞吐量的较少关键情况下,延迟为个位数秒。
这两种方法都使用应用程序的当前状态,要么通过调用读取模型,要么通过重新加载所有过去的事件来重建当前状态。重新加载只有在不同步的读取模型不可接受时才显得重要。生产数据库在 CQRS 中是下游服务,因此总会存在轻微的延迟。在高争用或超低延迟的领域,如真实货币转账,你应该重放单个账户流以避免风险。如果读取模型在几毫秒到几秒内更新,那么对其进行验证对于绝大多数应用程序来说是完全足够的。
“参与度”是一个糟糕的指标。
如果你所使用的指标可以被毒贩和赌场老板同样轻松地应用,那你就真的搞砸了。
是的,这是一篇低投入的文章,但我刚花了5分钟在LinkedIn的动态上,实在需要发泄一下。
感谢你来听我的TED演讲。
你好,这是我过去18个月一直在努力的项目。目前有很多工具可以在桌面上本地运行大型语言模型(例如ollama、LM Studio),但其他设备却被忽视了。这个项目旨在将这些模型运行在iOS和visionOS上,结果效果非常好。甚至一部iPhone 14 Pro也能轻松运行3B参数版本的Llama 3.2。CLIP模型的表现也很好!
它还具有实时语音聊天功能,提供双向对话体验,类似于谷歌提供的基于云的Gemini Live功能。
在技术层面上,它可以运行大多数GGUF模型,使用的是 heavily forked 和 diverged 版本的 llama.cpp,这提升了移动设备上的性能。
接下来的步骤是整合苹果的设备本地3B模型,希望他们能在一周后的WWDC上开放访问。我也正在添加对Gemma 3和Qwen 3的支持。
请告诉我你的想法!