我一直在试验JOliver的Event Store 3.0作为项目的潜在组件,并一直试图通过Event Store来衡量事件的吞吐量.
我开始使用一个简单的线束,它基本上通过for循环迭代创建一个新流,并将一个包含GUID id和字符串属性的非常简单的事件提交给MSSQL2K8 R2 DB.调度员本质上是一个无操作员.
这种方法设法在8路HP G6 DL380上运行~3K操作/秒,数据库在单独的32路G7 DL580上运行.测试机器没有资源限制,阻塞看起来是我的限制.
有没有人有过测量Event Store吞吐量的经验以及取得了哪些数据?我希望能够获得至少1个数量级的吞吐量,以使其成为可行的选择.
我同意阻止IO将成为最大的瓶颈.我可以在基准测试中看到的一个问题是您正在针对单个流进行操作.您的域中有多少聚合根,每秒3K +事件?EventStore的主要设计是针对多个聚合进行多线程操作,从而减少了对读取世界应用程序的争用和锁定.
另外,你使用什么序列化机制?JSON.NET?我还没有协议缓冲区实现,但每个基准测试表明PB在性能方面明显更快.对你的应用程序运行一个分析器来查看最大的瓶颈是多么有趣.
我注意到的另一件事是你正在引入网络跳跃到等式中,这增加了针对任何单个流的延迟(和阻塞时间).如果您正在写入使用固态驱动器的本地SQL实例,那么与运行磁盘驱动器的远程SQL实例相比,我可以看到这些数字要高得多,并且数据和日志文件位于同一个盘片上.
最后,您的基准测试应用程序是否使用System.Transactions或默认为没有事务?(EventStore是安全的,不使用System.Transactions或任何类型的SQL事务.)
现在,尽管如此,我毫不怀疑EventStore中的某些区域可以通过一点点关注进行显着优化.事实上,我正在围绕3.1版本的一些向后兼容的架构修订,以减少在单个提交操作期间在SQL Server(以及一般的RDBMS引擎)中执行的写入次数.
在开始作为3.x基础的2.x重写时,我遇到的一个最大的设计问题是异步,非阻塞IO的想法.我们都知道node.js和其他非阻塞Web服务器在一定数量级上击败了线程Web服务器.但是,调用者引入复杂性的可能性增加,必须加以考虑,因为它是大多数程序和库运行方式的根本转变.如果我们确实转向一个规范的非阻塞模型,它将在4.x时间范围内更多.
底线:发布您的基准,以便我们可以看到瓶颈所在.
优秀的问题马特(+1),我看到奥利弗先生自己回答为答案(+1)!
我想引入一种稍微不同的方法,我自己正在使用它来帮助你看到的每秒3000次提交的瓶颈.
使用JOliver的EventStore的大多数人似乎试图遵循的CQRS模式允许许多"向外扩展"子模式.人们通常排队的第一个是事件提交本身,你看到了它的瓶颈."队列关闭"意味着从实际提交中卸载并将它们插入到一些写优化的非阻塞I/O进程中,或者"队列".
我的宽松解释是:
命令广播 - >命令处理程序 - >事件广播 - >事件处理程序 - >事件存储
这些模式中实际上有两个扩展点:命令处理程序和事件处理程序.如上所述,大多数都是从事件处理程序部分扩展开始,或者在你的情况下将事件扩展到EventStore库,因为这通常是最大的瓶颈,因为需要在某个地方持久存在(例如Microsoft SQL Server数据库).
我自己正在使用一些不同的提供程序来测试"排队"这些提交的最佳性能.CouchDB和.NET的AppFabric Cache(具有很棒的GetAndLock()功能).[OT]我非常喜欢AppFabric的持久缓存功能,它允许您创建冗余缓存服务器,在多台计算机上备份您的区域 - 因此,只要至少有1台服务器启动并运行,您的缓存就会保持活动状态.[/ OT]
因此,假设您的事件处理程序不直接将提交写入EventStore.相反,你有一个处理程序将它们插入到"队列"系统中,例如Windows Azure Queue,CouchDB,Memcache,AppFabric Cache等.重点是选择一个几乎没有块的系统来排队事件,但是这是持久的冗余内置(Memcache是我最不喜欢的冗余选项).您必须具有该冗余,如果服务器丢失,您仍然将该事件排队.
要最终从这个"排队事件"中提交,有几个选项.我喜欢Windows Azure的Queue模式,因为许多"工作者"可以不断地在队列中寻找工作.但它不一定是Windows Azure - 我使用在后台线程中运行的"队列"和"工作者角色"在本地代码中模仿Azure的队列模式.它非常好地扩展.
假设您有10名工作人员不断查看此"队列"中的任何用户更新事件(我通常会为每个事件类型编写一个工作人员角色,因此当您监控每种类型的统计信息时,可以更轻松地进行扩展).两个事件被插入到队列中,前两个工作者立即接收一个消息,并将它们(提交它们)直接插入到您的EventStore中 - 多线程,正如Jonathan在他的回答中提到的那样.您使用该模式的瓶颈将是您选择的任何数据库/事件库备份.假设您的EventStore正在使用MSSQL,瓶颈仍然是3,000 RPS.这很好,因为系统的构建是为了"赶上"当RPS下降到20000次爆发后的50 RPS.这是CQRS允许的自然模式:"最终一致性".
我说过CQRS模式还有其他横向扩展模式.如上所述,另一个是命令处理程序(或命令事件).这也是我所做的,特别是如果你有一个非常丰富的域域作为我的客户之一(每个命令上的几十个处理器密集型验证检查).在这种情况下,我实际上会将命令本身排队,然后由一些辅助角色在后台处理.这也为您提供了一个很好的扩展模式,因为现在您的整个后端,包括事件的EvetnStore提交,都可以进行线程化.
显然,缺点是您放弃了一些实时验证检查.我通过在构造我的域时通常将验证分为两类来解决这个问题.一个是域中的Ajax或实时"轻量级"验证(有点像Pre-Command检查).其他是硬故障验证检查,只在域中完成但不能用于实时检查.然后,您需要在Domain模型中进行代码失败.意思是,如果出现问题,总是编写出一条出路,通常以通知电子邮件的形式向用户发出错误信息.由于此排队命令不再阻止该用户,因此如果该命令失败,则需要通知他们.
您需要转到'后端'的验证检查将转到您的查询或"只读"数据库,riiiight?不要进入EventStore来检查一个独特的电子邮件地址.您将针对前端查询的高可用只读数据存储进行验证.哎呀,将一个CouchDB文档专门用作系统中所有电子邮件地址的列表,作为CQRS的Query部分.
CQRS只是建议......如果你真的需要实时检查繁重的验证方法,那么你可以围绕它建立一个Query(只读)存储,并加速验证 - 在PreCommand阶段,在它插入之前队列.很多灵活性.我甚至认为,验证诸如空用户名和空电子邮件之类的内容甚至不是域关注点,而是UI责任(卸载在域中进行实时验证的需要).我已经构建了一些项目,我在MVC/MVVM ViewModels上进行了非常丰富的UI验证.当然,我的Domain有非常严格的验证,以确保它在处理之前是有效的.但是,将平庸的输入验证检查或我称之为"轻量级"验证的内容移至ViewModel层,可以向最终用户提供近乎即时的反馈,而无需进入我的域.(有一些技巧可以保持与您的域同步).
总而言之,可能会考虑在提交之前排队这些事件.这与Jonathan在他的回答中提到的EventStore的多线程功能非常吻合.
| 归档时间: |
|
| 查看次数: |
3620 次 |
| 最近记录: |