前言:
此时朋友们对“mysql半同步”大体比较注重,大家都想要剖析一些“mysql半同步”的相关文章。那么小编同时在网摘上收集了一些关于“mysql半同步””的相关内容,希望看官们能喜欢,我们快快来了解一下吧!关注我「程序猿集锦」,获取更多分享。
前言主从复制的方式异步复制半同步复制安装半同步复制插件Master节点安装半同步插件Slave节点安装半同步插件配置半同步插件的参数Master节点参数配置Slave节点参数配置启动半同步复制插件参数rpl_semi_sync_master_wait_point详解半同步复制的注意事项同步复制总结前言
前面我们分享了MySQL数据库读写分离主从复制环境搭建的过程,包括基于日之点的主从复制和基于全局事务GTID的复制两种方式。这两种复制方式,在主和从之间的复制binlog的时候都是异步进行的,也就是说,主上面的一个事务完成并提交之后,这个事务什么时候会被同步到从上面,主是不关系的,是交给主从同步的线程自己去管理的。
这样的方式在主节点异常宕机后,很容易发生已经提交的数据丢失的现象发生,同时在集群中发生数据冲突,数据不一致的概率也比较大。MySQL为了解决这些问题,在5.6之后提出了半同步复制的方式。
主从复制的方式
MySQL在复制主节点的binlog日志的时候有三种复制方式,分别如下:
异步复制:MySQL默认的复制即是异步的,主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理,这样就会有一个问题,主如果crash掉了,此时主上已经提交的事务可能并没有传到从上,如果此时,强行将从提升为主,可能导致新主上的数据不完整。半同步复制:介于异步复制和全同步复制之间,主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个或多个从库(这里可以通过参数配置到底需要多少个从库)接收到并写到relay log中才返回给客户端。相对于异步复制,半同步复制提高了数据的安全性,同时它也造成了一定程度的延迟,这个延迟最少是一个TCP/IP往返的时间。所以,半同步复制最好在低延时的网络中使用。同步复制:指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。异步复制
异步复制是搭建好MySQL主从复制集群后,默认使用的复制方式。这个复制的流程图如下,供你参考:
半同步复制
半同步复制是依赖于插件来完成的,默认情况下这个插件是没有安装的,所以我们需要自己安装并且启动这个插件。下面我们基于一个双主双从的集群来安装并启用半同步复制。这个集群的网络拓扑图如下所示:
安装半同步复制插件
参考链接:
MySQL中所有的插件安装文件都在MySQL的安装目录下,具体是哪里,我们可以使用如下的命令查看插件安装文件所在的目录。
mysql> show variables like '%plugin_dir%';+---------------+------------------------+| Variable_name | Value |+---------------+------------------------+| plugin_dir | /usr/lib/mysql/plugin/ |+---------------+------------------------+1 row in set (0.01 sec)mysql>
通过上面的命令,我们知道插件安装文件在目录/usr/lib/mysql/plugin/下面。我们查看一下具体有哪些插件安装文件。
root@master1:~# ls -lstr /usr/lib/mysql/plugin/total 6752 28 -rw-r--r-- 1 root root 27624 Jun 2 2020 version_token.so 32 -rw-r--r-- 1 root root 32152 Jun 2 2020 validate_password.so 20 -rw-r--r-- 1 root root 19160 Jun 2 2020 semisync_slave.so # salve节点需要安装的半同步插件安装文件 64 -rw-r--r-- 1 root root 62000 Jun 2 2020 semisync_master.so # master节点需要安装的半同步插件安装文件 60 -rw-r--r-- 1 root root 60904 Jun 2 2020 rewriter.so1816 -rw-r--r-- 1 root root 1855976 Jun 2 2020 mysqlx.so 16 -rw-r--r-- 1 root root 14512 Jun 2 2020 mysql_no_login.so 16 -rw-r--r-- 1 root root 14968 Jun 2 2020 mypluglib.so 16 -rw-r--r-- 1 root root 14288 Jun 2 2020 locking_service.so 16 -rw-r--r-- 1 root root 15096 Jun 2 2020 libpluginmecab.so 280 -rw-r--r-- 1 root root 283416 Jun 2 2020 libmemcached.so 24 -rw-r--r-- 1 root root 22944 Jun 2 2020 keyring_udf.so 84 -rw-r--r-- 1 root root 85704 Jun 2 2020 keyring_file.so 108 -rw-r--r-- 1 root root 110080 Jun 2 2020 innodb_engine.so4040 -rw-r--r-- 1 root root 4135568 Jun 2 2020 group_replication.so 48 -rw-r--r-- 1 root root 48920 Jun 2 2020 connection_control.so 36 -rw-r--r-- 1 root root 35416 Jun 2 2020 authentication_ldap_sasl_client.so 16 -rw-r--r-- 1 root root 14616 Jun 2 2020 auth_socket.so 28 -rw-r--r-- 1 root root 25488 Jun 2 2020 adt_null.so 4 drwxr-xr-x 2 root root 4096 Oct 13 16:03 debugroot@master1:~#
安装半同步插件,需要使用具有super权限的MySQL用户,我们这里使用root用户来安装这个插件。
Master节点安装半同步插件
下面在所有的maser节点上面安装semisync_master.so和semisync_slave.so,之所以要安装semisyncslave.so是因为两个主节点之间互为主备,它两个彼此之间要互相作为对方的从节点。
安装完成后可以看到关于半同步复制的参数和状态如下所示:
mysql> install plugin rpl_semi_sync_master soname 'semisync_master.so';Query OK, 0 rows affected (0.06 sec)/* 查看安装半同步复制插件后的默认参数值,没有安装插件的时候,是看不到这些变量的的。 */mysql> show global variables like '%rpl%';+-------------------------------------------+------------+| Variable_name | Value |+-------------------------------------------+------------+| rpl_semi_sync_master_enabled | OFF || rpl_semi_sync_master_timeout | 10000 || rpl_semi_sync_master_trace_level | 32 || rpl_semi_sync_master_wait_for_slave_count | 1 || rpl_semi_sync_master_wait_no_slave | ON || rpl_semi_sync_master_wait_point | AFTER_SYNC || rpl_semi_sync_slave_enabled | OFF || rpl_semi_sync_slave_trace_level | 32 || rpl_stop_slave_timeout | 31536000 |+-------------------------------------------+------------+9 rows in set (0.00 sec)/* 查看安装半同步复制插件后的参数状态,没有安装插件的时候,是看不到这些状态变量的。 */mysql> show global status like '%rpl%';+--------------------------------------------+-------+| Variable_name | Value |+--------------------------------------------+-------+| Rpl_semi_sync_master_clients | 0 || Rpl_semi_sync_master_net_avg_wait_time | 0 || Rpl_semi_sync_master_net_wait_time | 0 || Rpl_semi_sync_master_net_waits | 2 || Rpl_semi_sync_master_no_times | 1 || Rpl_semi_sync_master_no_tx | 0 || Rpl_semi_sync_master_status | OFF || Rpl_semi_sync_master_timefunc_failures | 0 || Rpl_semi_sync_master_tx_avg_wait_time | 1855 || Rpl_semi_sync_master_tx_wait_time | 1855 || Rpl_semi_sync_master_tx_waits | 1 || Rpl_semi_sync_master_wait_pos_backtraverse | 0 || Rpl_semi_sync_master_wait_sessions | 0 || Rpl_semi_sync_master_yes_tx | 2 || Rpl_semi_sync_slave_status | OFF |+--------------------------------------------+-------+15 rows in set (0.00 sec)mysql>
下面介绍一下maser节点上关于半同步复制的几个关键参数,如下:
rpl_semi_sync_master_enabled:它的值为OFF|ON,表示开启或关闭master节点半同步复制。rpl_semi_sync_master_timeout:master节点等待slave节点反馈的时间,如果超过这个参数设置的时间,master将不再等待slave给与的反馈,把此次半同步复制转换为异步复制方式来进行。这个值不要设置的过大,否则将会影响master节点上面写数据的响应时间。建议设置为1s或0.5s即可。rpl_semi_sync_master_wait_for_slave_count:这个参数表示主节点需要等待几个从节点给反馈后,才向客户端返回事务执行成功的消息。默认值为1,表示主节点只要接受到任意1个从节点给的反馈后,就会向客户端返回事务执行成功的消息,如果是配置为2,则表示至少要有两个从节点反馈消息给主节点后,主节点才会返回给客户端事务执行成功的消息。这个参数在有多个从节点的时候,有必要配置,否则将会等待所有的从节点都反馈给主节点之后,主节点才会把事务执行的消息反馈给客户端。这个参数的功能启用与否,取决于参数rpl_semi_sync_master_wait_no_slave的值。rpl_semi_sync_master_wait_no_slave:它的值为OFF|ON,默认为ON,它决定是否开启参数rpl_semi_sync_master_wait_for_slave_count的功能。rpl_stop_slave_timeout:这个参数一般不用修改,它可以控制停止SLAVE在超时之前等待的时间长度(以秒为单位)。这可以用来避免STOP SLAVE和其他使用到副本的不同客户端连接的SQL语句之间的死锁。它的最大值和默认值为31536000秒(1年),最小值是2秒。对该变量的更改将对后续的STOP SLAVE语句生效。这个变量只影响发出STOP SLAVE语句的客户端。当达到超时时,发出命令的客户端返回一个错误消息,说明命令执行不完整。然后客户端停止等待复制线程停止,但是复制线程继续尝试停止,并且stop SLAVE指令仍然有效。一旦复制线程不再繁忙,就会执行STOP SLAVE语句并停止复制。rpl_semi_sync_master_wait_point:它的值为AFTER_SYNC|AFTER_COMMIT,默认值为AFTER_SYNC。这个参数用于控制主节从什么时间点开始等待从反馈同步的结果,这个参数是在MySQL5.7.2版本中才增加的,在这个版本之前,是没有这个参数的,那个时候半同步复制的是采用AFTER_COMMIT的功能来实现的。当这个参数的值为AFTER_SYNC的时候,表示只要主节点的服务层记录了binlog之后,就开始进入等待状态,此时主节点的存储引擎层并没有执行commit操作。所以,在主节点等待从节点给与反馈之前的这段时间,新的客户端请求是不能从主节点中读取到这个事务的修改内容的。当这个参数的值为AFTER_COMMIT的时候,表示只有当主节点的存储引擎层执行了commit的操作之后,主节点才开始进入等待状态,此时的事务已经提交,只是还没有反馈给客户端。如果此时使用新的客户端向主节点发起查询,是可以查询到刚才的事务对数据的修改内容。Slave节点安装半同步插件
然后在所有的salve节点semisync_slave.so,安装完成后可以看到半同步相关参数和状态如下所示:
mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so';Query OK, 0 rows affected (0.08 sec)mysql> show global variables like '%rpl%';+---------------------------------+----------+| Variable_name | Value |+---------------------------------+----------+| rpl_semi_sync_slave_enabled | OFF || rpl_semi_sync_slave_trace_level | 32 || rpl_stop_slave_timeout | 31536000 |+---------------------------------+----------+3 rows in set (0.02 sec)mysql> show global status like '%rpl%';+----------------------------+-------+| Variable_name | Value |+----------------------------+-------+| Rpl_semi_sync_slave_status | OFF |+----------------------------+-------+1 row in set (0.01 sec)mysql>
下面介绍一下salve节点中的关于半同步设置的几个重要参数,如下:
rpl_semi_sync_slave_enabled:取值范围是OFF|ON,表示关闭或者开启slave节点的半同步复制功能。rpl_stop_slave_timeout:同master节点上的这个参数含义一样。
在安装完成半同步复制的插件之后,我们可以在mysql.plugin表中,查看到我们自己安装的插件,对于MySQL原本就存在的插件,这个表中不会显示出来,如下所示。除了可以在这个表中查看,我们还可以使用show plugins命令查看所有已经安装的插件,这个命令可以查看所有存在的插件,包括MySQL原生自带的和我们自己安装的。
/* master节点如下所示 */mysql> select * from mysql.plugin;+----------------------+--------------------+| name | dl |+----------------------+--------------------+| rpl_semi_sync_master | semisync_master.so |+----------------------+--------------------+1 row in set (0.01 sec)/* slave节点如下所示 */mysql> select * from mysql.plugin;+---------------------+-------------------+| name | dl |+---------------------+-------------------+| rpl_semi_sync_slave | semisync_slave.so |+---------------------+-------------------+1 row in set (0.00 sec)mysql>配置半同步插件的参数
在maser节点和slave节点都安装好半同步复制的插件之后,我们需要对半同步复制插件的参数做一些修改,然后再去启用半同步复制的功能。
Master节点参数配置
在所有的master节点修改如下参数,一共需要修改三个参数,开启主和从的半同步复制功能,并且修改主等待从反馈的超时时间。
/* 启用主节点的半同步复制功能 */mysql> set global rpl_semi_sync_master_enabled = ON;Query OK, 0 rows affected (0.02 sec)/* 设置半同步复制功能等待从节点反馈的超时时间为500毫秒 */mysql> set global rpl_semi_sync_master_timeout=500;Query OK, 0 rows affected (0.00 sec)/* 启用从节点的半同步复制功能,此时的主作为另外一个主节点的从节点,所以需要开启这个从节点半同步复制的功能 */mysql> set global rpl_semi_sync_slave_enabled = ON;Query OK, 0 rows affected (0.00 sec)/* 查看修改后的结果 */mysql> show global variables like '%rpl%';+-------------------------------------------+------------+| Variable_name | Value |+-------------------------------------------+------------+| rpl_semi_sync_master_enabled | ON |/*已经开启master节点的半同步复制的功能*/| rpl_semi_sync_master_timeout | 500 |/*超时时间已经修改成功*/| rpl_semi_sync_master_trace_level | 32 || rpl_semi_sync_master_wait_for_slave_count | 1 || rpl_semi_sync_master_wait_no_slave | ON || rpl_semi_sync_master_wait_point | AFTER_SYNC || rpl_semi_sync_slave_enabled | ON |/*已经开启slave节点的半同步复制的功能*/| rpl_semi_sync_slave_trace_level | 32 || rpl_stop_slave_timeout | 31536000 |+-------------------------------------------+------------+9 rows in set (0.00 sec)mysql>Slave节点参数配置
在所有的slave节点修改如下参数,slave节点的参数修改只要开启半同步复制的功能就可以了,其他不用做多余的修改。
/* 启用从节点的半同步复制功能 */mysql> set global rpl_semi_sync_slave_enabled = ON;Query OK, 0 rows affected (0.00 sec)/* 查看修改后的结果 */mysql> show global variables like '%rpl%';+---------------------------------+----------+| Variable_name | Value |+---------------------------------+----------+| rpl_semi_sync_slave_enabled | ON |/*已经开启slave节点的半同步复制的功能*/| rpl_semi_sync_slave_trace_level | 32 || rpl_stop_slave_timeout | 31536000 |+---------------------------------+----------+3 rows in set (0.01 sec)mysql>
注意:以上配置都是真的当前正在运行的MySQL数据库实例来设置的,如果MySQL数据库实例重启之后,上面的设置会失效。为了永久生效,需要把上面的参数配置在my.cnf配置文件中,这样就能保住即便是MySQL数据库实例重启之后,我们的半同步复制配置仍然有效。具体配置参考如下:
[mysqld]# 下面的四个参数只针对master节点才配置rpl_semi_sync_master_enabled = onrpl_semi_sync_master_timeout = 500rpl_semi_sync_master_wait_point = AFTER_SYNCrpl_semi_sync_slave_enabled = on # 如果master节点也需要从其他节点同步数据,则开启这个参数,否则不用配置这个参数。# 下面的这个参数只针对slave节点才配置rpl_semi_sync_slave_enabled = on启动半同步复制插件
配置好半同步复制的参会之后,接下来启动这个版同步复制的功能。其实启动这个功能很简单,前面参数已经配置为on启动的状态,我们只要把组从复制的链路,停止然后再重新启动就可以了。
在所有的master节点和salve节点都执行如下的SQL语句:
mysql> stop slave;Query OK, 0 rows affected, 1 warning (0.00 sec)mysql> start slave;Query OK, 0 rows affected (0.07 sec)mysql>
在都重新启动复制链路之后,我们看下master1节点的半同步复制的状态:
/*master1节点执行的结果如下*/mysql> show global status like '%rpl%';+--------------------------------------------+-------+| Variable_name | Value |+--------------------------------------------+-------+| Rpl_semi_sync_master_clients | 3 |/*从这个参数可以看出,这个主有3个从,分别是master2和salve1和slave2*/| Rpl_semi_sync_master_net_avg_wait_time | 0 || Rpl_semi_sync_master_net_wait_time | 0 || Rpl_semi_sync_master_net_waits | 5 || Rpl_semi_sync_master_no_times | 2 || Rpl_semi_sync_master_no_tx | 1 || Rpl_semi_sync_master_status | ON || Rpl_semi_sync_master_timefunc_failures | 0 || Rpl_semi_sync_master_tx_avg_wait_time | 4809 || Rpl_semi_sync_master_tx_wait_time | 4809 || Rpl_semi_sync_master_tx_waits | 1 || Rpl_semi_sync_master_wait_pos_backtraverse | 0 || Rpl_semi_sync_master_wait_sessions | 0 || Rpl_semi_sync_master_yes_tx | 1 || Rpl_semi_sync_slave_status | ON |+--------------------------------------------+-------+15 rows in set (0.00 sec)/*master2节点执行的结果如下*/mysql> show global status like '%rpl%';+--------------------------------------------+-------+| Variable_name | Value |+--------------------------------------------+-------+| Rpl_semi_sync_master_clients | 1 |/*从这个参数可以看出,这个主有1个从,就是master1*/| Rpl_semi_sync_master_net_avg_wait_time | 0 || Rpl_semi_sync_master_net_wait_time | 0 || Rpl_semi_sync_master_net_waits | 2 || Rpl_semi_sync_master_no_times | 1 || Rpl_semi_sync_master_no_tx | 0 || Rpl_semi_sync_master_status | ON || Rpl_semi_sync_master_timefunc_failures | 0 || Rpl_semi_sync_master_tx_avg_wait_time | 1855 || Rpl_semi_sync_master_tx_wait_time | 1855 || Rpl_semi_sync_master_tx_waits | 1 || Rpl_semi_sync_master_wait_pos_backtraverse | 0 || Rpl_semi_sync_master_wait_sessions | 0 || Rpl_semi_sync_master_yes_tx | 2 || Rpl_semi_sync_slave_status | ON |+--------------------------------------------+-------+15 rows in set (0.00 sec)mysql>
查看slave1和slave2从节点上,半同步复制的状态如下:
mysql> show global status like '%rpl%';+----------------------------+-------+| Variable_name | Value |+----------------------------+-------+| Rpl_semi_sync_slave_status | ON |+----------------------------+-------+1 row in set (0.00 sec)mysql>
此时我们就在主节点和从节点上面都启动了半同步复制的功能。
参数rpl_semi_sync_master_wait_point详解
MySQL5.7.2中为何要增加AFTER_SYNC的支持?
当采用rpl_semi_sync_master_wait_point=AFTER_COMMIT这种方式时候,有这样一个潜在的问题:客户端事务在存储引擎层执行完成commit之后,等待将binlog同步到从节点的过程中,此时还没有将commit的结果发给客户端,如果主库宕机了,此时可能的情况有两种
事务还没发送到从库上
此时,客户端会收到事务提交失败的信息,客户端会重新提交该事务到新的主上,当宕机的主库重新启动后,以从库的身份重新加入到该主从结构中,会发现,该事务在从库中被提交了两次,一次是之前作为主的时候,一次是被新主同步过来的。
事务已经发送到从库上
此时,从库已经收到并应用了该事务,但是客户端仍然会收到事务提交失败的信息,重新提交该事务到新的主上,此时就发生异常。
为了解决上面的现象所产生的问题,在MySQL5.7.2版本中,才增加了参数rpl_semi_sync_master_wait_point=AFTER_SYNC的功能来解决这个问题。
rpl_semi_sync_master_wait_point = AFTER_SYNC的效果如下所示:
rpl_semi_sync_master_wait_point = AFTER_COMMIT的效果如下所示,在5.7.2之前的版本,都默认采用下面这种复制方式。
结合上面的两张图片,我们可以做一个实验来真实体验一下参数rpl_semi_sync_master_wait_point的值分别是什么效果。从上面的两个图中可以看出,我们设置如下的测试参数:
/* 第一个是实验的参数配置 */set global rpl_semi_sync_master_timeout = 40000set global rpl_semi_sync_master_wait_for_slave_count = 2set global rpl_semi_sync_master_wait_no_slave = onset global rpl_semi_sync_master_wait_point = AFTER_SYNC/* 另外一个是实验的参数配置 */set global rpl_semi_sync_master_timeout = 40000set global rpl_semi_sync_master_wait_for_slave_count = 2set global rpl_semi_sync_master_wait_no_slave = onset global rpl_semi_sync_master_wait_point = AFTER_COMMIT
基于上面的每一套参数配置,我们都会把其中一个主从复制链路使用stop slave命令停止掉,另外一个slave正常复制,目的就是为了当我们在主上面执行一个DML语句后,让主等待40s之后才给发起事务的客户端反馈。而在这40s的时间内,我们在主上新开一个session窗口,去查看主上刚执行的DML操作是否可以在新的session中被查询到。
这样,我们可以体会到rpl_semi_sync_master_wait_point参数的值为AFTER_SYNC或者AFTER_COMMIT的区别是什么了。
我们知道在InnoDB存储引擎中,MySQL在执行DML操作的时候,会涉及到两阶段提交的操作。期间有这么一个步骤,存储引擎层告知服务层undolog记录成功并标记为prepare状态,可以记录binlog日志了,服务层接收到存储引擎层的通知后,会记录binlog日志,在记录binlog日志之后,再通知存储引擎层,存储引擎层收到消息后,会修改undolog的状态为commit状态,此时的事务才算是真正的被commit成功。结合上面的rpl_semi_sync_master_wait_point参数,我们更能够体会到这个事务两阶段提交的过程。
半同步复制的注意事项关于半同步复制插件的相关变量和参数,需要在安装完成插件后才可以查看到,否则没有这些参数和变量。在安装半同步复制插件的时候,需要使用具有super权限的用户来安装。插件在所有节点都要安装,不同的节点安装不同的插件,Linux/Unix服务器上插件的名称以.so结尾,Windows上面插件的名称以.dll结尾。在半同步复制中,主节点等待从节点反馈消息的时间如果超过了最大等待时间的阈值,半同步转换会异步同步。等主从链路恢复后,下次的事务会自动再次转换为半同步复制,无需人工切换。只限于单源复制,不支持多源复制,也就是只支持一主一从,一主多从,双主多从(主主互为主备)这样的网络拓扑架构,不支持多主一从的网络拓扑架构。不支持如下网络拓扑架构。
同步复制
同步复制是最安全的一种复制方式,但是效率也是最低的一种模式。它的复制流程图如下所示,这也是另外中MySQL高可用集群的实现方式之一:MGR高可用集群,基于组的复制。以后再展开说一下这个这种复制方式。
总结
这篇文章中,我们讨论了MySQL集群中,主从复制的三种复制方式。分别是异步复制、半同步复制、同步复制。这三种复制模式对于数据库写性能的影响,是从小到大。
异步复制对写性能的影响比较小,但是在集群中发生数据的丢失和数据不一致的风险确是最大的。半同步复制对写的性能有一定的影响,但是对集群中发生数据丢失和数据不一致的风险能有一定的保障。同步复制对写性能影响最大,但是它对集群中发生数据丢失和数据不一致的风险确是最小的。
推荐在生产环境中,使用介于异步复制和同步复制中间的半同步复制方式作为主从复制的方式。原因是:它能在保证数据不丢失,主从数据的一致性的同时,还可以最大限度地提高了数据及其写的性能,是从两个方面综合考虑后的一种方式。
标签: #mysql半同步