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