企业级运维——Mysql主从复制(异步、半同步、全同步)

主从复制原理

MySQL主从复制涉及到三个线程,一个运行在主节点(log dump thread),其余两个(I/O thread, SQL
thread)运行在从节点,如下图所示:
在这里插入图片描述

1.主节点 binary log dump 线程

当从节点连接主节点时,主节点会创建一个log dump 线程,用于发送bin-log的内容。在读取bin-log中的操作时,此线程会对主节点上的bin-log加锁,当读取完成,甚至在发动给从节点之前,锁会被释放。

2.从节点I/O线程

当从节点上执行start slave命令之后,从节点会创建一个I/O线程用来连接主节点,请求主库中更新的bin-log。I/O线程接收到主节点binlog dump 进程发来的更新之后,保存在本地relay-log中。

3.从节点SQL线程

SQL线程负责读取relay log中的内容,解析成具体的操作并执行,最终保证主从数据的一致性。

主从复制过程

  • 对于每一个主从连接,都需要三个进程来完成。当主节点有多个从节点时,主节点会为每一个当前连接的从节点建一个binary log dump 进程,而每个从节点都有自己的I/O进程,SQL进程。从节点用两个线程将从主库拉取更新和执行分成独立的任务,这样在执行同步数据任务的时候,不会降低读操作的性能。比如,如果从节点没有运行,此时I/O进程可以很快从主节点获取更新,尽管SQL进程还没有执行。如果在SQL进程执行之前从节点服务停止,至少I/O进程已经从主节点拉取到了最新的变更并且保存在本地relay日志中,当服务再次起来之后,就可以完成数据的同步。

  • 要实施复制,首先必须打开Master 端的binary log(bin-log)功能,否则无法实现。

  • 因为整个复制过程实际上就是Slave 从Master 端获取该日志然后再在自己身上完全顺序的执行日志中所记录的各种操作。如下图所示:
    在这里插入图片描述

复制的基本过程如下:

  • 1.从节点上的I/O 进程连接主节点,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容;
  • 2.主节点接收到来自从节点的I/O请求后,通过负责复制的I/O进程根据请求信息读取指定日志指定位置之后的日志信息,返回给从节点。返回信息中除了日志所包含的信息之外,还包括本次返回的信息的bin-log file 的以及bin-log position;从节点的I/O进程接收到内容后,将接收到的日志内容更新到本机的relay log中,并将读取到的binary log文件名和位置保存到master-info 文件中,以便在下一次读取的时候能够清楚的告诉Master“我需要从某个bin-log 的哪个位置开始往后的日志内容,请发给我”;
  • 3.Slave 的 SQL线程检测到relay-log 中新增加了内容后,会将relay-log的内容解析成在祝节点上实际执行过的操作,并在本数据库中执行。

异步模式(mysql async-mode)

异步模式如下图所示,这种模式下,主节点不会主动push bin log到从节点,这样有可能导致failover的情况下,也许从节点没有即时地将最新的bin log同步到本地。

在这里插入图片描述

半同步模式(mysql semi-sync)

这种模式下主节点只需要接收到其中一台从节点的返回信息,就会commit;否则需要等待直到超时时间然后切换成异步模式再提交;这样做的目的可以使主从数据库的数据延迟缩小,可以提高数据安全性,确保了事务提交后,binlog至少传输到了一个从节点上,但不能保证从节点将此事务更新到db中。性能上会有一定的降低,响应时间会变长。如下图所示:

在这里插入图片描述
半同步模式不是mysql内置的,从mysql 5.5开始集成,需要master 和slave 安装插件开启半同步模式。

全同步模式

全同步模式是指主节点和从节点全部执行了commit并确认才会向客户端返回成功。

主从复制——异步复制实验

一、实验环境

两台rhel7.5的虚拟机,一台作为master,一台作为slave。

主机名(IP)角色
server1master
server2slave

