数据库读写分离下的数据同步解决⽅案
⽬录
模拟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的策略解决的,这⾥就完美的解决了数据同步的问题。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论