Questions tagged «event-sourcing»

2
ES / CQRS并发处理
我最近开始研究CQRS / ES,因为我可能需要在工作中应用它。对于我们来说,这似乎很有希望,因为它将解决很多问题。 我对ES / CQRS应用程序如何看起来像上下文简化后的银行业务用例(提取资金)进行了粗略的了解。 综上所述,如果A人提取了一些钱: 发出命令 命令已交出以进行验证/验证 如果验证成功,则将事件推送到事件存储 聚合器使事件出队以对聚合应用修改 据我了解,事件日志是事实的源泉,因为它是FACTS的日志,因此我们可以从中得出任何预测。 现在,在这种宏伟的计划中,我不了解的是在这种情况下会发生什么: 规则:余额不能为负 A人的余额为100e 人A发出100e的WithdrawCommand 验证通过并发出100e事件的MoneyWithdrewEvent 同时,人A发出另一个100e的WithdrawCommand 第一个MoneyWithdrewEvent尚未汇总,因此验证通过,因为针对汇总(尚未更新)的验证检查 再次发出100e的MoneyWithdrewEvent ==>我们处于不一致状态,余额为-100e,并且日志包含2 MoneyWithdrewEvent 据我了解,有几种策略可以解决此问题: a)将聚合版本ID和事件一起放入事件存储中,因此,如果修改后版本不匹配,则不会发生任何事情 b)使用一些锁定策略,这意味着验证层必须以某种方式创建一个 与策略有关的问题: a)在这种情况下,事件日志不再是事实的源头,如何处理?另外,我们还给客户端确定,但是允许退出是完全错误的,在这种情况下使用锁是否更好? b)锁==死锁,您对最佳做法有什么见解? 总体而言,我对如何处理并发的理解正确吗? 注意:我了解同一个人不可能在如此短的时间内提取两次资金,但是我举了一个简单的例子,不要迷失细节

2
事件源和REST
我遇到了事件源设计,我想在需要REST客户端(准确地说是RESTful)的应用程序中使用。但是,由于REST非常像CRUD,并且事件源基于任务,因此我无法将它们连接在一起。我想知道您如何设计基于对REST服务器的请求的命令创建。考虑以下示例: 借助REST,您可以将一个新状态放入名为File的资源中。在一个请求中,您可以发送新的文件名,可以更改父文件夹和/或更改文件的所有者,依此类推。 如何构造服务器,以便可以使用事件源。我在考虑这些可能性: 确定服务器上哪些字段被改变,并创建相应的命令(RenameFileCommand,MoveFileCommand,ChangeOwnerCommand,...)并单独派遣这些。但是,在这种设置中,每个命令都可能失败,从而使其他命令无法进行事务处理,从而无法进行资源的“原子”更改。 调度只需要一个命令(UpdateFileCommand),并在命令处理程序,更精确地在总量上,确定哪些领域发生了变化,并发送单个事件,而不是(FileRenamedEvent,FileMovedEvent,OwnerChangedEvent,...) 我一点都不喜欢这个命令:在对服务器的请求中,我会在标头中指定要使用的命令,因为UI仍基于任务(但通信是通过REST完成的)。但是,在REST通信的任何其他用途(例如,外部应用程序)中,它都将失败,因为它们不一定要仅更改一个请求中的一个字段。另外,我在UI,REST和基于ES的后端中引入了很大的结合。 您更喜欢哪一个,或者有更好的方法来解决这一问题? 旁注:使用Java和Axon Framework编写的用于事件源的应用程序。

3
使用DDD和CRQS时,每个命令应该恰好是一个事件吗?
我正在寻找一种设计约定通用的ddd应用程序的方法。 说一个聚合“客户端”有一个定义为“ FillProfile”的命令。它将在逻辑上引发事件“ ProfileFilled”。 在某些情况下,命令会引发的事件多于一个事件,或者命令会基于某种逻辑引发不同的事件吗?还是这始终是1-1的关系(1个命令将始终不引发任何事件,或者仅引发给定类型的单个事件)。 我之所以这样问是因为,如果这是事实,那么命令将始终引发同一事件,那么我可以基于该事实建立约定系统。我知道“ RaiseEvent”将导致“ EventRaised” ...

