一、为什么使用主从
- 在业务复杂的系统中,有这么一个情景,有一句sql语句需要锁表,导致暂时不能使用读的服务,那么就很影响运行中的业务,使用主从复制,让主库负责写,从库负责读,这样,即使主库出现了锁表的情景,通过读从库也可以保证业务的正常运行。
- 做数据的热备,主库宕机后能够及时替换主库,保证业务可用性。
- 架构的扩展。业务量越来越大,I/O访问频率过高,单机无法满足,此时做多库的存储,降低磁盘I/O访问的频率,提高单个机器的I/O性能。
二、主从同步的原理
- 在master机器上的操作:当收到update、insert、delete指令后会将该指令写入bin-log中, 当master上的数据发生变化时,该事件变化会按照顺序写入bin-log中。当slave链接到master的时候,master机器会为slave开启binlog dump线程。当master的binlog发生变化的时候,bin-log dump线程会通知slave,并将相应的binlog内容发送给slave。
- 在slave机器上操作:当主从同步开启的时候,slave上会创建两个线程:I\O线程。该线程连接到master机器,master机器上的binlog dump 线程会将binlog的内容发送给该I\O线程。该I/O线程接收到binlog内容后,再将内容写入到本地的relay log;sql线程。该线程读取到I/O线程写入的ralay log。并且根据relay log 的内容对slave数据库做相应的操作。
三、主从同步延迟问题
MySQL数据库主从同步延迟原理mysql主从同步原理:由mysql主从同步的原理可知,mysql的主从复制都是单线程的操作,主库对所有DDL和DML产生binlog,binlog是顺序写,所以效率很高,slave的Slave_IO_Running线程到主库取日志,效率比较高,下一步,问题来了,slave的Slave_SQL_Running线程将主库的DDL和DML操作在slave实施。DML和DDL的IO操作是随即的,不是顺序的,成本高很多,还可能可slave上的其他查询产生lock争用,由于Slave_SQL_Running也是单线程的,所以一个DDL卡主了,需要执行10分钟,那么所有之后的DDL会等待这个DDL执行完才会继续执行,这就导致了延时。有朋友会问:“主库上那个相同的DDL也需要执行10分,为什么slave会延时?”,答案是master可以并发,Slave_SQL_Running线程却不可以。
MySQL数据库主从同步延迟是怎么产生的?当主库的TPS并发较高时,产生的DDL数量超过slave一个sql线程所能承受的范围,那么延时就产生了,当然还有就是可能与slave的大型query语句产生了锁等待。首要原因:数据库在业务上读写压力太大,CPU计算负荷大,网卡负荷大,硬盘随机IO太高次要原因:读写binlog带来的性能影响,网络传输延迟。
MySql数据库从库同步的延迟解决方案:
1、架构方面
- 业务的持久化层的实现采用分库架构,mysql服务可平行扩展,分散压力。
- 单个库读写分离,一主多从,主写从读,分散压力。这样从库压力比主库高,保护主库。
- 服务的基础架构在业务和mysql之间加入memcache或者redis的cache层。降低mysql的读压力。
- 不同业务的mysql物理上放在不同机器,分散压力。
- 使用比主库更好的硬件设备作为slave总结,mysql压力小,延迟自然会变小。
2、硬件方面:总结,硬件强劲,延迟自然会变小。
- 采用好服务器,比如4u比2u性能明显好,2u比1u性能明显好。
- 存储用ssd或者盘阵或者san,提升随机写的性能。
- 主从间保证处在同一个交换机下面,并且是万兆环境。
3、mysql主从同步配置优化
- sync_binlog在slave端设置为0
- –logs-slave-updates 从服务器从主服务器接收到的更新不记入它的二进制日志。
- 直接禁用slave端的binlog
- slave端,如果使用的存储引擎是innodb,innodb_flush_log_at_trx_commit =2
4、开启半同步复制
事务在主库写完binlog后需要从库返回一个已接受,才放回给客户端;5.5集成到mysql,以插件的形式存在,需要单独安装确保事务提交后binlog至少传输到一个从库。
5、并行复制:
目前最新的5.6,5.7,8.0 都是在SQL线程上实现了多线程,来提升slave的并发度。
以上方案只是尽可能的提高主从同步的速度,但是无法做到实时的一致,如果需要强一致可以采用如下方案:
1、强制走主库
2、使用cache:
- 先去mysql服务器上检查当前主从同步的延迟时间。
- 使用cache 记录,当前修改的操作,例如key=table:pk ,value=true。过期时间=主从同步的延迟时间。
- 当读数据的时候,先判断该key对应的cache是否存在,存在则从主库读,不存在则走从库读。