MySQL主从复制,读写分离是网上常见的数据库架构。这种架构最让人诟病的地方就是在数据量大、并发量大的场景下,主从延迟会很严重。为什么主从延迟这么大?答:MySQL使用单线程重放RelayLog。如何优化和缩短回放时间?答:RelayLog的多线程并行回放可以缩短时间。RelayLog的多线程并行回放有什么问题?答:需要考虑如何划分RelayLog,让多个数据库实例、多个线程可以并行replayRelayLog,不会出现不一致。为什么会有不一致?答:如果RelayLog随机分配给不同的replay线程,假设RelayLog中有3条串行修改记录:updateaccountsetmoney=100whereuid=58;updateaccountsetmoney=150whereuid=58;updateaccountsetmoney=200whereuid=58;if单线程串行重放:可以保证所有从库的执行顺序和主库一致。画外音:***money会是200,如果多线程随机分配replays:多个replay线程同时执行这3条语句,不确定谁执行的最多,最终从库数据可能和主库不一样。画外音:多个奴隶库的钱可能是100、150、200,不确定。如何从多个库中分配和重放多个线程,是否也能得到一致的数据?答:同库的写操作使用同一个线程重放RelayLog;对不同库的写操作可以被多个Threads并发使用并发回放RelayLog。怎么做?答:设计一个hash算法,hash(db-name)%thread-num,然后在库名hash后对线程数进行建模,这个很容易搞定。对同一个库的写操作是同一个replay线程串行执行的。画外音:不同库上的回放是并行的,起到了提速的作用。这个解决方案有什么缺点?答:很多公司对MySQL都是“单库多表”。如果是这样的话,数据库还是只有一个,RelayLog的播放速度无法提升。启示:将“单库多表”的DB架构模式升级为“多库多表”的DB架构模式。画外音:对于数据量大、并发量大的互联网业务场景,“多库”模式还有很多其他优势,比如:非常方便的实例扩展:DBA可以很方便的将不同的库扩展到不同的实例;根据业务库隔离:业务解耦,业务隔离,减少耦合和相互影响;非常方便微服务拆分:方便每个服务都有自己的实例;“单库多表”场景,RelayLog的多线程并行replay还能怎么优化?答:即使只有一个数据库,事务也是在master数据库上并发执行的。既然可以在主库上并行执行,那么在从库上应该也可以并行执行吧?并行执行的事务被分成一组并分配一个编号。从库上这些事务的回放是可以并行执行的(主库上事务的执行已经进入prepare阶段,说明事务之间没有冲突,否则是不可能提交的),对,MySQL正是这样做的。解决方案:基于GTID的并行复制。从MySQL5.7开始,组提交的信息存储在GTID中。使用mysqlbinlog工具,可以看到群组提交的内部信息:从MySQL5.7开始,群组提交的信息存储在GTID中。Usingthemysqlbinlogtool,youcan看到组提交内部的信息:2018101423:52server_id58XXXGTIDlast_committed=0sequence_numer=12018101423:52server_id58XXXGTIDlast_committed=0sequence_numer=22018101423:52server_id58XXXGTIDlast_committed=0sequence_numer=32018101423:52server_id58XXXGTIDlast_committed=0sequence_numer=4和原来的日志相比,多了last_committed和sequence_number。什么是last_committed?答:是事务提交时最后提交的事务编号。如果它们的last_committed相同,说明它们在一个group中,可以并发回放执行。总结MySQL并行复制,缩短主从同步延迟的方法体现了一些架构思想:多线程是缩短执行时间的常用方法;画外音:比如很多crontabs可以使用多线程来拆分数据,并行执行。多线程并发调度任务时,必须保证幂等性:MySQL提供了“根据库幂等”和“根据commit_id幂等”两种方法,值得学习;画外音:比如群消息可以根据group_id进行幂等;用户消息可以根据user_id进行幂等。具体到MySQL主从同步延迟:mysql5.5:不支持并行复制,请尽快升级MySQL版本;mysql5.6:根据数据库并行复制,推荐使用“多库”架构;mysql5.7:根据GTID并行复制;【本文为专栏作者《58神剑》原创稿件,转载请联系原作者】点此阅读更多该作者好文
