设计目标

  1. 尽量快的处理命令和事件,保证吞吐量;
  2. 处理完一个命令后不需要等待命令产生的事件持久化完成就能处理下一个命令,从而保证领域内的业务逻辑处理不依赖于持久化IO,实现真正的in-memory;
  3. 保证命令、事件处理的顺序性,先来的先处理,先产生的先处理;
  4. 保证一个聚合根的事件只有一个线程在持久化,并按事件产生的顺序持久化;
  5. 持久化事件时如果遇到并发冲突时(聚合根ID+事件版本号出现重复)的处理代价要轻;
  6. 要能利用多核的优势;

总体设计思路

  1. 先将命令根据聚合根ID路由到CommandMailBox里;
  2. 单线程处理CommandMailBox中的命令,由于聚合根在in-memory本地内存,所以处理非常快;
  3. 处理成功后更新聚合根的in-memory内存;
  4. 内存更新后将聚合根产生的事件同样原理路由到EventMailBox里;
  5. 单线程批量处理EventMailBox中的事件;由于是批量,所以持久化的吞吐量也可以保证;
  6. 处理完成一批事件后,把这一批事件对应的命令从CommandMailBox中移除;

详细设计思路

  1. 设计N个存放命令的CommandMailBox,命令首先按聚合根ID的hashcode取摸路由到对应的CommandMailBox;
  2. 每个CommandMailBox都有一个maxOffset, consumeOffset,以及一个CommandProcessor(单线程)在不停的处理;maxOffset表示最后一个命令的位置;consumeOffset表示当前正在处理的命令的位置;
  3. CommandProcessor的处理逻辑;
    • 创建、修改聚合根;
    • 更新聚合根的in-memory缓存;
    • 将聚合根产生的事件按聚合根ID的hashcode取摸路由到对应的EventMailBox;EventMailBox的个数也是程序启动时配置;
  4. 每个EventMailBox都有一个maxOffset, consumeOffset,以及一个EventProcessor(单线程)在不停的处理;maxOffset表示最后一个事件的位置;consumeOffset表示当前正在处理的事件的位置;
  5. EventProcessor的处理逻辑:
    • 按次序批量获取一批要处理的事件;
    • 批量持久化事件到EventStore,采用SqlBulkCopy;
    • 如果持久化一切顺利,则publish这一批事件(publish如果遇到网络IO异常,则重试,直到成功为止),然后继续持久化下一批,并同时将当前这一批事件对应的命令从CommandMailBox中删除;.
    • 如果持久化遇到并发冲突(事件的aggregateRootId+Version重复),则对当前这一批事件一个个按顺序持久化。如果当前事件持久化成功,则同样publish该事件,当然遇到IO异常时也要不断重试,直到成功为止;成功后通知CommandMailBox移除当前事件对应的命令;如果当前事件持久化出现并发冲突,就做如下处理:

      1. 先通知当前事件对应聚合根暂停处理后续的命令;
      2. 用Event Sourcing技术将in-memory中的聚合根的状态还原到最新状态,确保下次执行command时基于的聚合根的状态是最新的;
      3. 把这一批里该聚合根的所有事件移除,把EventMailBox中的该聚合根的所有事件移除;
      4. 将CommandMailBox的处理位置重置为当前事件对应的命令的offset;从而可以确保产生并发冲突的事件对应的命令以及后续的命令能再重新被处理一遍;
      5. 通知当前事件对应聚合根继续处理后续的命令(从哪个位置开始处理,在上面第4步已经重置过了);
      6. 这一批的所有事件都一个个处理完之后,按同样的逻辑继续处理下一批事件;

其他说明

  1. 上面的设计基于一个前提,就是一个聚合根几乎不会同时在两台服务器上同时存在并处理命令,否则就会出现并发冲突,而并发冲突的处理的代价还是比较复杂的,应该尽量避免;这点可以通过EQueue保证;
  2. 当聚合根处理了命令,尝试更新in-memory内存时,可能有一种情况会失败。就是如果这个命令是创建聚合根的,而有可能并发的时候这个聚合根可能在内存中已经有了,则创建完聚合根添加到内存时,应该能检测出来并记录错误日志,然后该命令产生的事件也不必放入EventMailBox,然后认为该命令处理成功即可。
  3. 上面的设计中没有谈到当遇到命令重复执行时的设计思路,大家可以自己想想:)

