本文为您介绍PolarDB MySQL版基于物理复制架构,如何提升半同步复制(Semisynchronous replication,简称Semi-sync)的效率,降低对主库的性能影响。主要内容包括背景介绍、功能介绍、注意事项、性能测试、常见问题等。
背景介绍
MySQL官方默认支持基于Binlog的半同步复制功能。在此模式下,主库在事务提交前需要等待从库确认已接收并同步了该事务所产生的Binlog日志。然而,这种同步机制会引入额外的延迟,从而对主库的写入性能产生一定的影响。
PolarDB MySQL版基于物理复制架构,通过高效的Redo日志在主备可用区之间进行同步,这使得半同步复制的效率显著提高,从而大幅降低主库的性能损失。在高并发负载情况下,与异步模式相比性能降低约为10%。
相较于MySQL官方基于Binlog的半同步机制,PolarDB MySQL版基于物理复制(Redo 流)的半同步机制具备更高的同步效率。在事务执行过程中,Redo日志的产生和同步链路就已经产生并实时传输到备可用区,因此,在事务提交时,仅需等待对应的这条Redo日志成功同步至备可用区。而传统的Binlog半同步机制则在事务提交时才生成完整的Binlog,此过程需要等到所有的Binlog日志同步完成后,才能向客户端返回操作成功的信息。
功能介绍
PolarDB MySQL版半同步复制的逻辑相对容易理解:借助物理复制架构,通过Redo日志来完成主备可用区之间的同步工作。对于业务下发的写入请求,会在主可用区完成数据修改时产生Redo日志,并通过物理复制链路同步Redo信息。在主可用区返回业务执行成功前,写请求对应的写事务需要等待备可用区确认收到对应的Redo日志。
提交前最长等待时间
考虑到备可用区可能因某些非自然因素导致主可用区的写入请求迟迟无法提交,因此,在内核层面会限制写事务的提交前的最长等待时间,如果超过了设定时间仍未收到备可用区的同步确认信息,主可用区将会自动提交已经超时的写入事务。
自适应机制
在极端情况下,备可用区可能无法及时向主可用区确认同步信息,导致主可用区的每一条写入请求都需要等待超时后才能提交,造成性能损失。为了避免这一问题,半同步复制(Semi-sync)引入自适应机制,动态监测主备可用区之间的网络通信情况,在发生超时的情况较为频繁时,会自动切换至异步模式,保证主可用区的写入不受Semi-sync的影响,同时在监测到主备可用区的同步情况恢复正常时,系统将自动重新开启Semi-sync模式。
注意事项
PolarDB MySQL版基于物理复制的半同步模式能极大提升跨可用区切换的数据一致性,具体开启流程请参见跨可用区自动切换。
目前仅PolarDB MySQL企业版,数据库引擎为8.0.1且内核小版本为8.0.1.35.1及以上的集群支持跨可用区数据复制的半同步模式。
PolarDB MySQL企业版,数据库引擎为8.0.1且内核小版本为 8.0.1.1.40及以上,新增半同步模式自适应机制。
PolarDB MySQL企业版,数据库引擎为8.0.1且内核小版本为8.0.1.1.44.2及以上,开放参数
innodb_polar_wait_slave_reply_max_time
用于控制开启半同步复制后,主可用区写事务在提交前默认最长等待时间,默认值500ms。
RPO和RTO
在异步场景下,跨可用区自动切换功能是有损切换(绝大部分情况下RPO<100ms,最差情况下RPO<60s),使用前请进行评估。
在半同步场景下,开启后性能衰退约10%,默认事务提交等待时间是500ms,超过500ms就会退化为异步,不再等待同步至备可用区。无退化情况下RPO=0。
异步和半同步场景下的RTO<30s。
性能测试
本文中的测试结果仅反映当前版本的表现,并不代表最新版本的运行结果。
测试方式:同一个规格的集群,对比PolarDB MySQL版开启异步模式、PolarDB MySQL版半同步模式和MySQL半同步模式的QPS性能差异。
测试工具:Sysbench下的oltp_write_only。
测试规格:16C 64 GB。
测试版本:PolarDB MySQL版8.0.1版本且内核小版本为8.0.1.35.1(可能与最新版本存在微小差异)。
数据量:10张数据表,每张表1000万行数据。
可以看到开启Semi-sync在高并发场景下的性能衰减约为10%,并且在任何并发压力下,PolarDB MySQL版基于Redo日志方式的半同步复制的性能都要优于MySQL基于Binlog方式的半同步。
常见问题
Q1:为什么开启Semi-sync功能后,性能下降不止10%?
A1:在高并发的情况下,性能衰减最佳状态约为10%,原因在于Redo通过batch的方式进行同步处理,从而有效降低了因网络延迟带来的开销。在低并发场景下batch带来性能提升不够显著,因此可能会导致性能下降的情况较为严重,仅单线程写入时,无法对Redo IO进行batch操作,因为开启半同步复制后,增加了一个网络往返延迟从而明显降低了性能。
Q2:为什么控制台看不到innodb_polar_wait_slave_reply_max_time
这个参数?我该如何调整这个参数到一个合适的值?
A2:仅PolarDB MySQL企业版,数据库引擎为8.0.1且内核小版本为8.0.1.1.44.2及以上集群支持修改此参数,若控制台无法搜索到参数,请先确认集群版本是否满足要求,若不满足可以进行版本升级。
关于该参数的设置:通常情况下,您无需手动修改,默认值是500ms。如存在特殊需求,例如希望事务必须等到备可用区同步后再提交,可以适当增加此参数值,但绝大多数情况下默认的500ms已经足够。如果希望限制事务的等待时间,可以适当降低该参数值。但需要注意的是,当设置的值非常小,例如0或1ms时(通常主备可用区的网络延迟维持在1ms以内,而半同步复制同步至少需要等待一次网络来回),这可能导致半同步模式退化为异步模式,因此,修改此参数时需要结合实际情况进行考虑。
Q3:Semi-sync的自适应机制,什么情况下生效?我可以打开Semi-sync但是关闭自适应机制吗?
A3:目前Semi-sync开启后,系统会默认采用自适应机制,动态监听主备可用区同步状态,并实时进行调整。目前暂不支持单独关闭自适应机制。如果希望Semi-sync功能保持生效状态,可innodb_polar_wait_slave_reply_max_time
调整为一个较大的值,自适应机制将依赖于此参数值来判断当前的超时情况。
Q4:Semi-sync不发生退化时的RPO=0,这里说的退化和自适应机制动态关闭是一回事么?
A4:二者并不相同。不发生退化是指任何事务在提交前,必须确保备可用区已经同步了相应的Redo信息,在此情况下,可以严格保证RPO=0,但是自适应机制监测的粒度并非事务,而是网络包的通信,当自适应机制动态关闭Semi-sync时,通常已经发生了多个事务因同步超时而被提交的情况。换句话说,即使开启了Semi-sync且并没有被自适应机制关闭,此时RPO并不严格等于0,可能存在极个别事务因同步超时而提交,但这属于小概率事件,因此Semi-sync功能,能够保证RPO无限接近于0。