我们这里分别通过传统的基于日志点的主从复制、基于GTID的主从复制分别实现异步复制。

二、基于日志点的主从复制——异步复制

server1(master)主库配置

  • 1.官网下载并解压安装mysql
[root@server1 ~]# ls
mysql-5.7.24-1.el7.x86_64.rpm-bundle.tar
[root@server1 ~]# tar xf mysql-5.7.24-1.el7.x86_64.rpm-bundle.tar
[root@server1 ~]# ls
mysql-5.7.24-1.el7.x86_64.rpm-bundle.tar
mysql-community-client-5.7.24-1.el7.x86_64.rpm
mysql-community-common-5.7.24-1.el7.x86_64.rpm
mysql-community-devel-5.7.24-1.el7.x86_64.rpm
mysql-community-embedded-5.7.24-1.el7.x86_64.rpm
mysql-community-embedded-compat-5.7.24-1.el7.x86_64.rpm
mysql-community-embedded-devel-5.7.24-1.el7.x86_64.rpm
mysql-community-libs-5.7.24-1.el7.x86_64.rpm
mysql-community-libs-compat-5.7.24-1.el7.x86_64.rpm
mysql-community-minimal-debuginfo-5.7.24-1.el7.x86_64.rpm
mysql-community-server-5.7.24-1.el7.x86_64.rpm
mysql-community-server-minimal-5.7.24-1.el7.x86_64.rpm
mysql-community-test-5.7.24-1.el7.x86_64.rpm

我们这里安装mysql只需要一些必要的包即可,即下面这五个:

[root@server1 ~]# yum install -y mysql-community-client-5.7.24-1.el7.x86_64.rpm mysql-community-common-5.7.24-1.el7.x86_64.rpm mysql-community-libs-5.7.24-1.el7.x86_64.rpm mysql-community-libs-compat-5.7.24-1.el7.x86_64.rpm mysql-community-server-5.7.24-1.el7.x86_64.rpm

因为要实现主从复制,所以server2也需要安装这些包:

[root@server1 ~]# scp mysql-community-client-5.7.24-1.el7.x86_64.rpm mysql-community-common-5.7.24-1.el7.x86_64.rpm mysql-community-libs-5.7.24-1.el7.x86_64.rpm mysql-community-libs-compat-5.7.24-1.el7.x86_64.rpm mysql-community-server-5.7.24-1.el7.x86_64.rpm  root@172.25.66.2:

  • 2.启动数据库,查看密码,并进行安全初始化。
[root@server1 ~]# systemctl start mysqld
[root@server1 ~]# grep password /var/log/mysqld.log 
2019-07-29T02:17:59.567048Z 1 [Note] A temporary password is generated for root@localhost: dkgi%%xeo1=A
[root@server1 ~]# mysql_secure_installation

在这里插入图片描述

  • 3.登录查看Mysql密码是否修改成功。
[root@server1 ~]# mysql -uroot -pWsp+123ld
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 5
Server version: 5.7.24 MySQL Community Server (GPL)

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)
  • 4.编辑mysql的配置文件(为了实现主从复制)
[root@server1 ~]# vim /etc/my.cnf

文件末尾添加:
在这里插入图片描述
保存退出后记得重启服务:systemctl restart mysqld

  • 5.创建一个用户用来复制(Creating a User for Replication)并授权。
mysql> CREATE USER 'repl'@'172.25.66.%' IDENTIFIED BY 'Wsp+123ld';
Query OK, 0 rows affected (0.02 sec)

mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'172.25.66.%';
Query OK, 0 rows affected (0.01 sec)
  • 6.查看二进制日志是否打开,以及查看主库状态。
mysql> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | ON    |
+---------------+-------+
1 row in set (0.00 sec)

mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 |      615 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

server2(slave)从库配置

  • 1.安装Mysql
