MySQL Fabric这一新的架构为MySQL提供了高可用和向外扩展的特性。本实验专注于高可用。高可用指的是系统提供持续服务的能力。下图显示了一个系统中应该为服务可用提供的不同层次。
MySQL Fabric在MySQL复制上增加了一个管理和监控层,它和一组MySQL Fabric-aware连接器一起,把写和一致性读操作路由到当前的主服务器。MySQL Fabric有一个HA组的概念。HA组是由两个或两个以上的MySQL服务器组成的服务器池。在任一时间点,HA组中有一个主服务器,其它的都是从服务器。HA组的作用是确保该组中的数据总是可访问的。MySQL复制通过把数据复制多份提供数据安全性,同时,MySQL Fabric也提供两个组件提供高可用方案:
失败检测与提升
MySQL Fabric进程监控HA组中的主服务器。当主服务器宕机,该进程会选择一个从服务器,把它提升为主服务器,而HA组中其它的从服务器将接收新主服务器的数据修改。注意当连接器观察到主服务器出现问题时,可能会提醒MySQL Fabric,而MySQL Fabric进程会使用该信息作为产生服务器池中相关状态决策的一部分。路由数据库请求
当MySQL Fabric提升了一个新的主服务器,它会修改存储的服务器状态并且提示连接器用更新的路由信息刷新其缓存。使用这种方式,应用不需要感知复制拓扑的改变,也不需要知道写操作指向了不同的目的地。
二、安装与配置
1. 使用VirtualBox安装两个CentOS release 6.4虚拟机,安装Python 2.6或以上版本,关闭iptables和selinux。虚拟机和网卡说明如下表所示。
主机名 |
内部网络IP |
说明 |
fab_connector |
192.168.56.101 |
安装Fabric和MySQL,建立一个MySQL实例,使用缺省的3306端口,存储HA Group的状态和路由信息 |
fab_group1 |
192.168.56.102 |
安装MySQL,建立三个MySQL数据库实例,端口分别是3326、3327、3328,组成一个HA Group |
虚拟机名称 |
网卡 |
连接方式 |
说明 |
fab_connector |
网卡1 |
网络地址转换(NAT) |
用于虚拟机访问宿主机和外网 |
网卡2 |
桥接网卡(192.168.16.119) |
用于宿主机访问虚拟机 |
|
网卡3 |
内部网络 |
用于Fabric组内互联 |
|
fab_group1 |
网卡1 |
网络地址转换(NAT) |
用于虚拟机访问宿主机和外网 |
网卡3 |
内部网络 |
用于Fabric组内互联 |
cd /root tar xvf mysql-5.7.10-linux-glibc2.5-x86_64.tar tar zxvf mysql-5.7.10-linux-glibc2.5-x86_64.tar.gz ln -s mysql-5.6.13-linux-glibc2.5-x86_64 mysql groupadd mysql useradd -r -g mysql mysql chown -R mysql .3. 在fab_connector上安装Fabric
cd /root tar zxvf mysql-utilities-1.5.6.tar.gz cd mysql-utilities-1.5.6 sudo python setup.py install4. 在fab_connector上配置并启动MySQL
[root@fab_connector ~]# cat /root/.bash_profile # .bash_profile # Get the aliases and functions if [ -f ~/.bashrc ]; then <span style="white-space:pre"> </span>. ~/.bashrc fi # User specific environment and startup programs PATH=$PATH:$HOME/bin:/root/mysql/bin export PATH [root@fab_connector ~]# cat /etc/my_fabric.cnf [mysqld] basedir=/root/mysql datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock binlog-format=ROW log-slave-updates=true gtid-mode=on enforce-gtid-consistency=true master-info-repository=TABLE relay-log-info-repository=TABLE sync-master-info=1 port=3306 report-host=fab_connector report-port=3306 server-id=1 log-bin=fab-bin.log [root@fab_connector ~]# mysqld --defaults-file=/etc/my_fabric.cnf --initialize [root@fab_connector ~]# mysqld --defaults-file=/etc/my_fabric.cnf --user=mysql & [root@fab_connector ~]# mysql -h 127.0.0.1 -P3306 -u root -p -e "CREATE USER 'fabric'@'localhost' IDENTIFIED BY 'secret';GRANT ALL ON fabric.* TO 'fabric'@'localhost'";5. 在fab_group1上配置三个MySQL实例
[root@fab_group1 ~]# cat .bash_profile # .bash_profile # Get the aliases and functions if [ -f ~/.bashrc ]; then . ~/.bashrc fi # User specific environment and startup programs PATH=$PATH:$HOME/bin:/root/mysql/bin export PATH [root@fab_group1 bin]# cat /etc/my_group1_1_init.cnf [mysqld] basedir=/root/mysql datadir=/var/lib/group1_1 port=3326 socket=/var/lib/group1_1/mysql.sock [root@fab_group1 bin]# cat /etc/my_group1_2_init.cnf [mysqld] basedir=/root/mysql datadir=/var/lib/group1_2 port=3327 socket=/var/lib/group1_2/mysql.sock [root@fab_group1 bin]# cat /etc/my_group1_3_init.cnf [mysqld] basedir=/root/mysql datadir=/var/lib/group1_3 port=3328 socket=/var/lib/group1_3/mysql.sock [root@fab_group1 ~]# cat /etc/my_group1_1.cnf [mysqld] basedir=/root/mysql datadir=/var/lib/group1_1 port=3326 socket=/var/lib/group1_1/mysql.sock binlog-format=ROW log-slave-updates=true gtid-mode=on enforce-gtid-consistency=true master-info-repository=TABLE relay-log-info-repository=TABLE sync-master-info=1 report-host=fab_group1 report-port=3326 server-id=11 log-bin=fab1a-bin.log log_error_verbosity=1 [root@fab_group1 ~]# cat /etc/my_group1_2.cnf [mysqld] basedir=/root/mysql datadir=/var/lib/group1_2 port=3327 socket=/var/lib/group1_2/mysql.sock binlog-format=ROW log-slave-updates=true gtid-mode=on enforce-gtid-consistency=true master-info-repository=TABLE relay-log-info-repository=TABLE sync-master-info=1 report-host=fab_group1 report-port=3327 server-id=12 log-bin=fab1a-bin.log log_error_verbosity=1 [root@fab_group1 ~]# cat /etc/my_group1_3.cnf [mysqld] basedir=/root/mysql datadir=/var/lib/group1_3 port=3328 socket=/var/lib/group1_3/mysql.sock binlog-format=ROW log-slave-updates=true gtid-mode=on enforce-gtid-consistency=true master-info-repository=TABLE relay-log-info-repository=TABLE sync-master-info=1 report-host=fab_group1 report-port=3328 server-id=13 log-bin=fab1a-bin.log log_error_verbosity=1 [root@fab_group1 ~]# mysqld --defaults-file=/etc/my_group1_1_init.cnf --initialize [root@fab_group1 ~]# mysqld --defaults-file=/etc/my_group1_2_init.cnf --initialize [root@fab_group1 ~]# mysqld --defaults-file=/etc/my_group1_3_init.cnf --initialize # 记下初始化生成的临时密码 [root@fab_group1 ~]# chown -R mysql /var/lib/group1_1 [root@fab_group1 ~]# chown -R mysql /var/lib/group1_2 [root@fab_group1 ~]# chown -R mysql /var/lib/group1_3 [root@fab_group1 ~]# mysqld --defaults-file=/etc/my_group1_1_init.cnf --user=mysql & [root@fab_group1 ~]# mysqld --defaults-file=/etc/my_group1_2_init.cnf --user=mysql & [root@fab_group1 ~]# mysqld --defaults-file=/etc/my_group1_3_init.cnf --user=mysql & [root@fab_connector ~]# mysql -h 127.0.0.1 -P3326 -u root -p ALTER USER USER() IDENTIFIED BY 'new_password'; CREATE USER 'fabric'@'%' IDENTIFIED BY 'secret'; GRANT ALL ON *.* TO 'fabric'@'%'; [root@fab_connector ~]# mysql -h 127.0.0.1 -P3327 -u root -p ALTER USER USER() IDENTIFIED BY 'new_password'; CREATE USER 'fabric'@'%' IDENTIFIED BY 'secret'; GRANT ALL ON *.* TO 'fabric'@'%'; [root@fab_connector ~]# mysql -h 127.0.0.1 -P3328 -u root -p ALTER USER USER() IDENTIFIED BY 'new_password'; CREATE USER 'fabric'@'%' IDENTIFIED BY 'secret'; GRANT ALL ON *.* TO 'fabric'@'%'; # 修改初始密码,添加fabric用户 [root@fab_group1 ~]# mysqladmin -u root --protocol=tcp -h127.0.0.1 -P3326 -p shutdown [root@fab_group1 ~]# mysqladmin -u root --protocol=tcp -h127.0.0.1 -P3327 -p shutdown [root@fab_group1 ~]# mysqladmin -u root --protocol=tcp -h127.0.0.1 -P3328 -p shutdown [root@fab_group1 ~]# mysqld --defaults-file=/etc/my_group1_1.cnf --user=mysql & [root@fab_group1 ~]# mysqld --defaults-file=/etc/my_group1_2.cnf --user=mysql & [root@fab_group1 ~]# mysqld --defaults-file=/etc/my_group1_3.cnf --user=mysql & # 重启三个实例
6. 在fab_connector上配置并启动Fabric
[root@fab_connector ~]# cat /etc/mysql/fabric.cfg [DEFAULT] prefix = sysconfdir = /etc logdir = /var/log [statistics] prune_time = 3600 [logging] url = file:///var/log/fabric.log level = INFO [storage] auth_plugin = mysql_native_password database = fabric user = fabric address = localhost:3306 connection_delay = 1 connection_timeout = 6 password = secret connection_attempts = 6 [failure_tracking] notification_interval = 60 notification_clients = 50 detection_timeout = 1 detection_interval = 6 notifications = 300 detections = 3 failover_interval = 0 prune_time = 3600 [servers] restore_user = fabric unreachable_timeout = 5 backup_password = secret backup_user = fabric user = fabric restore_password = secret password = secret [connector] ttl = 1 [protocol.xmlrpc] disable_authentication = no ssl_cert = realm = MySQL Fabric ssl_key = ssl_ca = threads = 5 user = admin address = 192.168.16.119:32274 password = secret [executor] executors = 5 [sharding] prune_limit = 10000 mysqldump_program = /root/mysql/bin/mysqldump mysqlclient_program = /root/mysql/bin/mysql [protocol.mysql] disable_authentication = no ssl_cert = ssl_key = ssl_ca = user = admin address = 192.168.16.119:32275 password = secret [root@fab_connector ~]# mysqlfabric manage setup在状态存储(MySQL数据库实例)中建立Fabric库,执行显示如下图。
[root@fab_connector ~]# mysqlfabric manage start --daemonize
启动MySQL Fabric进程,执行显示如下图。
[root@fab_connector ~]# mysqlfabric manage ping
检查fabric进程是否运行,执行显示如下图。
7. 在fab_connector上建立HA Group(my_group1,并在其中添加三个MySQL实例)
警告:在执行这步前要确认组中所有的server-uuid都不相同。否则在将服务器添加到组中时会报错。
[root@fab_group1 bin]# cat /var/lib/group1_1/auto.cnf [auto] server-uuid=e488a44d-aa02-11e5-876a-080027a5c938 [root@fab_group1 bin]# cat /var/lib/group1_2/auto.cnf [auto] server-uuid=ee359882-aa02-11e5-89aa-080027a5c938 [root@fab_group1 bin]# cat /var/lib/group1_3/auto.cnf [auto] server-uuid=f6bea0b0-aa02-11e5-89c7-080027a5c938
[root@fab_connector ~]# mysqlfabric group create my_group1[root@fab_connector ~]# mysqlfabric group create my_group1
[root@fab_connector ~]# mysqlfabric group add my_group1 192.168.56.102:3327将实例2添加到my_group1,执行显示如下图。
[root@fab_connector ~]# mysqlfabric group add my_group1 192.168.56.102:3328
将实例3添加到my_group1,执行显示如下图。
[root@fab_connector ~]# mysqlfabric group promote my_group1
自动在my_group1中选出一个实例提升为primary,执行显示如下图。
[root@fab_connector ~]# mysqlfabric group lookup_servers my_group1
查看my_group1中的实例,执行显示如下图。
[root@fab_connector ~]# mysqlfabric group activate my_group1
激活故障自动切换,执行显示如下图。
初始实例的状态如下图所示,3328为主,3326、3327为从。
三个实例的GTID如下所示。3328:f6bea0b0-aa02-11e5-89c7-080027a5c938:1-21101
正常关闭3328实例
[root@fab_group1 ~]# mysqladmin -u root --protocol=tcp -h127.0.0.1 -P3328 -p shutdown自动失败切换后,三个实例的状态如下图所示,3328的状态变为FAULTY,3327提升为主,3326为从。
use test; create table t1(a int); insert into t1 values(1); commit;两个实例上的GTID如下所示。
再把3328加回到组中
[root@fab_connector ~]# mysqlfabric group remove my_group1 192.168.56.102:3328 [root@fab_group1 ~]# mysqld --defaults-file=/etc/my_group1_3.cnf --user=mysql & [root@fab_connector ~]# mysqlfabric group add my_group1 192.168.56.102:3328
3328上的GTID如下所示。
3326:e488a44d-aa02-11e5-876a-080027a5c938:1-3113
3327:ee359882-aa02-11e5-89aa-080027a5c938:1-3894
3328:f6bea0b0-aa02-11e5-89c7-080027a5c938:1-21101
在3328上查询t1,数据已经自动复制。
use test; select * from t1;至此,在“没有活动会话且正常关实例”的情况下,可以失败自动切换,当实例重新加回到组中,下线期间的事务会自动复制以保持数据一致性。这种场景意义不大,除了有计划的停机,不会在生产系统中出现。
2. 没有活动会话,异常关实例
用kill -9强杀主实例进程,结果和上一种情况类似。可以失败自动切换,当实例重新加回到组中,下线期间的事务会自动复制以保持数据一致性。这种场景意义也不大,繁忙的生产系统中出现的概率几乎没有。
3. 有活动会话,正常关实例
初始实例的状态如下图所示,3328为主,3326、3327为从。
三个实例的GTID如下所示。
3326:e488a44d-aa02-11e5-876a-080027a5c938:1-3113
3327:ee359882-aa02-11e5-89aa-080027a5c938:1-3896
3328:f6bea0b0-aa02-11e5-89c7-080027a5c938:1-23809
运行一个Java应用程序,代码如下:
import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import org.apache.commons.lang3.RandomStringUtils; public class Main { private static String URL = "jdbc:mysql:fabric://192.168.16.119:32274/test?fabricUsername=admin&fabricPassword=<span style="font-family: Consolas, 'Courier New', Courier, mono, serif; font-size: 12px; line-height: 18px; background-color: rgb(248, 248, 248);">secret</span>&fabricServer Group=my_group1"; private static String USERNAME = "fabric"; private static String PWD = "secret"; private static int MAX = 20000; private static String SQL = "insert into chat_message(src_userid,target_userid,message,s1,s2,s3,s4) values(?,?,?,?,?,?,?)"; public static void main(String[] args) throws ClassNotFoundException, SQLException, UnsupportedEncodingException { long start = System.currentTimeMillis(); testInsert(); long end = System.currentTimeMillis(); System.out.println((end - start)); System.out.println(MAX / ((end - start) / 1000)); } private static Connection getConnection() throws SQLException, ClassNotFoundException { Class.forName("com.mysql.fabric.jdbc.FabricMySQLDriver"); Connection con = DriverManager.getConnection(URL,USERNAME,PWD); return con; } private static void testInsert() throws ClassNotFoundException, SQLException { Connection con = getConnection(); con.setAutoCommit(false); con.setReadOnly(false); PreparedStatement pt = con.prepareStatement(SQL); int i = 0; while (i < MAX) { pt.setLong(1, 1 + (int) (Math.random() * 100000000)); pt.setLong(2, 1 + (int) (Math.random() * 100000000)); pt.setString(3, RandomStringUtils.randomAscii(200)); pt.setInt(4, 1); pt.setInt(5, 1); pt.setInt(6, 1); pt.setInt(7, 1); pt.executeUpdate(); con.commit(); i++; } con.close(); } private static void testInsertAutoCommit() throws ClassNotFoundException, SQLException { Connection con = getConnection(); con.setAutoCommit(true); PreparedStatement pt = con.prepareStatement(SQL); int i = 0; while (i < MAX) { pt.setLong(1, 1 + (int) (Math.random() * 100000000)); pt.setLong(2, 1 + (int) (Math.random() * 100000000)); pt.setString(3, RandomStringUtils.randomAscii(200)); pt.setInt(4, 1); pt.setInt(5, 1); pt.setInt(6, 1); pt.setInt(7, 1); pt.executeUpdate(); i++; } con.close(); } private static void testBatchInsert(int batchSize) throws ClassNotFoundException, SQLException { Connection con = getConnection(); con.setAutoCommit(false); PreparedStatement pt = con.prepareStatement(SQL); int i = 0; while (i < MAX) { pt.setLong(1, 1 + (int) (Math.random() * 100000000)); pt.setLong(2, 1 + (int) (Math.random() * 100000000)); pt.setString(3, RandomStringUtils.randomAscii(200)); pt.setInt(4, 1); pt.setInt(5, 1); pt.setInt(6, 1); pt.setInt(7, 1); pt.addBatch(); if (i % batchSize == 1) { pt.executeBatch(); con.commit(); } i++; } pt.executeBatch(); con.commit(); con.close(); } private static void testLoadFile(int batchSize) throws ClassNotFoundException, SQLException, UnsupportedEncodingException { String fieldsterminated = "\t\t"; String linesterminated = "\t\r\n"; String loadDataSql = "LOAD DATA LOCAL INFILE 'sql.csv' INTO TABLE chat_message FIELDS TERMINATED BY '" + fieldsterminated + "' LINES TERMINATED BY '" + linesterminated + "' (src_userid,target_userid,message,s1,s2,s3,s4) "; Connection con = getConnection(); con.setAutoCommit(false); PreparedStatement pt = con.prepareStatement(loadDataSql); com.mysql.jdbc.PreparedStatement mysqlStatement = null; if (pt.isWrapperFor(com.mysql.jdbc.Statement.class)) { mysqlStatement = pt.unwrap(com.mysql.jdbc.PreparedStatement.class); } int i = 0; StringBuilder sb = new StringBuilder(10000); while (i < MAX) { sb.append(1 + (int) (Math.random() * 100000000)); sb.append(fieldsterminated); sb.append(1 + (int) (Math.random() * 100000000)); sb.append(fieldsterminated); sb.append(RandomStringUtils.randomAscii(200).replaceAll("\\\\", " ")); sb.append(fieldsterminated); sb.append(1); sb.append(fieldsterminated); sb.append(1); sb.append(fieldsterminated); sb.append(1); sb.append(fieldsterminated); sb.append(1); sb.append(linesterminated); if (i % batchSize == 1) { byte[] bytes = sb.toString().getBytes(); InputStream in = new ByteArrayInputStream(bytes); mysqlStatement.setLocalInfileInputStream(in); mysqlStatement.executeUpdate(); con.commit(); sb = new StringBuilder(10000); } i++; } byte[] bytes = sb.toString().getBytes(); InputStream in = new ByteArrayInputStream(bytes); mysqlStatement.setLocalInfileInputStream(in); mysqlStatement.executeUpdate(); con.commit(); con.close(); } }该程序持续向test.chat_message表里添加数据。在程序执行过程中正常关闭3328实例。
[root@fab_group1 ~]# mysqladmin -u root --protocol=tcp -h127.0.0.1 -P3328 -p shutdown此时三个实例的状态如下图所示,3328的状态为FAULTY,3326和3327的状态还是从,并没有执行自动失败切换。
3326上三个实例的GTID如下所示。
3326:e488a44d-aa02-11e5-876a-080027a5c938:1-3113
3327:ee359882-aa02-11e5-89aa-080027a5c938:1-3896
3328:f6bea0b0-aa02-11e5-89c7-080027a5c938:1-24647
3327上三个实例的GTID如下所示。
3326:e488a44d-aa02-11e5-876a-080027a5c938:1-3113
3327:ee359882-aa02-11e5-89aa-080027a5c938:1-3896
3328:f6bea0b0-aa02-11e5-89c7-080027a5c938:1-24166
3326上由复制执行的事务多于3327(24647大于24166),分别在两个实例上查询记录数也可以证明这一点。3326上test.chat_message表的记录数是838(24647-23809),3327上是357(24166-23809)。
再看一下两个从的状态,3326的如下所示。
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Reconnecting after a failed master event read
Master_Host: 192.168.56.102
Master_User: fabric
Master_Port: 3328
Connect_Retry: 60
Master_Log_File: fab1a-bin.000007
Read_Master_Log_Pos: 434518
Relay_Log_File: fab_group1-relay-bin.000002
Relay_Log_Pos: 434611
Relay_Master_Log_File: fab1a-bin.000007
Slave_IO_Running: Connecting
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 434518
Relay_Log_Space: 434823
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 2003
Last_IO_Error: error reconnecting to master '[email protected]:3328' - retry-time: 60 retries: 6
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 13
Master_UUID: f6bea0b0-aa02-11e5-89c7-080027a5c938
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp: 151225 16:54:37
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set: f6bea0b0-aa02-11e5-89c7-080027a5c938:23809-24647
Executed_Gtid_Set: e488a44d-aa02-11e5-876a-080027a5c938:1-3113,
ee359882-aa02-11e5-89aa-080027a5c938:1-3896,
f6bea0b0-aa02-11e5-89c7-080027a5c938:1-24647
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
1 row in set (0.00 sec)
3327的如下所示。
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: 192.168.56.102
Master_User: fabric
Master_Port: 3328
Connect_Retry: 60
Master_Log_File: fab1a-bin.000007
Read_Master_Log_Pos: 185847
Relay_Log_File: fab_group1-relay-bin.000003
Relay_Log_Pos: 185493
Relay_Master_Log_File: fab1a-bin.000007
Slave_IO_Running: No
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 185360
Relay_Log_Space: 224784
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 13
Master_UUID: f6bea0b0-aa02-11e5-89c7-080027a5c938
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set: f6bea0b0-aa02-11e5-89c7-080027a5c938:23735-24166
Executed_Gtid_Set: e488a44d-aa02-11e5-876a-080027a5c938:1-3113,
ee359882-aa02-11e5-89aa-080027a5c938:1-3896,
f6bea0b0-aa02-11e5-89c7-080027a5c938:1-24166
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
1 row in set (0.00 sec)
从以上状态信息看到,3326的IO线程一直在尝试连接master,而3327已经停止的IO线程。这种情况下Fabricb并没有进行失败切换。这时只能进行人为干预:
(1)停止两个slave:在3326、3327两个实例上执行stop slve;
(2)提升一个slave成为master:在fabric上执行mysqlfabric group promote my_group1
此时三个实例的状态如下图所示,3328的状态为FAULTY,3327是主,3326是从。
3326上三个实例的GTID如下所示。
3326:e488a44d-aa02-11e5-876a-080027a5c938:1-3113
3327:ee359882-aa02-11e5-89aa-080027a5c938:1-3896
3328:f6bea0b0-aa02-11e5-89c7-080027a5c938:1-24647
3327上三个实例的GTID如下所示。
3326:e488a44d-aa02-11e5-876a-080027a5c938:1-3113
3327:ee359882-aa02-11e5-89aa-080027a5c938:1-3896
3328:f6bea0b0-aa02-11e5-89c7-080027a5c938:1-24647
可见在fabric把3327提升为主时,已经把落后于3326的事务补齐,这时分别在两个实例上查询test.chat_message表的记录数都是838。
在新主上执行一些操作
use test; create table t1(a int); insert into t1 values(1); commit;再把3328加回到组中
[root@fab_connector ~]# mysqlfabric group remove my_group1 192.168.56.102:3328 [root@fab_group1 ~]# mysqld --defaults-file=/etc/my_group1_3.cnf --user=mysql & [root@fab_connector ~]# mysqlfabric group add my_group1 192.168.56.102:3328加回3328实例后,三个实例的状态如下图所示,3327为主,3326、3328为从。
3326:e488a44d-aa02-11e5-876a-080027a5c938:1-3113
3327:ee359882-aa02-11e5-89aa-080027a5c938:1-3898
3328:f6bea0b0-aa02-11e5-89c7-080027a5c938:1-24647
在3328上查询t1,数据已经自动复制。
use test; select * from t1;至此,在“有活动会话且正常关实例”的情况下得到以下结论:
5. 启动半同步复制后,有活动会话,异常关实例
(1)启动MySQL5.7的半同步复制
分别在3326、3327、3328三个实例上执行下面的操作:
在cnf配置文件的[mysqld]中添加
plugin_dir=/root/mysql-5.7.10-linux-glibc2.5-x86_64/lib/plugin重启实例后,执行下面的SQL语句
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so'; INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';在cnf配置文件的[mysqld]中添加
rpl_semi_sync_slave_enabled=1 rpl_semi_sync_master_enabled = 1 rpl_semi_sync_master_timeout = 1000重启实例,至此三个实例都已启动了半同步复制。
初始实例的状态如下图所示,3328为主,3326、3327为从。
三个实例的GTID如下所示。
e488a44d-aa02-11e5-876a-080027a5c938:1-3113
ee359882-aa02-11e5-89aa-080027a5c938:1-4609
f6bea0b0-aa02-11e5-89c7-080027a5c938:1-29204
运行上面所示的Java应用程序,在程序执行过程中杀掉3328实例进程
[root@fab_group1 ~]# kill -9 2898此时三个实例的状态如下图所示,3328的状态为FAULTY,3327提升为主,3326为从,执行了自动失败切换。
3326、3327两个实例的GTID如下所示。
e488a44d-aa02-11e5-876a-080027a5c938:1-3113
ee359882-aa02-11e5-89aa-080027a5c938:1-4609
f6bea0b0-aa02-11e5-89c7-080027a5c938:1-29539
在新主上执行一些操作
use test; create table t1(a int); insert into t1 values(1); commit;再把3328加回到组中
[root@fab_connector ~]# mysqlfabric group remove my_group1 192.168.56.102:3328 [root@fab_group1 ~]# mysqld --defaults-file=/etc/my_group1_3.cnf --user=mysql & [root@fab_connector ~]# mysqlfabric group add my_group1 192.168.56.102:3328加回3328实例后,三个实例的状态如下图所示,3327为主,3326、3328为从。
此时三个实例的GTID如下所示。
e488a44d-aa02-11e5-876a-080027a5c938:1-3113
ee359882-aa02-11e5-89aa-080027a5c938:1-4611
f6bea0b0-aa02-11e5-89c7-080027a5c938:1-29539
在3328上查询t1,数据已经自动复制。
use test; select * from t1;再在三个实例上查询chat_message表,数据是一致的。
use test; select count(*) from chat_message;至此,在开启半同步复制的情况下得到以下结论: