数据库主从一致性问题

背景

    上一篇我写了为了处理高并发带来的数据库压力问题,引出了数据库读写分离技术。其思想总结为:一主多从、读写分离,冗余多个读库。然而存在一个明显的问题就是:从数据库同步数据的同时可能给业务方返回的是旧的数据,即所谓的脏读现象。如图所示:

《数据库主从一致性问题》 image.png

【1】系统先对Master-DB进行了一个写操作,写主库;
【2】很短的时间内并发进行了一个读操作,读从库,此时主从同步没有完成,故读取到了一个旧数据;
【3】主从同步完成。
    为了解决主从同步一致性导致读取旧数据的问题,本文主要提出四种解决方案,仅供参考。

解决方案

方案一、读写都在主库

    显然,这是一种最简单的方法,读写全落在主库上,必然不会带来不一致问题。如图所示:
《数据库主从一致性问题》 image.png

方案二、semi-sync(半同步复制)

    之所以会读取到旧数据,关键在于主从同步需要一个时间段,而读取请求可能刚好就发生在同步阶段。为了读取到最新的数据,需要等主从同步完成之后,主库上的写请求再返回。示意图如图所示:
《数据库主从一致性问题》 image.png

【1】系统先对DB-master进行了一个写操作,写主库;
【2】等主从同步完成,写主库的请求才返回;
【3】读从库,读到最新的数据(如果读请求先完成,写请求后完成,读取到的是“当时”最新的数据)。
    显然带来的后果就是主库的写请求时延会增加,吞吐量会降低。

方案三、数据库中间件

    借助中间件的路由作用,对服务层的读写请求进行分发,从而避免出现不一致问题。示意图如图所示:
《数据库主从一致性问题》 image.png

【1】所有的读写都走数据库中间件,通常情况下,写请求路由到主库,读请求路由到从库;
【2】记录所有路由到主库的key,在经验主从同步时间窗口内(假设是500ms),如果有读请求访问中间件,此时有可能从库还是旧数据,就把这个key上的读请求路由到主库;
【3】经验主从同步时间过完后,对应key的读请求继续路由到从库
    中间件带来的好处就是能保证数据的绝对一致性,但同时也带来成本上升的问题。

方案四、利用缓存

    原理同方案三类似,当写请求发生时,
《数据库主从一致性问题》 image.png

【1】将某个库上的某个key要发生写操作,记录在cache里,并设置“经验主从同步时间”的cache超时时间;
【2】修改数据库

而读取请求发生的时候:
《数据库主从一致性问题》 image.png

从图中可以看出:

1)先到cache里查看,对应库的对应key有没有相关数据;

2)如果cache hit,有相关数据,说明这个key上刚发生过写操作,此时需要将请求路由到主库读最新的数据;
3)如果cache miss,说明这个key上近期没有发生过写操作,此时将请求路由到从库,继续读写分离。
    显然,利用缓存,减少了中间件带来的成本问题,但多了一个Cache组件,并且读写数据库多了一步Cache操作,操作相对其他稍较繁琐。

    原文作者:Ferrari1001
    原文地址: https://www.jianshu.com/p/5387bf6b6dec
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