ENode框架单台机器在处理Command时的设计思路的更多相关文章

  1. 不要将缓存服务器与Tomcat放在单台机器上,否则出现竞争内存问题

    缓存分为本地缓存和远程分布式缓存,本地缓存访问速度更快但缓存数据量有限,同时存在与应用程序争用内存的情况. 1.不要将缓存服务器与Tomcat放在单台机器上,否则出现竞争内存问题 2.不要将缓存服务器 ...

  2. 每天有300W的pv,我们单台机器的QPS为58,大概需要部署几台这样机器?

    每天有300W的pv,我们单台机器的QPS为58,大概需要部署几台这样机器? 一.总结 一句话总结: ( 3000000 * 0.8 ) / (86400 * 0.2 ) = 139 (QPS) 13 ...

  3. 读懂在单台机器上创建RabbitMQ集群

    在优锐课java中了解有关在单台计算机上安装集群以及如何向集群添加更多节点的更多信息,码了很多专业的相关知识, 分享给大家参考学习. 如果你在单台计算机上设置群集时遇到问题,那么以下文章可能会帮助回答 ...

  4. 单台机器配置redis多实例

    1.增加/usr/local/redis/etc中拷贝一份配置文件重新命名为redis6483.conf 2.编辑redis6483.conf daemonize yes  //以后台进程启动 pid ...

  5. ENode 2.0 - 介绍一下关于ENode中对Command的调度设计

    CQRS架构,C端的职责是处理从上层发送过来的command.对于单台机器来说,我们如何尽快的处理command呢?本文想通过不断提问和回答的方式,把我的思考写出来. 首先,我们最容易想到的是使用多线 ...

  6. enode框架step by step之消息队列的设计思路

    enode框架step by step之消息队列的设计思路 enode框架系列step by step文章系列索引: enode框架step by step之开篇 enode框架step by ste ...

  7. enode框架step by step之框架要实现的目标的分析思路剖析1

    enode框架step by step之框架要实现的目标的分析思路剖析1 enode框架系列step by step文章系列索引: 分享一个基于DDD以及事件驱动架构(EDA)的应用开发框架enode ...

  8. enode框架

    enode框架 2.0 step by step之整体架构介绍 前言 enode框架简介 enode架构图 command handler一次只处理一个command 让domain生活在in mem ...

  9. enode框架step by step之Staged event-driven architecture思想的运用

    enode框架step by step之Staged event-driven architecture思想的运用 enode框架系列step by step文章系列索引: 分享一个基于DDD以及事件 ...

随机推荐

  1. 博客使用BOS上传图片

    1.博客平台的选定 从大学开始做个人主页算起,最开始是使用html,CSSS写简单的页面,后面大学毕业之后接触到了WordPress,就开始用WordPress搭建网站.现在还维护着一个农村网站.ht ...

  2. Asp.net Core 初探(发布和部署Linux)

    前言 俗话说三天不学习,赶不上刘少奇.Asp.net Core更新这么长时间一直观望,周末帝都小雨,宅在家看了下Core Web App,顺便搭建了个HelloWorld环境来尝尝鲜,第一次看到.Ne ...

  3. C# Entity Framework并发处理

    原网站:C# Entity Framework并发处理 在软件开发过程中,并发控制是确保及时纠正由并发操作导致的错误的一种机制.从 ADO.NET 到 LINQ to SQL 再到如今的 ADO.NE ...

  4. 【干货分享】流程DEMO-制度发文和干部任免

    流程名: 制度发文和干部任免  业务描述: 当员工在该出勤的工作日出勤但漏打卡时,于一周内填写补打卡申请.  流程相关文件: 流程包.xml  流程说明: 直接导入流程包文件,即可使用本流程  表单: ...

  5. H3 BPM让天下没有难用的流程之功能介绍

    H3 BPM10.0功能地图如下:  图:H3 BPM 功能地图 一.流程引擎 H3  BPM 流程引擎遵循WFMC 标准的工作流引擎技术,设计可运行的流程和表单,实现工作任务在人与人.人与系统.系统 ...

  6. InnoDB:Lock & Transaction

    InnoDB 是一个支持事务的Engine,要保证事务ACID,必然会用到Lock.就像在Java编程一下,要保证数据的线程安全性,必然会用到Lock.了解Lock,Transaction可以帮助sq ...

  7. EF里Guid类型数据的自增长、时间戳和复杂类型的用法

    通过前两章Lodging和Destination类的演示,大家肯定基本了解Code First是怎么玩的了,本章继续演示一些很实用的东西.文章的开头提示下:提供的demo为了后面演示效果,前面代码有些 ...

  8. 【流量劫持】SSLStrip 终极版 —— location 瞒天过海

    前言 之前介绍了 HTTPS 前端劫持 的方案,虽然很有趣,然而现实却并不理想.其唯一.也是最大的缺陷,就是无法阻止脚本跳转.若是没有这个缺陷,那就非常完美了 -- 当然也就没有必要写这篇文章了. 说 ...

  9. XCodeGhost表明:为了安全,开发工具应该从官方网站下载

    今天的热门话题就是XCode编译器,这个神器在火热的移动互联网浪潮下也被人利用了,据文章分析 (XCode编译器里有鬼 - XCodeGhost样本分析)http://www.huochai.mobi ...

  10. 浅谈浏览器http的缓存机制

    针对浏览器的http缓存的分析也算是老生常谈了,每隔一段时间就会冒出一篇不错的文章,其原理也是各大公司面试时几乎必考的问题. 之所以还写一篇这样的文章,是因为近期都在搞新技术,想“回归”下基础,也希望 ...