MySQL实战宝典 高可用架构篇 16 读写分离设计:复制延迟?
很多同学发现,自己的主从复制会存在主从数据延迟的问题,甚至会导致读写分离架构设计在业务层出现较为严重的问题,比如迟迟无法读取到主库已经插入的数据。但这可能并不是MySQL复制的问题,而是你的业务没有根据MySQL复制的特点进行设计
逻辑日志的优缺点
上一节,了解到MySQL复制基于的二进制日志是一种逻辑日志,其写入的是每个事务中已变更的每条记录的前像和后像。有了每条记录的变化内容,用户可以方便的分析MySQL的二进制日志内容,准确地将MySQL中的数据同步到异构的数据平台,如HBase、ES、Hive等大数据平台。
逻辑日志简单易懂,方便数据之间的同步,但它的缺点是:事务不能太大,否则会导致二进制日志非常大,一个大事务的提交会非常慢。假设有个DELETE删除操作,删除当月数据,由于数据量有可能存在1亿条记录,可能会产生10G的二进制日志,则这条SQL在提交时需要等待10G的二进制日志写入磁盘,如果二进制日志磁盘每秒写入速度为100M/s,至少需要等待100s才能完成这个事务的提交。
所以在MySQL中,一定要对大事务特别对待:
- 设计时,把DELETE删除操作转换为DROP TABLE/PARTITION,主要是在设计时把流水表或日志类的表按时间分表或分区,这样在删除时,二进制日志内容就是一条DROP TABLE/PARTITION的SQL,写入速度就非常快。
- 业务设计时,把大事务拆成小事务,可以进行多线程的并发操作,进一步提升删除效率,比如每次只删除1000条的小操作。
DELETE FROM ...
WHERE time between ... and ...
LIMIT 1000;
MySQL数据库中,大事务除了会导致提价速度变慢,还会导致主从复制的延迟。
试想一下,一个大事务在主服务器上运行了30分钟,那么在从服务器上也需要运行30分钟。在从机回放这个大事务的过程中,主从服务器之间的数据就产生了延迟;产生大事务的另一个可能就是主服务器上没有创建索引,导致一个简单的SQL操作时间变得非常长,这样在从机回放时,也会需要很长时间从而导致主从复制的延迟。
除了把大事务拆分成小事务,可以避免主从复制延迟,还可以设置复制回放相关的配置参数,接下来我们就来分析一下主从复制延迟的优化。
主从复制延迟优化
要彻底避免MySQL主从复制延迟,数据库版本至少要升级到5.7,因为之前的版本从机回放二进制日志都是单线程的(5.6时基于库级别的单线程)。
从MySQL 5.7版本开始,MySQL支持了从机多线程回放二进制日志的方式,通常把它叫做“并行复制”,官方文档中称为“Multi-Threaded Slave(MTS)”。
MySQL的从机并行复制有两种模式:
COMMIT ORDER
COMMIT ORDER模式的从机并行复制,从机完全根据主服务器的并行度进行回放,理论上来说,主从延迟极小,但如果主服务器上并行度非常小,事务并不小,比如单线程每次插入100条记录,则从机单线程回放,也会存在一些复制延迟的情况。
WRITESET
WRITESET模式是基于每个事务并行,如果事务间更新的记录不冲突,就可以并行,还是以“单线程每次插入100条记录”为例,如果插入的记录没有冲突,比如唯一索引冲突,那么虽然主机是单线程,但从机可以是多线程并行回放。所以在WRITESET模式下,主从复制几乎没有延迟,那么要启用WRITESET模式,你需要做这样的配置:
binlog_transaction_dependency_tracking = WRITESET
transaction_write_set_extraction = XXHASH64
slave-parallel-type = LOGICAL_CLOCK
slave-parallel-workers = 16
因为主从复制延迟会影响到后续高可用的切换,以及读写分离的架构设计,所以在真实的业务中,你要对主从复制延迟进行监控。
主从复制延迟监控
Seconds_Behind_Master
很多同学或许知道使用命令SHOW SLAVE STATUS
,其中的Seconds_Behind_Master可以查看复制延迟,如:
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.18.0.2
Master_User: root
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000008
Read_Master_Log_Pos: 2032
Relay_Log_File: edu-mysql-relay-bin.000010
Relay_Log_Pos: 2207
Relay_Master_Log_File: mysql-bin.000008
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...
Seconds_Behind_Master: 0
...
1 row in set, 1 warning (0.01 sec)
但是Seconds_Behind_Master并不准确,用于严格判断主从延迟的问题并不合适,有以下3个原因:
- 它的计算规则是当前回访二进制时间减去二进制日志的时间,如果I/O线程有延迟,那么Seconds_Behind_Master为0,但这时可能已经落后很久了,比如存在有大事务的情况下;
- 对于级联复制,最下游的从服务器延迟是不准确的,因为它只表示和上一级主服务器之间的延迟;
- 若主从时区不一样,那么Seconds_Behind_Master也不准确
总的来说,线上业务通过Seconds_Behind_Master值观察主从复制延迟并不准确,需要额外引入一张表,才能真正监控主从复制的延迟情况。
心跳表
想要实时准确的监控主从复制延迟,可以在主服务器上引入一张心跳表heartbeat,用于定时更新时间(比如每3秒一次)。与主从复制机制,主机写入的时间会被复制到从机,这时对于主要主从复制延迟的判断可以根据如下规则:
这可以很好的解决上述Seconds_Behind_Master值存在的问题。表heartbeat和定时更新时间可以根据类似的设计:
CREATE TABLE heartbeat (
server_id VARCHAR(36) PRIMARY KEY,
ts TIMESTAMP(6) NOT NULL
);
REPLACE INTO heartbeat VALUES (@@server_id,NOW())
上面的设计中,创建了一张表heartbeat,用于记录当前时间。
REPLACE语句用于定期更新当前时间,并存入到表heartbeat,表heartbeat在正常情况下只有一条记录。定期执行REPLACE语句可以使用定期的脚本调度程序,也可以使用MySQL自带的事件调度器(Event Scheduler),如:
CREATE EVENT e_heartbeat
ON SCHEDULE
EVERY 3 SECOND
DO
BEGIN
REPALCE INTO heartbeat VALUES (@@server_id,NOW())
END
根据上述2个小节,你已经能正确配置并行复制,并对复制延迟进行监控,这时可以设计一个读写分离的业务架构了
读写分离设计
读写分离设计是指:把对数据库的读写请求分不到不同的数据库服务器上。对于写入操作只能请求主服务器,而对读操作则可以将读取请求分布到不同的从服务器上。这样可以有效的降低主服务器的负载,提升从服务器资源利用率,从而进一步提升整体业务的性能。下面这张图显示了一种常见的业务读写分离的架构设计:
![读写分离] Cgp9HWDDKOGAbQ-bAABk4et1jJc226.png上图引入了Load Balance负载均衡的组件,这样Server对于数据的请求不用关心后面有多少个从机,对于业务来说也就是透明的,只需要访问Load Balance服务器的ID或域名就可以。
通过配置Load Balance服务,还能降读取请求平均或按照权重平均分布到不同的从服务器。这可以根据架构的需要做灵活的设计。
请牢记:读写分离设计的前提是从机不能落后主机太多,最好是能准时数据同步,无比一定要开始并行复制,并确保线上已经将大事务拆成小事务。
当然,若是一些报表类的查询,只要不影响最终结果,业务是能够容忍一些延迟的。但无论如何,请一定要在线上数据库环境中做好主从复制延迟的监控。
如果真的由于一些不可预知的情况发生,比如一个初级的DBA在主机上做了一个大事务操作,导致主从延迟发生,那么怎么做好读写分离设计的兜底呢?
读写分离架构在Load Balance服务器,可以配置较小比例的读取请求访问主机,如上图所示的1%,其余三台从服务器各自承担33%的读取请求。如果发生严重的主从复制延迟情况,可以设置下面从机权重为0,将主机权重设置为100%,这样就不会因为数据延迟,导致业务的影响了。
总结
本小节是基于上一节的内容的延伸,学习怎么解决主从服务可能发生的数据延迟问题,以及基于主从复制搭建一个读写分离结构,总的来说:
- MySQL二进制日志是一种逻辑日志,便于将数据同步到异构的数据平台
- 逻辑日志在事务提交时才写入,若存在大事务,则提交速度很慢,也会影响主从数据库之间的同步
- 在MySQL中务必将大事务拆分成小事务出来,这样才能避免主从数据延迟问题
- 通过配置MTS并行复制机制,可以进一步缩短主从数据延迟的问题,推荐使用MySQL 5.7以上版本,并配置成基于WRITESET的复制
- 主从复制延迟监控不能依赖Seconds_Behind_Master的值,最好的方法是额外配置一张心跳表
- 读写分离是一种架构上常见的方法,你一定要掌握,并做好读写分离架构失效情况下的兜底设计。