数据库读写分离下的数据同步解决方案

目录

1、读写分离解决了什么问题

2、读写分离与业务的架构

3、实际案例

4、解决方案


模拟binlog协议   延迟消费

 

1、读写分离解决了什么问题

       读写分离其实将数据库分离一个主库,多个从库,主从库之前通过某种机制(如binlog)进行数据同步,这是一种常见的数据库架构。在大多数互联网业种中,都是读多写少的业务,为了能够线性提升数据库的读性能,消除读写冲突并提升写的性能,一般可以采用读写分离的思想(当然还有其他解决方案:如复本集,缓存策略等等)。其实,用一句话来概括,读写分离基本原理就是将数据库的读写操作路由到不同的节点上,用来解决数据库的读性能瓶颈的。

2、读写分离与业务的架构

      在实际的项目中,读写分离与业务架构如下图所示。应用程序A通过执行事件(事务执行)成功后,发送消息队列通知应用程序C。应用程序C通过上游应用程序B获取数据。其中,应用程序A主要是写操作,连接master库,应用程序B主要是读操作连接slave库。master与slave通过某种机制进行数据同步。

       

    在这样一个简单的架构中,其实存在一个主要的问题,也是本文将着重探讨及解决的——应用程序B获取的数据可能是还未同步到从库的数据。

3、实际案例

    下面首先我结合案例介绍一下遇到的问题(数据库为innodb)。

    在**年初,有商家反馈**写操作后数据没有生效,实际的业务视图与上面的保持一致。其实原因现在来看已经很清楚了,但定位问题还是花费了几天,首先排查代码(有事务,并且通过TSM的afterCommit后再发送的消息队列,当然缓存的设置也是没有问题【如先del还是直接set】,这里就不表了),单中代码层面上是没有问题的,接着就从系统级别排查问题,并且对比数据库的写时间,调用从库获取的数据等日志综合定位——由数据同步延迟导致的。

      于主库来说,事务成功提交后,该数据一定对另一个事务可见(本文所讨论的数据库在没有特殊说明下,都指Innodb, 隔离级别为RR)。接口则是从从库获取数据。这里简单梳理下一条数据写入数据库的整个过程:对于update/insert/delete等操作,依次会产生undo log, redo log,在2PC下,当redolog prepare(是否落盘则根据innodb_flush_log_at_trx_commit控制)ok后,接着进行binlog(是否落盘则根据sync_binlog控制)的commit及redo log的commit; 当然在整个过程中,会读取相关的page到内存中进行更改,也即所谓的dirty page。当事务commit后,其实仅仅代表日志已经落盘,最终内存中的dirty page什么时候刷新到磁盘,这则是checkpoint的事儿了,其间会经历checksum,double write等等,这不是本文的重点,点到为止。 先保证redolog/binlog/undolog成功,这就是有名的WAL(为啥要WAL呢?redolog与binlog共存的意义何在?留个思考题吧)。整个过程,主库就完成了数据的写入;

       接着mysql就利用binlog进行数据同步,从库上一般会有IO线程,从主库中获取binlog日志存放在从库的内存中,即relay log,假设消耗时间为T1;然后利用sql线程进行回放数据,假设消耗时间为T2。目前线上,我们使用的mysql版本号为5.5(貌似在5.6的哪个版本是支持binlog的多线程复制,不过在5.5一定是单线程),binlog的复制方式是RBR(另外两种是SBR,MBR),从库使用的数据库存储引擎也是Innodb。假设业务上的时间(如发送mq,下游接收mq并调用接口)的时间为T3。很显示,当T3<T1+T2时,是不是意味着获取到的数据是上一次发布的数据呢?没错,下游获取数据没有更新就是这种情况导致的。这是当时线上获取的binlog同步到从库相对主库的延迟监控图,从图中可以看到,在某些时刻,主从同步最大有甚至有1s,此时主库的CPU消耗也是挺高的。

  

4、解决方案

      解决数制库读写分离下的数据同步思路其实相当简单——确保从库与主库的数据已经同步即可。如轮询从库数据(当然这个不是很优雅的解决方案),订阅从库的binlog日志(当生成binlog日志时)。接下来我们对后面一种方案进行简单的描述。

      目前,已经有很多成熟的工具来模拟从库获取数据库实例的binlog日志并对其解析,如阿里的canal,京东的binlake等。他们可以按需过滤部分的binlog日志(如某个table的某些操作),然后发送到消息队列中,应用程序程序订阅该消息后,然后进行业务逻辑处理(如通过已经有工具解析binlog日志,然后进行业务逻辑处理,并按需发送消息给下游)。这里虽然解决了读写分离因同步延迟导致的业务不正确的问题,但并不完美,因此并没有彻底解决该问题。具体原因如下:

     在2PC中,分为两个阶段:第一阶段是redo/undo log的sync落盘, 第二阶段包含两步:前一步骤为binlog的sync操作,当这个阶段完成时,binlog已经写入,此时就可以发送给订阅者然后进行消费,后一步骤是commit操作[如释放mutex锁],只有commit全部完成之后,其他事务才能查询binlog日志所对应的事务产生的数据变更(这里有可能网友有疑问,如果binlog落盘了数据库崩溃了,能否恢复数据?答案当然是能够的)。因此在实际的项目中,我是通过延迟消费500ms的策略解决的,这里就完美的解决了数据同步的问题。

     binog日志落盘到整个2PC提交结束这个时间差可能导致数据不同步,要特别感谢该博文:https://www.jiqizhixin.com/articles/2018-12-05-14, 在这里我才意识到可能存在这个问题,并在实际的项目中与小伙伴一起验证,通过连接7天的数据验证,终于发现了一条这样的数据。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值