当前位置: 首页 > 科技观察

你知道MySQL主从复制的原理吗?

时间:2023-03-12 21:05:42 科技观察

主从复制是如何实现的?update语句会记录binlog,是逻辑日志。有了这个binlog,从服务器就会获取主服务器的binlog文件,然后解析里面的SQL语句,在从服务器上执行,保持主从数据一致。涉及三个线程,连接master获取binlog,解析binlog写入relaylog。该线程称为I/O线程。master节点上有一个logdump线程,用于向slave发送binlog。从库的SQL线程用于读取relaylog并将数据写入数据库。做了主从复制方案后,我们只向主节点写数据,读请求可以共享给从节点。我们称这种方案为读写分离。读写分离可以在一定程度上降低数据库服务器的访问压力,但是需要特别注意主从数据一致性的问题。如果我们在master中写入,马上去slave查询,但是此时slave数据还没有同步,怎么办?因此,基于主从复制的原理,我们需要搞清楚主从复制慢的原因是什么?线程在早期的MySQL中,slave的SQL线程是单线程的。master可以支持SQL语句的并行执行,配置的最大连接数为最大并发SQL并行执行数。但是slaveSQL只能在单线程队列中执行。在主库并发量大的情况下,同步数据肯定会有延迟。为什么从库上的SQLThreads不能并行执行?比如主库执行了很多SQL语句,先是用户发表评论,然后修改内容,最后删除评论。这三个语句在从库上的执行顺序一定不能颠倒如何解决这个问题呢?如何降低主从复制的延迟?异步和全同步首先我们要知道,在主从复制的过程中,MySQL默认是异步复制的。也就是说,对于master节点来说,写入binlog后,事务就完成了,返回给客户端。对于slave来说,收到binlog就结束了,master并不关心slave的数据是否写入成功。如果要减少延迟,可不可以等从数据库的事务全部执行完再返回给客户端呢?这种方法称为完全同步复制。从库写入数据后,主库返回给客户端。这种方式虽然可以保证数据在读取之前已经同步成功,但是副作用应该是可以想象的。事务执行时间会变长,导致主节点性能下降。有没有更好的办法?既减少了slave写的延迟,又不会显着增加master返回client的时间?半同步复制介于异步复制和全同步复制之间。还有一种半同步复制的方法。主库执行完客户端提交的事务后不会立即返回客户端,而是等待至少有一个从库接收到binlog并写入relaylog后才返回客户端。master不会等太久,但是当它返回给client时,数据就写成功了,因为它只有最后一步:读取relaylog并写入从库。如果我们要在数据库中使用半同步复制,我们必须安装一个插件,这是谷歌工程师贡献的。mysql的插件目录下已经提供了这个插件:cd/usr/lib64/mysql/plugin/主库和从库是不同的插件,安装后需要开启:--The主库执行INSTALLPLUGINrpl_semi_sync_masterSONAME'semisync_master.so';setglobalrpl_semi_sync_master_enabled=1;showvariableslike'%semi_sync%';--从库执行INSTALLPLUGINrpl_semi_sync_slaveSONAME'semisync_slave.so';setglobalrpl_semi_sync_slave_enabled=1;showglobalvariableslike'%semi%';与异步复制相比,半同步复制提高了数据的安全性,同时也造成了一定程度的延迟。它需要等待从服务器写入中继日志。这里多了一个网络交互过程。因此,半同步复制最好用在低延迟的网络中。这是从主从库连接的角度来保证从库数据的写入。另一种思路,如果想减少主从同步的延迟,减少sql执行带来的等待时间,有没有办法在从库上并行执行多条sql语句而不是排队呢?多库并行复制如何实现并行复制?想象一下,如果在三个数据库中执行三个语句,分别操作各自的数据库,会不会没有并发问题呢?执行顺序没有要求。当然,所以如果你是操作三个数据库,这三个数据库的从库的SQL线程是可以并发执行的。这就是MySQL5.6支持的多库并行复制。但是大多数情况下,我们是在一个数据库中有多个表的情况下。如何在数据库中实现并行复制?也就是说,我们知道数据库本身是支持多个事务同时进行的;为什么这些事务在main库中可以并行执行,却不会出现问题?因为它们互不干扰。例如,这些事务对不同的表或行进行操作,不存在资源竞争和数据干扰。在主库上并行执行的事务在从库上也应该并行执行吧?比如master上有3个事务同时操作3张表。这三个事务能否在slave上并行执行?什么?5GTIDreplicationofasynchronousreplicationhttps://dev.mysql.com/doc/refman/5.7/en/replication-gtids.html所以,我们可以将主库上并行执行的事务分成一组,并编号,这组事务也可以在从库上并行执行。我们把这个号码叫做GTID(GlobalTransactionIdentifiers),我们把这种主从复制方式叫做GTID-basedreplication。如果我们要使用GTID复制,可以通过修改配置参数开启,默认是关闭的:showglobalvariableslike'gtid_mode';无论是优化主从连接方式,还是允许从数据库并行执行SQL,都是从数据库层面解决主从复制延迟的问题。