当我们在设计数据库的时候,因为某些数据库中的数据量非常大,所以我们常常会选择进行数据库的切割,而针对数据量的这种情况,水平切割是一种常用的方式。
当使用水平切割时,我们通常会选择一个切割的维度,也就是选择一个patition key。我现在在做一个B2B的平台,每天会有大量的订单,作为店铺,会有一个ShopId,作为买家,会有一个UserId。
当我们查询店铺订单时,如果ShopId是我们的patition key,那查询就比较简单,但,这是如果我们想要查询买家的订单时,就需要查询多库。反之,如果UserId是patition key,那么买家查询方便了,但是店铺查询就麻烦了。
针对这种情况,我们就可以把同一个数据冗余两份,一个使用UserId分库,一个使用ShopId分库。
1)服务同步双写
如果我们需要数据冗余,那么可以在服务执行时,同时向两个数据库写入数据。
这种解决方案的优点就是:
当然,缺点也比较明显:
假设,我们需要提高处理的时间,那么我们可以使用下面这种解决方案,也是一种比较常用的解决方案。
2)服务异步双写
在这个方案里,通过引入了消息总线,和数据同步中心,让数据不再是通过服务来一次完成双写了。服务会异步向消息总线发出一个消息,然后通知数据同步中心来完成冗余数据的写入。
这个方案的优点我们已经说过了,就是:
当然,缺点也应运而生:
当然,沈剑还介绍了第三种方案,这种我没有试验过,说是能够实现冗余数据的解耦。
3)线下异步双写
这种方式类似于数据库的订阅同步一样,冗余数据的写入不再是通过服务来完成的了,而是通过一个线下的服务或者任务来完成的。
线下的服务或者任务通过读取日志记录来完成冗余数据的写入。
这种方式的优点:
缺点当然也是有的:
不管我们使用哪种方式,系统总有可能出现这样那样的异常,特别是在高并发的情况下。当这些异常出现时,我们就需要一个手段,来将不一致的数据最终实现一致。
因此,就必须完成:异步检测、异步修复。
沈剑在他的文章里介绍了三种方法,这里,我也就将这三种方法分享给大家。
1)线下全量数据扫描
线下启动一个离线的扫描工具,不停的扫描对比T1表和T2表的数据,一旦发现数据不一致,就进行修复。
这样做的优点:
缺点也非常明显:
有没有办法不用每次都扫描全部数据,只是有针对性的进行扫描呢?
2)线下增量数据扫描
我们修改线上的服务,让它在每次写入数据的时候,同时写入一个日志。然后,我们同样需要一个离线的扫描工具,只是这个扫描工具每次只是增量的扫描日志,如果发现日志数据不一致,就进行修复。
这样做以后:
但:
有没有一个能够实时监测的方式呢?
3)线上实时监测“消息对”法
这次,我们将服务进行改造,不在写入日志,改成向总线发送一个消息。在数据写入成功后,就发送一个消息,两次写入,就发送了两次消息。这时,我们不再需要一个扫描工具了,而是需要一个实时订阅消息的服务,不停的去收这些消息,当收到第一次写入成功的消息后一定时间内,没有收到第二次消息,就去检测数据的一致性,如果发现不一直,就进行修复。
这样做以后:
但也有缺点:
具体我们需要使用哪种解决方案,就需要根据我们实际的业务需求来判断了。技术本来就没有一个绝对的方法,我们需要考虑投入和产出,因此,不一定缺点明显的方案就不是好方案。