redis上的数据本来就是被所有的应用服务器共享的呀。并发很正常,但是redis内部是单线程的,所以天生支持各种并发命令的处理。
[该贴被tangxuehua于2013-10-11 13:14修改过]
domain model 中触发事件改变模型状态,这时把触发的事件发送到持久化事件队列中(这里的队列可能是远程的持久化服务器,也可能是本地做持久化),然后持久化队列有一个线程对其进行持久化,并发送事件到事件处理段来更新读服务器(只有保存成功后才会发送)
做个比喻,比如我用手拿杯子,domain model 中的数据就好像,我大脑已经有这个想法了,而实际使用的数据库的数据就好比我收已经拿到杯子了
domain model 无需知道是否保存了,就算断电了,数据没有来得及保存,在做事件溯源的时候,就当做没有发生过这个一样
domain model 在内存中执行有多快你比我清楚,
[该贴被w438418754于2013-10-11 14:19修改过]
事件产生后,先放在一个持久化队列中,然后队列的消费者逐个持久化事件,如果成功,则发布事件到查询端,如果失败,则一直重试。
是否有IO,要看从什么角度去看了,如果只是从command handler来看,那是没IO的,因为只是产生事件,然后发送到队列就好。但是从整个一次完整处理过程来理解,持久化事件也算IO的呀,而且这里的IO也只是狭义的,实际上像发送到队列,难道不是IO吗?呵呵,从in-memory(如redis)取聚合跟难道不是IO吗?呵呵,访问网络就是IO。
到目前为止,我还没见过真正没有IO的纯in-memory系统。
而另一个线程去读取持久化队列中的数据(这里就和domain model不是同一个线程了,也就是异步了),取出数据化是要发送远程进行持久化,还是在本地都可以(当然远程的话就可以做同步服务器,如果是本地,那么死机后只能等待这台机器进行重启回溯事件)
从in-memory取聚合跟难道不是IO吗?
我认为不是,所以我才说是否有必要用redis,因为我的数据是放在应用服务器的内存中,而不是在redis里面,
如果要使用redis,那么redis存的也是query中的数据,也就是读的数据,其实和domain model 是没有关系的
2.任何消息必须持久化,否则一断电,就没消息了;
[该贴被tangxuehua于2013-10-11 15:40修改过]
所以我才觉得我和你的想法有些不同,你认为domain model产生事件后更改了状态就已经是这个已经发生的事情了(所以你必须在这里做同步的IO保存)
而我认为,我可以先更改domain model 异步做IO保存,保存成功后才是真正发生的事情 event handle 处理完成后才会看得到这件事,所以command handle 我是不会去通知用户任何我执行的command是否已经成功的消息,而是会在event handle上做通知
[该贴被w438418754于2013-10-11 16:23修改过]
这个问题也是我现在在考虑的一个问题之一,
假设现在有很多的数据,我们把他按照地区分片
现在有一台服务器处理北京这边的数据,这是如果你扩展一台服务器进来也处理北京这边的数据,你的数据放在redis中,你要如何处理同一条数据被两个服务器同时使用的情况呢,这就和并发的原理是一样的
[该贴被w438418754于2013-10-11 16:20修改过]
比如缓存服务器集群、消息队列中间件服务器集群、应用服务器集群、数据库集群;每一个集群都有各自的作用和扩展方法;
应用服务器如果无状态,那就可以随便增加或减少;
缓存服务器,如果用mongodb,那mongodb本身就自带在线扩容(增加sharding)的能力,redis不支持,但也有方案来做,比如用redis作者所说的presharding方式;
消息队列的集群,应该很常见,像rabbitmq,淘宝的metaq都支持;
数据库集群,mysql的案例很多吧。
如果你的应用服务器里有状态,如一些消息暂存在里面;那要是这台机器挂了,谁来处理这些消息呢?相反,如果是用专业的消息队列服务器来统一存储各种消息,那通过像zookeep等分布式协调服务,可以判断出,哪个消费者挂了,然后就会把本该由该消费者的消息自动传递给其他消费者,从而保证系统一直可用,所有消息都能有服务器处理。
[该贴被tangxuehua于2013-10-11 16:38修改过]
"的内容
而我认为,我可以先更改domain model 异步做IO保存,保存成功后才是真正发生的事 ...
我没有认为聚合跟状态一更改就认为事情已经发生了哦!!
我只认为事件保存了才认为事情发生了,所以我才会在事件持久化成功后才更新in-memory(redis)的。
"的内容
对于,这一点,我在事件持久化完成后,我会调用command的一个会掉函数,告诉用户某个command在command side处理完了。
比如缓存服务器集群、消息队列中间件服务器集群、应用服务器集群、数据库集群;每一个集群都有各自的作用和扩展方法;
应用服务器如果无状态,那就可以随便增加或减少;
缓存服务器,如果用mongodb,那mongodb本身就自带在线扩容(增加sharding)的能力,redis不支持,但也有方案来做,比如用redis作者所说的presharding方式;
消息队列的集群,应该很常见,像rabbitmq,淘宝的metaq都支持;
数据库集群,mysql的案例很多吧。
如果你的应用服务器里有状态,如一些消息暂存在里面;那要是这台机器挂了,谁来处理这些消息呢?相反,如果是用专业的消息队列服务器来统一存储各种消息,那通过像zookeep等分布式协调服务,可以判断出,哪个消费者挂了,然后就会把本该由该消费者的消息自动传递给其他消费者,从而保证系统一直可用,所有消息都能有服务器处理。
你这里的我可以理解,但是你这里其实并不是解决分片问题,而是解决失败后故障转移的问题,分片还是无法动态进行扩展的~~
当然如果只是失败后故障转移,我想lmax中也提到了,他是使用多个服务器同时处理的方式(只是他这种方式我也是有些疑问的,不过他这样就可以实现数据存放在应用服务器的问题了)
我最大的疑惑是,他的input events是什么呢?
LMAX是先持久化input events,然后再到内存处理。
然后内存如果挂了或要重启,那可以通过input events来还原。这我我觉得不是event sourcing了,而是command sourcing了。你觉得呢?这种做法就和redis的aof一样了,存储的都是cmd,然后redis重启时,读取日志中的所有cmd,然后再重新执行一遍。
而event sourcing,重演的时候是根据domain产生的domain event.也就是基于“事实”进行重演。
所以LMAX,他的重演,我觉得很复杂了,因为一个command要重新执行,涉及到的东西就很多了,还有很多外部系统的交互呢。