关于EventSourceing的胡思乱想

这是在看了lmax架构后的一些想法
我们知道对象是随时间而变化的,每个时段当中的对象就是对象本身在这个时段变化的快照,而domainEvent是作用在某个时段上的一个动作的记录,按照lmax的架构方式是除了要记录每个时段当中作用在对象上的domainEvent外,还需要定时的去为每个对象的某个时段做快照(可以加快回放速度)。举一例子
BankAccount『
存入3$Event
存入4$Event
取出3$Event
快照
存入5$Event

以上情况乍看似乎没有什么问题,在单线程处理无非就是顺序处理存入。但在多线程或者分布多进程情况下问题就变复杂化了,考虑的一个重要的问题是,假如由于网络或者机器故障,造成某台操作事件无法及时持久event或者是丢失event,event就造成了断裂。例如

BankAccount『
快照
机器1 存入3$Event
丢失 存入4$Event
机器2 取出3$Event
机器2 存入5$Event

那向lmax这种一天一快照的方式,就会造成信息断裂,这时候就算你取到了最近的快照,也无法回放到最新的对象状态。

2011年10月25日 14:32 "@gamex"的内容
假如由于网络或者机器故障,造成某台操作事件无法及时持久event或者是丢失event,event就造成了断裂 ...

这时的Event也是一种数据持久,一般是append到日志中,可以有保障措施。

2011年10月25日 20:23 "@banq"的内容
这时的Event也是一种数据持久,一般是append到日志中,可以有保障措施。 ...

恩,主要就是在event持久化丢失了,那就会出现断裂。可能我没有把我思考的场景描述清楚,我是基于共享对象的场景来思考的。
例如:
有个共享对象 叫 仓库
在分布式系统中 就会有这样的场景 机器1 和机器2 都会对这个对象进行操作。
我们知道lmax 的架构都是基于内存访问的,所以持久的动作也应该是存入缓存后再做的,如果在做持久的过程当中丢失了某些需要持久的event,这就会造成持久后的event出现断层现象。
如果要避免这个问题就变成是 所有产生的event都堆积在 仓库这个内存对象当中
仓库『
List events

因为事件是连续的,所以要保证事件的连续就有必要放到共享event队列当中
,并且要持久化这些events需要有专门的进程读取锁定进行持久,否则将造成并发问题,这种方式也制约了系统的吞吐速度。

如果把这种持久动作由各个机器自己去持久相应的那一部分的event,那持久的工作将分摊到各台机器上,处理速度也就加快了,但是同时也带来了一个问题,那就是,假设:机器1 操作了共享对象 并成功的更新了缓存 正准备持久化他操作的event 这时候网络断了,但是 机器2 的更新是基于 刚刚 机器1操作的基础之上去做的,他也成功的更新了缓存,也刚好要持久,但是他持久成功了。这时候你就会发现,持久到磁盘上的event少了一部分,对,就是 机器1 操作的那一部分,造成了断裂,在加上快照是基于一段时间一次的快照,这时候就会造成问题。

事件丢失不是逻辑问题,事件不在了,也就不存在某个事实了,在整个系统中,仍然是逻辑严谨的,只是某件事不被认为有发生过而已,我有点过按钮吗?没有。

关于事件队列,内存中肯定有一个的,如何没有如何确定发生顺序?

而且硬要说持久丢失,那么在队列到数据库过程中一样会丢失,后果也是一样的。

2011年10月26日 16:15 "@SpeedVan"的内容
事件丢失不是逻辑问题,事件不在了,也就不存在某个事实了,在整个系统中,仍然是逻辑严谨的,只是某件事不被认为有发生过而已,我有点过按钮吗?没有。

关于事件队列,内存中肯定有一个的,如何没有如何确定发生顺序?

而且硬要说持久丢失,那 ...


所以楼上的看法应该是趋向于我说的第一种方案,共享队列,有持久进程去读取共享队列做持久,在持久的时候还得避免读取共享对象的一些并发上需要考虑的问题,而且这种方式前提要保证持久的处理速度要足够快,否则将内存溢出,或者是限制队列的闸(但是这就造成了阻塞),这是很有趣的问题,希望大家想想有什么好的解决方法。

2011年10月26日 16:27 "@gamex"的内容
,而且这种方式前提要保证持久的处理速度要足够快,否则将内存溢出,或者是限制队列的闸(但是这就造成了阻塞) ...

Disruptor就是这样的队列,通过RingBuffer将持久化专门委托其他机器实现,比如通过MQ或JMS集群服务器来进行持久化,JMS服务器能够事务保证持久化完成,持久化失败JMS的队列中消息不会丢失,Durable在专门的数据库中,可以设置尝试次数,直至最终保证持久化完成。

2011年10月26日 16:27 "@gamex"的内容
所以楼上的看法应该是趋向于我说的第一种方案,共享队列,有持久进程去读取共享队列做持久,在持久的时候还得避免读取共享对象的一些并发上需要考虑的问题,而且这种方式前提要保证持久的处理速度要足够快,否则将内存溢出,或者是限制队列的闸(但是这就造成 ...

“处理足够快”这是不能确定的,各种因素影响。

代码上,我们可以确保每秒处理多少,然后稍作限制即可,又有分布式内存和云技术支撑;硬件上,以足够强的硬件来处理,或者设置路由防火墙限制等。

一般的应用和系统,以现在的普通的服务器足以。