# 读写分离
当一个公司业务不断扩展,用户量大量增加,原来使用的数据库很可能就撑不住了。那么可以
- Scale-in,扩充硬件的性能,但是很可能用户量继续增长,增加的性能很快就吃光了。
- 读写分离:数据库撑不住了,无非就是读写量过大,特别是有一些复杂的查询比如最近24小时最热门的产品等。需要很复杂的SQL语句,运行起来当然是慢。
但是为了读写分离,需要把数据库拆分为master库和Slave库,
市面上主要的关系数据库都支持**数据复制功能**,所以可以把一个数据库拆分为Master和Slave两种角色,**写操作**在主上,由Master服务器向其他Slave服务器进行同步。
而**读操作**以及数据分析等离线操作都在Slave服务器上进行。
我们知道互联网的很多应用都是读的,这样有多个Slave可以**负载分担**一下,又可以保证数据的可用性和正确性。
![image.png](http://upload-images.jianshu.io/upload_images/1323506-7371a2116b037768.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
但是相应的原有的**应用代码**也需要修改,必须改为写数据用master库,读数据的时候使用slave库,就相当于重写了。
# 复杂查询
但是就算重写了代码,发现性能还是无法得到明显的提升,原因仍然是使用了太多复杂的查询,比如说有很多表在联接,在[数据库(四),数据库组成部分](http://www.cnblogs.com/dy2903/p/8438206.html)里面我们都说过,联接非常消耗性能。
那么我们可不可以**单独用一张表**来存放过去24小时的热门产品啊,这样只需要使用简单的SQL就能搞定。
也就是说,一套单一的数据库表对报表、搜索、事务等不同的行为是不适当的。
现在的表是为了**新增、修改数据**而设计的,对复杂查询不适合。
但是我们还需要考虑这个查询库如何更新的问题,还就是可能不是实时更新,我们能否忍受这种延迟的问题。
# CQRS
能否忍受延迟的问题需要从业务上来看,比如过去24小时热门的极品,一点点过时的信息没有太大的影响,只要求最终一致即可。
我们可以使用CQRS(Command Query Responsibility Segregation),也就是增删改的**命令与查询责任分离**。
![image.png](http://upload-images.jianshu.io/upload_images/1323506-f7e4c298714c8f06.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
在CQRS中,强调的是读(Query)写(Command)分离,因为用户读到的数据通常是过时的,那么为什么还需要从数据库读一遍呢,可以直接建立一个读数据源。可以是Cache,可以是XML、JSON等。
那之前提到的怎么**更新**的问题怎么解决?可以使用Event,也就是事件,比如某个产品卖出去了,可以发布一个事件,修改原有的Read Model。
这样就通过事件机制把同步变成了异步。
最后,这种方法最好只在**复杂查询**中用,原来的简单查询依然在关系型数据库里面取。为什么呢?因为引入一种新的技术需要付出代价,比如同步变异步了,还需要事件机制,我们不能只看到新技术的优点,而看不到缺点了。
![image.png](http://upload-images.jianshu.io/upload_images/1323506-c9226a8db16cfc9b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
# 主要参考
[从读写分离到CQRS,张大胖是如何解决性能问题的?](http://mp.weixin.qq.com/s?__biz=MzAxOTc0NzExNg==&mid=2665513844&idx=1&sn=82a70f987fdf56a47debffc995addfec&chksm=80d67b37b7a1f221187a97af92ec7fed5b31d1fae3831d7b59b28c34935afb7765cb1b7a4fb0&scene=21#wechat_redirect)