[root@server2 ~]# yum install -y mysql-community-client-5.7.24-1.el7.x86_64.rpm mysql-community-common-5.7.24-1.el7.x86_64.rpm mysql-community-libs-5.7.24-1.el7.x86_64.rpm mysql-community-libs-compat-5.7.24-1.el7.x86_64.rpm mysql-community-server-5.7.24-1.el7.x86_64.rpm
  • 2.安全初始化
[root@server2 ~]# systemctl start mysqld
[root@server2 ~]# grep pass /var/log/mysqld.log 
2019-07-29T02:46:44.242354Z 1 [Note] A temporary password is generated for root@localhost: 2pH,kaH)nI/w
[root@server2 ~]# mysql_secure_installation 

这里与MASTER一致。

  • 3.修改配置文件(为了实现主从复制)
[root@server2 ~]# vim /etc/my.cnf
在文件最下写入一行:
server-id=2

[root@server2 ~]# systemctl restart mysqld
  • 4.slave节点需要的设置。(设置谁是master节点信息)
mysql> CHANGE MASTER TO MASTER_HOST='172.25.66.1',
    -> MASTER_USER='repl',
    -> MASTER_PASSWORD='Wsp+123ld',
    -> MASTER_LOG_FILE='mysql-bin.000001',
    -> MASTER_LOG_POS=615;

注意:这里的Master相关信息就是我们刚刚设置主库的相关信息,其中 MASTER_LOG_FILE和MASTER_LOG_POS是我们上面通过show master status;查看到的。

  • 5.开启主从复制的slave并查看从库slave是否设置成功。
mysql> start slave;
Query OK, 0 rows affected (0.02 sec)

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.25.66.1				# 查看是否是master
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 615
               Relay_Log_File: server2-relay-bin.000002
                Relay_Log_Pos: 320
        Relay_Master_Log_File: mysql-bin.000001
             Slave_IO_Running: Yes					#这里IO线程、SQL线程运行,说明成功
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 

如果这里Slave_IO_Running、Slave_IO_Running不全是Yes,请看这篇博客,有几种排错方法。

测试

  • 1.在主库server1中创建库和表并且插入数据
mysql> create database linux;
Query OK, 1 row affected (0.01 sec)

mysql> use linux;
Database changed

mysql> create table userlist(
    -> username varchar(10) not null,
    -> age int not null);
Query OK, 0 rows affected (0.18 sec)

mysql> insert into userlist values('mac',23);
Query OK, 1 row affected (0.02 sec)

mysql> select * from userlist;
+----------+-----+
| username | age |
+----------+-----+
| mac      |  23 |
+----------+-----+
1 row in set (0.00 sec)

  • 2.在从库server2登录查看数据是否同步
mysql> select * from linux.userlist;
+----------+-----+
| username | age |
+----------+-----+
| mac      |  23 |
+----------+-----+
1 row in set (0.00 sec)

至此,我们就用传统的主从复制方法——基于日志点的主从复制实现了异步复制。

三、基于GTID的主从复制——异步复制

基于gtid主从复制简介

mysql数据库从5.6.5开始新增一种基于gtid的复制方式。gtid(global transaction id)是对于一个已提交事务的编号。gtid实际上是由uuid+tid组成的,其中uuid是mysql实例的一个标识,tid则代表了该实例上交的事务数量,并且随着事务的提交单调递增
主从复制默认是通过pos(position)复制,就是说在日志文档里,将用户进行的每一项操作都进行编号(pos),每一个事件都有一个起始编号,一个终止编号,在配置主从复制节点时,要求其从master的pos开始同步数据库里面的数据,这也称作传统复制技术。
gtid就是类似pos的作用,不过它是整个mysql复制架构全局通用的,即在整个mysql冗余架构中,它们的日志文件里面事件的gtid的数值是一致的。
gtid是一个对于已提交的事物的编号,并且是一个全局唯一的编号
通过gtid保证每个主库上提交的事务在集群中有一个唯一的id。这种方式强化了主备的一致性,故障恢复及其容错能力。

  • @ 在传统的复制里面,当发生故障,需要主从切换,需要找到binlog和pos点,然后将主节点指向新的主节点,相对来说比较麻烦,也容易出错。在MySQL 5.6里面,不用再找binlog和pos点,我们只需要知道主节点的ip,端口,以及账号密码就行,因为复制是自动的,MySQL会通过内部机制GTID自动找点同步。

  • @ 多线程复制(基于库),在MySQL 5.6以前的版本,slave的复制是单线程的。一个事件一个事件的读取应用。而master是并发写入的,所以延时是避免不了的。唯一有效的方法是把多个库放在多台slave,这样又有点浪费服务器。在MySQL 5.6里面,我们可以把多个表放在多个库,这样就可以使用多线程复制。

