上一篇文章介绍了MySQL集群,以及主从复制、读写分离架构,这些架构解决了高并发业务中的很多问题,但是也存在很多的弊端。mysql 因为主从复制、读写分离,在读写时只能达到最终一致性,而无法达到实时一致性,所以理论是有延迟在所难免,在mysql 5.7 版本实现了多线程同步,缓解了延迟问题,但不可能完全实现实时同步。如何缩短延迟时间,将是本文的叙述重点。
一、如何判断是否延迟
个人认为,一般就会在这些步骤上浪费了时间,导致不同步:主节点更改数据后,主节点保存到二进制日志文件需要花时间。
从节点的I/O进程拉取二进制日志文件,并将其保存在从节点的中继日志文件中需要时间。
从节点的SQL进程对中继日志进行读取、解析、执行也需要花时间
主节点的并发请求较高时,产生的DDL数量超过从节点一个sql线程所能承受的范围,那么延时就产生了,当然还有就是可能与从节点的大型query语句产生了锁等待。
终其原因:数据库在业务上读写压力太大,CPU计算负荷大,读写二进制日志文件带来网络传输延迟。
在服务器上执行show slave status;可以看到很多同步的参数:
Master_Log_File: slave中的I/O线程当前正在读取的master中二进制日志文件的名称
Read_Master_Log_Pos: 在当前的二进制日志中,I/O线程已经读取的位置
Relay_Log_File: SQL线程当前正在读取和执行的中继日志文件的名称
Relay_Log_Pos: 在当前的中继日志中,SQL线程已读取和执行的位置
Relay_Master_Log_File: 由SQL线程执行的包含多数近期事件的master二进制日志文件的名称
Slave_IO_Running: I/O线程是否被启动并成功地连接到主服务器上
Slave_SQL_Running: SQL线程是否被启动
Seconds_Behind_Master: 从服务器SQL线程和从服务器I/O线程之间的时间差距(单位:s)
发现参数出现如下问题:
如果参数Seconds_Behind_Master不为0,就是延迟了,开发中这个数值可能会很大
如果参数Relay_Master_Log_File和Master_Log_File显示bin-log的编号相差很大,说明bin-log在从库上没有及时同步,所以近期执行的bin-log和当前IO线程所读的bin-log相差很大
如果mysql的从库数据目录下存在大量mysql-relay-log日志,该日志同步完成之后就会被系统自动删除,存在大量日志,说明主从同步延迟很厉害
二、如何解决MySQL主从复制的延迟
【A】架构方面应用程序中持久化层的实现尽量采用分库架构,mysql服务可以进行平行扩展,分散了压力。
在应用程序和mysql之间加入redis的cache层,可以降低从库的读压力。
建议从库数量3-5个为宜,如果一个主节点的从节点过多,要复制的从节点数量就多,就会增加复制延迟时间。
采用多线程复制方式。当然只有高版本mysql才支持多线程复制,主从复制单线程,如果主节点写操作并发太大,来不及传送到从节点就会导致延迟。
采用并行复制方式。
【B】硬件上从节点的硬件设备系统配置要比主节点好一些,从节点mysql读压力减小,延迟自然会变小。
【C】代码上最简单的在所有的insert和update之后,强制sleep几秒钟。这是非常粗鲁的方式,对于更新操作不是很高的中小型系统,此方式基本能解决问题。
不要写太多慢SQL语句。假如一条SQL语句执行时间是100秒,那么执行完毕到从节点上能查到数据也至少是100秒,通过查看慢查询日志找出执行时间长的查询语句或者大的事务,修改后分多次写入。
三、MySQL数据库其他问题及解决方案
1、mysql主从复制存在的问题:
● 主节点宕机后,数据可能丢失
● 主节点写操作高并发时,因为从节点只有一个SQL线程,复制过程会延时
2、解决方案:
● 半同步复制---解决数据丢失的问题
● 并行复制----解决从库复制延迟的问题