前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MySQL Fabric实验(一)HA

MySQL Fabric实验(一)HA

作者头像
用户1148526
发布2022-05-07 12:10:09
1.4K0
发布2022-05-07 12:10:09
举报
文章被收录于专栏:Hadoop数据仓库

一、概述

        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组内互联

        因为只是出于实验的目的,所以使用root用户安装MySQL和Fabric,下载的软件包分别是mysql-5.7.10-linux-glibc2.5-x86_64.tar和mysql-utilities-1.5.6.tar.gz。实验环境如下图所示。

2. 在两个虚拟机上安装MySQL

代码语言:javascript
复制
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

代码语言:javascript
复制
cd /root
tar zxvf mysql-utilities-1.5.6.tar.gz
cd mysql-utilities-1.5.6
sudo python setup.py install

4. 在fab_connector上配置并启动MySQL

代码语言:javascript
复制
[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实例

代码语言:javascript
复制
[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

代码语言:javascript
复制
[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都不相同。否则在将服务器添加到组中时会报错。

代码语言:javascript
复制
[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
代码语言:javascript
复制
[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:3326

将实例1添加到my_group1,执行显示如下图。

代码语言:javascript
复制
[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

激活故障自动切换,执行显示如下图。

三、测试 1. 没有活动会话,正常关实例

初始实例的状态如下图所示,3328为主,3326、3327为从。

三个实例的GTID如下所示。 3326:e488a44d-aa02-11e5-876a-080027a5c938:1-3113 3327:ee359882-aa02-11e5-89aa-080027a5c938:1-3892

3328:f6bea0b0-aa02-11e5-89c7-080027a5c938:1-21101

正常关闭3328实例

代码语言:javascript
复制
[root@fab_group1 ~]# mysqladmin -u root --protocol=tcp -h127.0.0.1 -P3328 -p shutdown

自动失败切换后,三个实例的状态如下图所示,3328的状态变为FAULTY,3327提升为主,3326为从。

在新主上执行一些操作

代码语言:javascript
复制
use test;
create table t1(a int);
insert into t1 values(1);
commit;

两个实例上的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 可以看到由于执行的两个事务,3327上的GTID由3892变成了3894。

再把3328加回到组中

代码语言:javascript
复制
[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为从。

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,数据已经自动复制。

代码语言:javascript
复制
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应用程序,代码如下:

代码语言:javascript
复制
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实例。

代码语言:javascript
复制
[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的如下所示。

代码语言:javascript
复制

 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 'fabric@192.168.56.102: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。

在新主上执行一些操作

代码语言:javascript
复制
use test;
create table t1(a int);
insert into t1 values(1);
commit;

再把3328加回到组中

代码语言:javascript
复制
[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如下所示。

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,数据已经自动复制。

代码语言:javascript
复制
use test;
select * from t1;

至此,在“有活动会话且正常关实例”的情况下得到以下结论: (1)不能失败自动切换,需要人为干预。 (2)当实例重新加回到组中,下线期间的事务会自动复制以保持数据一致性。 (3)这样手工提升会造成数据丢失。         这种场景应该不是常见的情况,即便要人为在主上shutdown,常规操作也会先停掉从。 4. 有活动会话,异常关实例         用kill -9强杀主实例进程,结果和上一种情况类似。不能失败自动切换,需要人为干预。当实例重新加回到组中,下线期间的事务会自动复制以保持数据一致性。这种场景是最常见的异常情况,繁忙的生产系统中主坏了,基本上肯定要人为干预了。

5. 启动半同步复制后,有活动会话,异常关实例

(1)启动MySQL5.7的半同步复制 分别在3326、3327、3328三个实例上执行下面的操作: 在cnf配置文件的[mysqld]中添加

代码语言:javascript
复制
plugin_dir=/root/mysql-5.7.10-linux-glibc2.5-x86_64/lib/plugin

重启实例后,执行下面的SQL语句

代码语言:javascript
复制
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';

在cnf配置文件的[mysqld]中添加

代码语言:javascript
复制
rpl_semi_sync_slave_enabled=1
rpl_semi_sync_master_enabled = 1
rpl_semi_sync_master_timeout = 1000

重启实例,至此三个实例都已启动了半同步复制。 (2)测试fabric自动失败切换

初始实例的状态如下图所示,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实例进程

代码语言:javascript
复制
[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

在新主上执行一些操作

代码语言:javascript
复制
use test;
create table t1(a int);
insert into t1 values(1);
commit;

再把3328加回到组中

代码语言:javascript
复制
[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,数据已经自动复制。

代码语言:javascript
复制
use test;
select * from t1;

再在三个实例上查询chat_message表,数据是一致的。

代码语言:javascript
复制
use test;
select count(*) from chat_message;

至此,在开启半同步复制的情况下得到以下结论: (1)可以失败自动切换 (2)当实例重新加回到组中,下线期间的事务会自动复制以保持数据一致性。 (3)没有数据丢失。 总结:         MySQL Fabric的auto failover是以主从数据一致性为前提的,如果主从数据不一致,则不会进行自动失败切换,这时需要人为干预,把是否需要手工切换的选择权交给用户。这样的设计是合理的。所以在生产系统中要使用自动失败切换,一定要开启半同步复制。当然这又引入了快速网络、快速存储、多线程复制等加快复制速度的优化问题了。 参考: MySQL Fabric官方文档 http://mysqlhighavailability.com/mysql-fabric-adding-high-availability-to-mysql/ http://m.blog.csdn.net/blog/jiangshouzhuang/44134267 http://dev.mysql.com/doc/refman/5.7/en/replication-semisync.html

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015-12-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档