基于GTID复制实现的工作原理

  • 主节点更新数据时,会在事务前产生GTID,一起记录到binlog日志中。
  • 从节点的I/O线程将变更的bin log,写入到本地的relay log中。
  • SQL线程从relay log中获取GTID,然后对比本地binlog是否有记录(所以MySQL从节点必须要开启binary log)。
  • 如果有记录,说明该GTID的事务已经执行,从节点会忽略。
  • 如果没有记录,从节点就会从relay log中执行该GTID的事务,并记录到bin log。
  • 在解析过程中会判断是否有主键,如果没有就用二级索引,如果有就用全部扫描。

pos与gtid的区别

俩者都是日志文件里的一个标志,如果将整个mysql集群看作一个整体,pos就是局部的,gtid就是全局的

GTID master节点的配置

  • 1.配置文件添加如下内容:
gtid_mode=ON
enforce-gtid-consistency=true

在这里插入图片描述

  • 2.重启服务,并查看master的uuid
[root@server1 ~]# systemctl restart mysqld
[root@server1 ~]# cat /var/lib/mysql/auto.cnf 
[auto]
server-uuid=15d708f6-b1a7-11e9-9c82-525400d85f32

GTID slave节点的配置

  • 1.配置文件添加如下内容,并重启服务
gtid_mode=ON
enforce-gtid-consistency=true

在这里插入图片描述

systemctl restart mysqld
  • 2.先停掉slave,添加新的master模式,然后再次开启slave
mysql> stop slave;
Query OK, 0 rows affected (0.03 sec)

mysql> CHANGE MASTER TO
    -> MASTER_HOST = '172.25.66.1',
    -> MASTER_USER = 'repl',
    ->  MASTER_PASSWORD = 'Wsp+123ld',
    -> MASTER_AUTO_POSITION = 1;

mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
  • 3.查看slave状态,注意uuid是否与master一致。
mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.25.66.1
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000002
          Read_Master_Log_Pos: 154
               Relay_Log_File: server2-relay-bin.000002
                Relay_Log_Pos: 367
        Relay_Master_Log_File: mysql-bin.000002
             Slave_IO_Running: Yes
            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: 154
              Relay_Log_Space: 576
              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: 1
                  Master_UUID: 15d708f6-b1a7-11e9-9c82-525400d85f32			# uuid与master一致
             Master_Info_File: /var/lib/mysql/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: 
            Executed_Gtid_Set: 
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

测试

  • 1.在主库中插入数据
mysql> insert into linux.userlist values('hah',12);
Query OK, 1 row affected (0.03 sec)
  • 2.在从库中查看
mysql> select * from linux.userlist;
+----------+-----+
| username | age |
+----------+-----+
| mac      |  23 |
| hah      |  12 |
+----------+-----+
2 rows in set (0.00 sec)

主从复制——半同步复制实验(基于GTID)

我们这里实现Mysql的基于GTID的半同步复制实验。

半同步定义

MySQL默认的复制即是异步的,主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理,这样就会有一个问题,主如果挂掉了,此时主上已经提交的事务可能并没有传到从上,如果此时,强行将从提升为主,可能导致新主上的数据不完整。则半同步复制就解决数据丢失的问题。半同步最少有一个slave复制完成master的所有数据后才会进行下一步事务操作。

