CQRS实际是一个很简单的概念,读写分离,这是架构首次重视读写分离,以往我们都没有这个意识,比如使用Spring+Hibernate,写命令和读操作被服务统管在一起,其实从REST的POST/GET分离的概念我们可能也体会到了Web系统的一个本质。
如果我们从读写分离关注这个新角度重新审视我们系统,发现优化余地很大,比如Tomcat等Web容器总是会自动产生JSESSIONID,依附在URL或Cookie中,这两者都很违背互联网原则,因为在互联网环境中,CDN是必须的,但是本来是一个内容不怎么更新的文章因为有了JSESSIONID,被CDN等会认为是动态页面而不缓存,CDN没有起作用,而我们关注的是要让CDN能分清楚经常更新和不太经常更新的。要做到这点,必须从读写分离这个角度将系统的所有读页面去除Cookie,只有用户登录后(可能会写操作)才会有Cookie。
当然,从读写分离角度还可以很优雅解决负载问题,因为大部分系统写操作负载不大,那么分两台服务器分别负责读和写,对读的服务器我们就可以尽情优化,而不担心用户Session问题,去除了服务器HttpSession粘附,使用负载平衡效率更高,因为负载平衡如果发现一个URL后面有JSESSIONID,会发到原来服务器,这样负载平衡的粒度只能划分到Session,而读写分离后,没有Session,负载平衡的粒度可以划分到每个Request
来自文章破除CQRS神秘系统地谈了这个问题,作者看到有些CQRS不必要地走弯路,搞复杂了,特别写这篇文章澄清一下。
1.误区一:CQRS = Event Sourcing,反之亦然。
Event sourcing一般比较合适CQRS, 因为它在模型的最终一致性方面提出了一个直接的构建和更新读存储的方式。同时能够更好聚合那些侧重行为的系统或基于任务驱动UI系统。
但是 event sourcing是完全和CQRS是相互垂直的,只是互相合适对方,CQRS并不一定需要event sourcing, 而实现event sourcing并不意味着我们在实现CQRS.
作者认为event sourcing对于他来说门槛很高。
误区2:CQRS需要一个最终一致的读存储
这其实不必,你可以采取即时一致读取(关系数据库),也就是说,当你的命令成功执行后,你的读存储能够立即更新。(最终一致和即时一致是的区别见CAP原理和BASE思想)
对于很多遗留系统,切换到最终一致性会导致系统失火,特别是你急于切入异步模型。相反,你可以逐步过渡,比如哪些页面用户不希望立即看到结果,将之实现异步(如密码已经发到你信箱等功能)。