1
为什么Protobuf 3将消息上的所有字段都设为可选?
protobuf的语法3使所有字段成为可选字段,从而删除了关键字required以及optional以前的proto2语法。阅读开发人员的一些评论似乎是为了增强向前/向后二进制兼容性而完成的。 但是对我而言,这可以通过仅对软件包名称进行版本控制(例如说)com.example.messages.v1,然后让客户端实施他们理解的反序列化程序来实施。同时,它删除了一些从软件工程的角度来看有用的合同类型。例如,如果我有 message Location { double latitude = 1; double longitude = 2; } 在proto3中,可以Location通过不提供必填字段之一来创建半备份但完全有效的文件。 创建基于模式的序列化格式以在客户端之间交换数据时,这不是一个很大的缺点吗?将额外的验证代码移至每个客户端以检查所有必填字段均具有有效值,这不是更糟吗?

5
DDD,佐贺(Saga)和事件来源:可以将补偿行为简单地删除事件存储区吗?
我意识到上述问题可能会引起一些“什么?”,但让我尝试解释一下: 我试图将一些相关概念,基本上是Saga模式(http://www.rgoarchitects.com/Files/SOAPatterns/Saga.pdf)与事件源(DDD概念)结合起来:http : //en.wikipedia.org/wiki/Domain-driven_design) 一个很好的文章,将其包装在一起: https //blog.jonathanoliver.com/cqrs-sagas-with-event-sourcing-part-ii-of-ii/ 我一分钟就会解决这个问题,但是我想我必须先总结一下我对它的理解(这很可能是错误的,所以请纠正这种情况),因为这很可能会影响我为什么提出以下问题: Saga模式是一种代理,它给定操作(最终用户,自动化等,本质上是要更改数据的任何操作),将该操作划分为业务活动,并将这些活动中的每一个作为消息发送给Message Bus,依次将其发送到各个聚合根进行处理。 这些聚集的根可以完全自主地运行(关注点分离得很好,可扩展性强等)。 Saga实例本身不包含任何业务逻辑,该逻辑包含在向其发送活动的聚合根中。Saga中包含的唯一“逻辑”是“过程”逻辑(通常实现为状态机),它根据收到的动作(以及后续事件)确定要做什么(即:发送什么活动) Saga模式实现了一种分布式事务模式。即:当聚合根之一(可以再次自动工作,而又不了解彼此的存在)失败时,可能必须回滚整个操作。 这是通过让所有聚合根实现的,将它们的活动报告完成后返回给Saga。(无论成功还是失败) 如果所有聚合根均返回成功,则内部状态机是否由Saga决定下一步(或决定已完成) 在失败的情况下,Saga将参与最后一个动作的所有聚合根发出一个所谓的补偿动作,即:撤销每个聚合根所做的最后一个动作的动作。 如果操作是“加1票”,则可能只是在进行“减1票”,但可能会更复杂,例如将博客文章还原到以前的版本。 事件源(请参阅结合了这两个博客文章)旨在将保存在外部的每个汇总根源的每个活动的结果保存到集中式事件存储中(在这种情况下,这些更改称为“事件”) 此事件存储区是“事实的单一版本”,可用于简单地通过迭代存储的事件来重播所有实体的状态(本质上类似于事件日志) 将两者结合起来(即:让聚集的根使用事件源来将其更改外包,然后再将其报告回Saga)可以实现很多不错的可能性,其中之一是我的问题... 我觉得我需要把这件事从肩膀上移开,因为一口气要掌握很多。鉴于此上下文/心态(再次,请纠正错误) 问题:当汇总根接收到补偿动作并且如果该汇总根已使用事件源外包将其状态更改外包时,补偿动作不是在所有情况下都只是删除事件存储中针对该事件的最后一个事件给定总根?(假设持久实现允许删除) 这对我来说很有意义(这将是这种组合的另一个很大的好处),但是正如我所说的那样,我可能基于对这些概念的错误/不完全理解而做出这些假设。 我希望这不会太冗长。 谢谢。

2
如何在事件源中实施流程管理器
我正在研究一个小示例应用程序,以学习CQRS和事件源的概念。我有一个Basket汇总和一个Product应该独立工作的汇总。 这是一些伪代码来展示实现 Basket { BasketId; OrderLines; Address; } // basket events BasketCreated { BasketId; } ItemAdded { BasketId; ProductId; Quantity } AddItemSucceeded { BasketId; ProductId; Quantity } AddItemRevoked { BasketId; ProductId; Quantity } ItemRemoved { BasketId; ProductId; Quantity } CheckedOut { BasketId; Address } Product { ProductId; Name; Price; } …

3
从“快照”投影而不是事件存储中补水聚合
因此,尽管我从未有机会在实际项目中应用这些模式,但我一直在调动Event Sourcing和CQRS一段时间。 我了解将读取和写入问题分开的好处,并且感谢事件搜寻如何使将状态更改轻松地投影到与事件存储区不同的“读取模型”数据库中变得容易。 我不清楚的是,为什么您会从Event Store自身中重新添加聚合。 如果将更改投影到“读取”数据库很容易,为什么不总是将更改投影到其架构与您的域模型完全匹配的“写入”数据库呢?这实际上将是快照数据库。 我想这在野外的ES + CQRS应用程序中一定很常见。 在这种情况下,事件存储仅在由于架构更改而重建“写”数据库时有用吗?还是我想念更大的东西?

2
如何处理事件来源中的副作用?
假设我们要为金融应用程序实现一个小型安全子系统,该子系统将在检测到异常模式时通过电子邮件向用户发出警告。对于此示例,该模式将包括所描述的三个事务。安全子系统可以从队列中读取主系统中的事件。 我想得到的是一个警报,它是系统中发生的事件的直接结果,而没有中间模式来模拟模式的当前状态。 监控已激活 交易已处理 交易已处理 交易已处理 警报已触发(ID:123) 已发送警报电子邮件(ID:123) 交易已处理 考虑到这一点,我认为事件源可以在这里很好地应用,尽管我有一个没有明确答案的问题。在示例中触发的警报具有明显的副作用,需要发送电子邮件,这种情况只能发生一次。因此,在重放聚合的所有事件时不应发生这种情况。 在某种程度上,我看到需要发送的电子邮件类似于查询方生成的实现,这在CQRS / Event采购文献中已经见过很多次了,尽管差别不大。 在此文献中,查询端是由事件处理程序构建的,该事件处理程序可以在给定点生成状态的实现,从而再次读取所有事件。但是,在这种情况下,由于前面解释的原因,不能完全像那样完成。每个状态都是瞬态的想法在这里并不适用。我们需要记录警报发送到某个地方的事实。 对于我来说,一个简单的解决方案是使用其他表或结构,在其中保留先前触发的警报的记录。由于我们具有ID,因此我们可以检查之前是否发布了具有相同ID的警报。拥有此信息将使SendAlertCommand成为幂等。可以发出几个命令,但副作用只会发生一次。 即使考虑到该解决方案,我也不知道这是否暗示此体系结构对此问题有问题。 我的方法正确吗? 在哪里可以找到更多有关此的信息? 奇怪的是我还没有找到更多有关此的信息。也许我一直在使用错误的措词。 非常感谢!

7
将高频事件保存到连接限制受限的数据库中
我们有一种情况,我必须处理大量涌入服务器的事件,平均每秒大约1000个事件(峰值可能是2000个)。 问题 我们的系统托管在Heroku上,并使用相对昂贵的Heroku Postgres DB,该数据库最多允许500个DB连接。我们使用连接池从服务器连接到数据库。 事件传入的速度快于数据库连接池无法处理的速度 我们遇到的问题是事件的发生速度快于连接池无法处理的速度。到一个连接完成从服务器到DB的网络往返时,它可以释放回池中,而不是n其他事件。 最终,事件堆积起来,等待保存,并且由于池中没有可用的连接,它们超时并且整个系统变得无法运行。 我们已经通过以较慢的速度从客户端发出有问题的高频事件来解决紧急情况,但是我们仍然想知道在需要处理高频事件时如何处理这种情况。 约束条件 其他客户端可能希望同时读取事件 其他客户端连续请求使用特定密钥读取所有事件,即使它们尚未保存在数据库中也是如此。 客户端可以查询GET api/v1/events?clientId=1并获取客户端1发送的所有事件,即使这些事件尚未保存到DB中也是如此。 是否有有关如何处理此问题的“教室”示例? 可能的解决方案 使事件排队在我们的服务器上 我们可以在服务器上排队事件(队列的最大并发性为400,因此连接池不会用完)。 这是个坏主意,因为: 它将耗尽可用的服务器内存。堆积的排队事件将消耗大量RAM。 我们的服务器每24小时重启一次。这是Heroku施加的硬限制。当事件排队时,服务器可以重新启动,导致我们丢失排队的事件。 它在服务器上引入状态,从而损害了可伸缩性。如果我们有一个多服务器设置,并且客户端要读取所有已排队+保存的事件,则我们将不知道已排队事件在哪台服务器上。 使用单独的消息队列 我假设我们可以使用消息队列(例如RabbitMQ吗?),在其中将消息泵入其中,另一方面,还有另一台服务器仅处理将事件保存在DB上。 我不确定消息队列是否允许查询排队的事件(尚未保存),因此,如果另一个客户端想要读取另一个客户端的消息,我只能从数据库中获取已保存的消息,并从队列中获取待处理的消息。并将它们连接在一起,这样我就可以将它们发送回读取请求客户端。 使用多个数据库,每个数据库使用中央数据库协调器服务器保存一部分消息,以管理它们 不过,我们的另一个解决方案是使用多个数据库,并使用一个中央“ DB协调器/负载平衡器”。接收到事件后,此协调器将选择一个数据库来写入消息。这应该允许我们使用多个Heroku数据库,从而将连接限制提高到500 x数据库数。 在进行读取查询时,此协调器可以SELECT向每个数据库发出查询,合并所有结果,然后将其发送回请求读取的客户端。 这是个坏主意,因为: 这个主意听起来像是...太设计了吗?管理(备份等)也将是一场噩梦。它的构建和维护非常复杂,除非绝对必要,否则听起来像是违反了KISS。 它牺牲了一致性。如果我们遵循这个想法,那么跨多个数据库进行事务是不可行的。

3
域驱动设计中的域对象是否应该仅是写操作?
我已经阅读了近两年的关于域驱动设计的文章,并且一直在谨慎地将一些概念引入我的日常工作中,或者至少计划了如何在域驱动设计中定期完成工作的计划。 我开始得出一个结论,尤其是在阅读了有关事件源和命令查询责任隔离(CQRS)的更多信息后,域对象可能仅用于写目的。更清楚地说,在我阅读的许多文档中,人们似乎巧妙地暗示了域对象负责进行以域为中心的操作/计算,验证,然后在那里主要是为持久化提供了一条途径存储库实现中提供的基础结构。尽管我喜欢这样的事实,因为它可以大大简化领域模型,因为它消除了公开状态的责任。 如果确实确实将域对象主要用作只写对象,那么这对我提出了一些问题,希望有人可以回答。 如何对具有setter的对象或修改对象状态但不提供向外公共接口以从诸如C#中的属性获取器读取状态的方法执行单元测试?仅仅为了使该对象可测试就可以公开状态吗? 如何向用户显示在域中完成的计算或运算的结果,而不必持久存储它们,然后将结果从持久存储中拉出到域的上下文之外?仅出于显示结果的目的而公开状态是否可以? 根据经验,唯一的属性获取器(获取访问器)应该是在域中也可写的属性吗?还是换句话说,只读属性应该唯一避免,因为它们仅出于读取目的存在,因此在实际的域模型中不发挥必要的作用? 相关资料: TDD,DDD和封装

1
事件驱动和事件源之间有什么区别?
我正在研究域驱动设计(DDD),并且遇到了一些术语:事件驱动和事件源。我知道这与从生产者到消费者发布事件并存储日志有​​关,所以我的问题是: 事件驱动和事件源之间有什么区别?

2
在分布式,事件源系统中维护一致性的模式?
我最近一直在阅读事件源,非常喜欢它背后的想法,但是仍然遇到以下问题。 假设您有N个并发进程,它们接收命令(例如Web服务器),结果生成事件并将它们存储在集中存储中。我们还假设通过依次应用来自存储的事件,所有瞬态应用程序状态都保留在各个进程的内存中。 现在,我们有以下业务规则:每个不同的用户必须具有唯一的用户名。 如果两个进程收到一个针对相同用户名X的用户注册命令,则它们都将检查X是否不在其用户名列表中,该规则将对这两个进程进行验证,并且它们都会在存储中存储“具有用户名X的新用户”事件。 现在,由于违反了业务规则(存在两个具有相同用户名的不同用户),我们进入了不一致的全局状态。 在传统的N服务器<-> 1 RDBMS样式系统中,数据库被用作同步的中心点,这有助于防止此类不一致。 我的问题是:事件源系统通常如何解决此问题?它们是否只是简单地按顺序处理每个命令(例如,将可写入存储的处理量限制为1)?

2
CQRS +事件源:(是否正确)命令通常是点对点传递的,而域事件是通过pub / sub传递的?
我基本上是想围绕CQRS的概念和相关概念。 尽管CQRS不一定包含消息传递和事件源,但它似乎是一个很好的组合(从结合了这些概念的许多示例/博客中可以看出) 给定一个用于某种情况的状态更改的用例(例如,更新有关SO的问题),您是否认为以下流程是正确的(如最佳实践中那样)? 系统发出一个汇总的UpdateQuestionCommand,可以将其分成几个较小的命令:以Question Aggregate Root为目标的UpdateQuestion和以User Aggregate Root为目标的UpdateUserAction(对点进行计数)。这些是使用点对点消息传递异步发送的。 聚合根起作用,如果一切顺利,则分别引发事件QuestionUpdated和UserActionUpdated,它们包含外包给事件存储的状态。要保留yadayada,只是为了完整起见,此处并不是重点。 这些事件也被放在发布/订阅队列中进行广播。任何订阅者(其中可能有一个或多个创建阅读视图的投影仪)都可以自由订阅这些事件。 一个普遍的问题:最佳实践是命令之间进行点对点通信(即:接收方已知),而广播事件(即:接收方未知)吗? 假设以上所述,允许通过pub / sub而不是点对点广播命令的优点/缺点是什么? 例如:在使用Saga广播广播Commands时可能会出现问题,因为Saga在某个聚合根之一出现故障的情况下需要扮演的调解角色受到了阻碍,因为saga不知道哪个聚合根开始参与。 另一方面,我看到允许广播命令时的优势(灵活性)。

3
事件源和持久性
我正在阅读事件源,并且对持久性有疑问。 我仍然可以拥有一个包含所有实体的数据库,对吗?还是应该在每次启动应用程序时重播事件以获取内存中每个实体的最新版本?似乎在大型系统上(如大量数据)上的浪费? 事件来源的意义在于,如果需要,我可以重播事件以填充数据存储区吗?(或分析数据)

1
如何在CQRS + Event Sourcing架构中处理Add / Create *命令
我想使用CQRS模式和Event Sourcing来实现我的第一个应用程序。我想知道如何正确处理聚合根的创建。假设有人发送CreateItem命令。应该如何处理?事件ItemCreated应该存储在哪里?作为新项目的第一事件?还是我应该具有某种ItemList实体来聚合所有项目,并且其事件列表仅由ItemCreated事件组成? 乌迪·达汉( Udi Dahan)建议不要创建聚合根,而应始终使用某种获取方法。但是我如何获取新的东西,当然还没有分配任何ID。我理解背后的想法,并且认为一个新对象是其状态由零个事件组成的对象是很合理的。但是我应该如何使用呢?我的存储库中应该有一个与众不同的方法吗?getNewItem()还是让我的get(id)方法接受Optional<ItemId>? 编辑:经过一段时间的挖掘,我发现使用actor对上述模式进行了非常有趣的实现。作者不是创建聚合,而是从某种具有新创建的UUID的存储库中检索聚合。这种方法的缺点是他允许出现临时的不一致状态。我也想知道如何delete使用这种方法来实现方法。只需将Deleted事件添加到聚合的事件列表中?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.