基于gtid的半同步的部署

master主库的配置(server1)

  • 1.安装半同步的master服务插件
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
Query OK, 0 rows affected (0.02 sec)
  • 2.开启半同步复制,并查看半同步插件是否活跃
mysql> SET GLOBAL rpl_semi_sync_master_enabled = ON;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS
    ->        FROM INFORMATION_SCHEMA.PLUGINS
    ->        WHERE PLUGIN_NAME LIKE '%semi%';
+----------------------+---------------+
| PLUGIN_NAME          | PLUGIN_STATUS |
+----------------------+---------------+
| rpl_semi_sync_master | ACTIVE        |
+----------------------+---------------+
1 row in set (0.00 sec)

  • 3.查看半同步复制相关环境变量设置,半同步复制的master的状态:
mysql> show variables like '%semi%';
+-------------------------------------------+------------+
| Variable_name                             | Value      |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled              | ON         |
| 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 |
+-------------------------------------------+------------+
6 rows in set (0.00 sec)

这里可以看到,master的半同步已经开启,半同步的超时时间:10000ms(10s),我们在实际生产环境中为了保证数据完整性,用半同步的话,一般需要设置为无穷大;超时过后,默认变为异步复制。

mysql> show status like '%semi%';
+--------------------------------------------+-------+
| 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             | 0     |
| Rpl_semi_sync_master_no_times              | 0     |
| 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      | 0     |
| Rpl_semi_sync_master_tx_wait_time          | 0     |
| Rpl_semi_sync_master_tx_waits              | 0     |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0     |
| Rpl_semi_sync_master_wait_sessions         | 0     |
| Rpl_semi_sync_master_yes_tx                | 0     |
+--------------------------------------------+-------+
14 rows in set (0.00 sec)

可以看到| Rpl_semi_sync_master_status | ON |,说明已经开启成功。

slave从端的配置(server2)

  • 1.安装半同步slave的插件,并开启半同步复制
mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
Query OK, 0 rows affected (0.01 sec)

mysql> SET GLOBAL rpl_semi_sync_slave_enabled = 1;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like '%semi%';
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled     | ON    |
| rpl_semi_sync_slave_trace_level | 32    |
+---------------------------------+-------+
2 rows in set (0.00 sec)
  • 2.因为我们刚刚做了gtid的异步复制,所以要先关闭io线程然后再打开,如果没有进行重启io线程操作,则默认还是异步复制。
mysql> stop slave io_thread;
Query OK, 0 rows affected (0.02 sec)

mysql> start slave io_thread;
Query OK, 0 rows affected (0.00 sec)

测试

  • 1.slave从端关掉io线程
mysql> stop slave io_thread;
Query OK, 0 rows affected (0.01 sec)
  • 2.在主端插入数据,会等待10s中,当发现slave挂掉后,10s后会自动切换为默认的异步复制,再次插入数据,速度会变快,因为此时是异步复制,不用等待同步。
mysql> insert into linux.userlist values('nv',13);
Query OK, 1 row affected (10.03 sec)

mysql> insert into linux.userlist values('waaaa',43);
Query OK, 1 row affected (0.02 sec)

  • 3.在主端查看半同步复制的情况
mysql> show status like '%semi%';
+--------------------------------------------+-------+
| 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             | 0     |
| Rpl_semi_sync_master_no_times              | 1     |
| Rpl_semi_sync_master_no_tx                 | 2     |
| Rpl_semi_sync_master_status                | OFF   |
| Rpl_semi_sync_master_timefunc_failures     | 0     |
| Rpl_semi_sync_master_tx_avg_wait_time      | 0     |
| Rpl_semi_sync_master_tx_wait_time          | 0     |
| Rpl_semi_sync_master_tx_waits              | 0     |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0     |
| Rpl_semi_sync_master_wait_sessions         | 0     |
| Rpl_semi_sync_master_yes_tx                | 0     |
+--------------------------------------------+-------+
14 rows in set (0.00 sec)

可以看到,其中| Rpl_semi_sync_master_no_tx | 2 |表示有两次没有半同步成功。
此时我们在从端查询不到新插入的数据。

mysql> select * from linux.userlist;
+----------+-----+
| username | age |
+----------+-----+
| mac      |  23 |
| hah      |  12 |
+----------+-----+
2 rows in set (0.00 sec)
  • 4.在从端的数据是没有同步过来的,当再次打开io线程,数据同步过来但是这是因为主从异步复制所同步的数据。
mysql> start slave io_thread;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from linux.userlist;
+----------+-----+
| username | age |
+----------+-----+
| mac      |  23 |
| hah      |  12 |
| nv       |  13 |
| waaaa    |  43 |
+----------+-----+
4 rows in set (0.00 sec)

主从复制——全同步复制实验(基于GTID)

Mysql的组复制(全同步复制)简介

组复制分单主模式和多主模式,mysql 的复制技术仅解决了数据同步的问题。但是如果 master 宕机,意味着数据库管理员需要介入,应用系统可能需要修改数据库连接地址或者重启才能实现。

组复制在数据库层面上做到了,只要集群中大多数主机可用,则服务可用。

  • 单主模型:从复制组众多个MYSQL节点中自动选举一个master节点,只有master节点可以写,其它节点自动设置为只读。当master节点故障时,会自动选举一个新的master节点,选举成功后,它将设置为可写,其它的slave将指向这个新的master。

  • 多主模型:复制组中的任何一个节点都可以写,因此没有master和slave的概念,只要突然故障的节点的数量不太多这个多主模就能继续使用。

全同步复制原理

组复制由多个mysql服务器组成,并且组中的每一个mysql服务成员可以独立的执行事务。但是所有的读写事务只有在冲突检测成功后才会提交,只读事务不需要冲突检测,可以立即提交
对于任何读写事务,提交操作并不是由始发服务单向决定的,而是由组来决定是否提交。

在始发mysql服务上,当事务准备好要提交时,该主机会广播写入值即已改变的行和对应的写入集及已更新的行的唯一标识符。然后会为该事务建立一个全局的顺序。最终,所有的server成员以相同的顺序接收同一组事务。所有的server成员以相同的顺序应用相同的更改,以保证组内一致。

全同步复制优点

  1. 组复制中即使一些server发生故障,系统仍然可用,只是在性能和伸缩性上有所降低,但是仍然可用。
  2. server故障是孤立的。它们由组成员服务来监控,组成员服务依赖于分布式的故障检测系统,其能够在任何server自愿或者由于意外停止而离开组时发出信号。

单主模式下的Mysql全同步复制的部署

一、实验环境

这里需要增加一台slave节点。

主机名(IP)服务
server1(172.25.66.1)master
server2(172.25.66.2)slave
server3(172.25.66.3)slave

二、server1(Master)的部署

  • 1.由于在此实验之前做了mysql的其它相关应用,所以首先需要进行对数据库重新清理,以下2、3步为清理过程

  • 2.查看server1上的uuid后面组复制时的配置文件需要用到
    注意:这里需要的uuid和后面组中所有节点的uuid不能相同。

[root@server1 ~]# cat /var/lib/mysql/auto.cnf 
[auto]
server-uuid=15d708f6-b1a7-11e9-9c82-525400d85f32
  • 3.数据库的文件删除恢复到初始状态,注意要先关闭数据库然后再删文件,才会生效
[root@server1 ~]# cd /var/lib/mysql
[root@server1 mysql]# systemctl stop mysqld.service 
[root@server1 mysql]# ls
auto.cnf         client-key.pem  ib_logfile1       mysql-bin.000002    public_key.pem
ca-key.pem       ib_buffer_pool  linux             mysql-bin.index     server-cert.pem
ca.pem           ibdata1         mysql             performance_schema  server-key.pem
client-cert.pem  ib_logfile0     mysql-bin.000001  private_key.pem     sys
[root@server1 mysql]# rm -fr *
[root@server1 mysql]# ls
  • 4.编辑配置文件添加组复制相关配置
server_id=1
gtid_mode=ON
enforce_gtid_consistency=ON
master_info_repository=TABLE
relay_log_info_repository=TABLE
binlog_checksum=NONE
log_slave_updates=ON
log_bin=binlog
binlog_format=ROW

transaction_write_set_extraction=XXHASH64	##指定server必须为每个事务收集写集合,并使用哈希算法将其编码为散列
loose-group_replication_group_name="15d708f6-b1a7-11e9-9c82-525400d85f32"		##对创建的组命名,为我们之前的master的uuid
loose-group_replication_start_on_boot=off		##不自动启动组复制
loose-group_replication_local_address= "172.25.66.1:33061"		##本地的端口33061实现成员连接
loose-group_replication_group_seeds= "172.25.66.1:33061,172.25.66.2:33061,172.25.66.3:33061"
loose-group_replication_bootstrap_group=off		 ##是否自动引导组
loose-group_replication_ip_whitelist="127.0.0.1,172.25.66.0/24"
loose-group_replication_enforce_update_everywhere_checks=ON		##打开检查及其更新
loose-group_replication_single_primary_mode=OFF		#设置组自动选择一个server来处理读写工作
  • 5.开启数据库,查看密码并且登录,可以在登录后使用命令对其初始化及修改密码
[root@server1 mysql]# systemctl restart mysqld
[root@server1 mysql]# grep password /var/log/mysqld.log 


mysql> alter user root@localhost identified by 'Wsp+123ld';
Query OK, 0 rows affected (0.03 sec)

  • 6.开启组复制
mysql> SET SQL_LOG_BIN=0;	##首先在进行用户建立之前关闭二进制日志,建立好之后再打开
mysql> CREATE USER 'repl'@'%' identified by 'Wsp+123ld';	##创建复制用户
mysql> select user from mysql.user;		# 查看用户
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';		 #授予用户权限
mysql> FLUSH PRIVILEGES;	##刷新数据
mysql> SET SQL_LOG_BIN=1;	##开启日志
mysql> CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='Wsp+123ld' FOR CHANNEL 'group_replication_recovery';	

##设置如果要改变master时需要通过该通道group_replication_recovery给其master的用户名和密码

mysql> INSTALL PLUGIN group_replication SONAME 'group_replication.so';	 ##安装组复制插件
mysql> SET GLOBAL group_replication_bootstrap_group=ON;	 ##只在master上进行的操作,即自动引导组,当打开组复制之后将其再关闭 
mysql> START GROUP_REPLICATION;
mysql> SET GLOBAL group_replication_bootstrap_group=OFF;
mysql> SHOW PLUGINS;		 ##查看组复制插件,是否成功
  • 7.组复制添加完成后查看状态为online则组复制添加成功。
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | ba729a62-b1c5-11e9-8cbe-525400d85f32 | server1     |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
1 row in set (0.00 sec)

  • 8.创建库添加表,插入数据方便后续的测试
mysql> create database test;
Query OK, 1 row affected (0.01 sec)

mysql> use test;
Database changed

mysql> CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 TEXT NOT NULL);
Query OK, 0 rows affected (0.14 sec)

mysql> INSERT INTO t1 VALUES (1, 'Luis');
Query OK, 1 row affected (0.04 sec)

mysql> SELECT * FROM t1;
+----+------+
| c1 | c2   |
+----+------+
|  1 | Luis |
+----+------+
1 row in set (0.00 sec)

三、server2、server3(Slave)的部署

  • 1.如果和server1做了相应的mysql的应用,则需要删除数据,重新开启数据库进行初始化
[root@server2 ~]# cd /var/lib/mysql
[root@server2 mysql]# ls
auto.cnf         ib_logfile0  mysql.sock.lock           server2-relay-bin.index
ca-key.pem       ib_logfile1  performance_schema        server-cert.pem
ca.pem           ibtmp1       private_key.pem           server-key.pem
client-cert.pem  linux        public_key.pem            sys
client-key.pem   master.info  relay-log.info
ib_buffer_pool   mysql        server2-relay-bin.000004
ibdata1          mysql.sock   server2-relay-bin.000005
[root@server2 mysql]# systemctl stop mysqld.service 
[root@server2 mysql]# rm -fr *
[root@server2 mysql]# systemctl restart mysqld.service 
[root@server2 mysql]# grep pass /var/log/mysqld.log 

mysql> alter user root@localhost identified by 'Wsp+123ld';

  • 2.编辑配置文件添加组复制
    注意:修改server-id和localhost本地ip地址。
server_id=2
gtid_mode=ON
enforce_gtid_consistency=ON
master_info_repository=TABLE
relay_log_info_repository=TABLE
binlog_checksum=NONE
log_slave_updates=ON
log_bin=binlog
binlog_format=ROW

transaction_write_set_extraction=XXHASH64
loose-group_replication_group_name="15d708f6-b1a7-11e9-9c82-525400d85f32"
loose-group_replication_start_on_boot=off
loose-group_replication_local_address= "172.25.66.2:33061"
loose-group_replication_group_seeds= "172.25.66.1:33061,172.25.66.2:33061,172.25.66.3:33061"
loose-group_replication_bootstrap_group=off
loose-group_replication_ip_whitelist="127.0.0.1,172.25.66.0/24"
loose-group_replication_enforce_update_everywhere_checks=ON
loose-group_replication_single_primary_mode=OFF

保存退出后,重启服务systemctl restart mysqld

  • 3.启动组复制
mysql> SET SQL_LOG_BIN=0;
mysql> CREATE USER 'repl'@'%' IDENTIFIED BY 'Wsp+123ld';
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
mysql> FLUSH PRIVILEGES;
mysql> SET SQL_LOG_BIN=1;
mysql> CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='Wsp+123ld'   FOR CHANNEL 'group_replication_recovery';
mysql> INSTALL PLUGIN group_replication SONAME 'group_replication.so';
mysql> SET GLOBAL group_replication_allow_local_disjoint_gtids_join=on;
mysql> START GROUP_REPLICATION;
mysql> SHOW PLUGINS;

查看组成员及其状态:

mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | ba729a62-b1c5-11e9-8cbe-525400d85f32 | server1     |        3306 | ONLINE       |
| group_replication_applier | cc8f4072-b1c8-11e9-a152-5254000c57b5 | server2     |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+

如果出现问题,例如MEMBER_STATE 显示RECOVERING,从以下几点排错:
a.检测所有的MEMBER_ID 是否和master配置文件中loose-group_replication_group_name不同,才能进行。
b.检查解析文件/etc/hosts是否配置了和主机名一致的解析。
c.主从库的初始数据可能不一致导致。

这里可以参考博客:

  • 4.查看数据是否同步
mysql> select * from test.t1;
+----+------+
| c1 | c2   |
+----+------+
|  1 | Luis |
+----+------+
1 row in set (0.00 sec)
  • 5.同样的,在server3上查看组成员及其状态,以及数据是否同步。
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 881fedba-b1ce-11e9-b205-525400aaba12 | server3     |        3306 | ONLINE       |
| group_replication_applier | ba729a62-b1c5-11e9-8cbe-525400d85f32 | server1     |        3306 | ONLINE       |
| group_replication_applier | cc8f4072-b1c8-11e9-a152-5254000c57b5 | server2     |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+

mysql> select * from test.t1;
+----+------+
| c1 | c2   |
+----+------+
|  1 | Luis |
+----+------+
1 row in set (0.00 sec)


至此,就完成了组复制(全同步复制)的实验。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值