Replication为数据库提供了高可用性和可扩展性解决方案 , 基于GTIDReplication能够更好的处理复制重连和切换Server复制。本文将主要分析MariaDB基于GTIDReplication设计与实现 , 并与MySQL做对比。

1. MariaDB的GTID

1.1 MariaDB GTID定义与实现

GTIDGlobal transaction ID)表示作为一个执行单元的event group , 可以理解为一个“事务”(虽然也包含的非事务的DMLDDL操作)。当event groupMaster复制到Slave执行后 , GTID是被保留的 , 用来在有复制关系的server中识别对应的GTID

使用GTID可以方便的一个Slave切换到从另一个Master Server复制 , 因为GTID在有复制关系的Server中是被唯一标识的。而且执行的GTID信息记录在事务表中 , 可以做到slave的状态是crash-safe

MariaDB中 , GTID由三部分组成 , 三部分之间用’-‘分隔 , 例如0-161002-1:

struct rpl_gtid
{
  uint32 domain_id;
  uint32 server_id;
  uint64 seq_no;
};

第一个是无符号32位整数的domain_id , 在多源复制、多主拓扑复制中每个会写入的Master通常需要设置不同的Domain_id

第二个是无符号32位整数的server_id , 集群中每个server需要设置唯一的server id , 标识最初写入binlogserver , 用来避免循环复制。

第三个是服务号64位整数的seq_no , seq_no在每个写入server产生binlog中是递增的。

本文为分析MariaDB复制 , 创建了互为主备的两个server

1.2 GTID相关参数

  • gtid_slave_pos

    只读变量。用来表示各个复制domain , 最后复制到该server上执行的GTID , 例如”0-161002-3”。

    master_use_gtid=slave_pos , 可以通过设置该全局变量来决定slave server复制的位点。

  • gtid_binlog_pos

    该变量是一个只读参数 , 表示各个domain , 最后写入到binlog中的GTID

    如下面例子 , 分别用domain_id01创建表tt1之后, gtid_binlog_pos为’0-161002-1,1-161002-1’。

    > select @@global.gtid_binlog_pos;
    +--------------------------+
    | @@global.gtid_binlog_pos |
    +--------------------------+
    |                          |
    +--------------------------+
    ​
    select @@global.gtid_domain_id;
    +-------------------------+
    | @@global.gtid_domain_id |
    +-------------------------+
    |                       0 |
    +-------------------------+
    ​
    > create table t(c1 int);
    ​
    > select @@global.gtid_binlog_pos;
    +--------------------------+
    | @@global.gtid_binlog_pos |
    +--------------------------+
    | 0-161002-1               |
    +--------------------------+
    ​
    > set gtid_domain_id=1;
    ​
    > create table t1 (c1 int);
    ​
    > select @@global.gtid_binlog_pos;
    +--------------------------+
    | @@global.gtid_binlog_pos |
    +--------------------------+
    | 0-161002-1,1-161002-1    |
    +--------------------------+
  • gtid_binlog_state

    动态变量。该系统变量是由各个domainserver最后执行的GTID信息组成。这里和gtid_binlog_pos不同的是 , 这里除了domain_id , 不同的server_id也会单独记录。

    例如在上述复制关系中 , 在server_id161003中创建表t2 , 可以看到复制并在server 161002中应用后 , gtid_binlog_pos记录了domain_id分别为01最后应用的GTID: ‘0-161003-2,1-161002-1’ , 而gtid_binlog_state就考虑了不同server ‘0-161002-1,0-161003-2,1-161002-1’

    > create table t2(c1 int);
    ​
    server_id 161002
    ​
    > select @@global.gtid_binlog_pos, @@global.gtid_binlog_state;
    +--------------------------+----------------------------------+
    | @@global.gtid_binlog_pos | @@global.gtid_binlog_state       |
    +--------------------------+----------------------------------+
    | 0-161003-2,1-161002-1    | 0-161002-1,0-161003-2,1-161002-1 |
    +--------------------------+----------------------------------+

    同时gtid_binlog_pos是只读变量 , reset master后 , 可以通过gtid_binlog_state的设置来恢复server中已经写入binlog的信息。

  • gtid_current_pos

    只读变量。该变量记录了各个domain在该server上执行的最后一个GTID , 包含了该server写入和通过复制关系执行的。通过复制关系执行的即使未写入binlog(log_slave_update0) , 该变量也会记录对应的GTID信息。

    例如下面例子 , 在161003log_slave_update=0 , 这个时候在161002中执行写入 , 可以看到161003gtid_current_pos为’0-161002-3,1-161002-1’ , 而gtid_binlog_pos没有变。

    161002
    > insert into t values(2);
    ​
    161003
    show variables like "%gtid%";
    +------------------------+----------------------------------+
    | Variable_name          | Value                            |
    +------------------------+----------------------------------+
    | gtid_binlog_pos        | 0-161003-2,1-161002-1            |
    | gtid_binlog_state      | 0-161002-1,0-161003-2,1-161002-1 |
    | gtid_current_pos       | 0-161002-3,1-161002-1            |

    实际该变量是把gtid_binlog_pos合并到gtid_slave_pos中 , 如果同一个server_idgtid_slave_pos , 且gtid_binlog_possequence number , 就使用gtid_binlog_pos的值。否则就用gtid_slave_pos

    uchar *
    Sys_var_gtid_current_pos::global_value_ptr(THD *thd, const LEX_CSTRING *base)
    {
    String str;
    char *p;
    ​
    str.length(0);
    if (rpl_append_gtid_state(&str, true) ||
        !(p= thd->strmake(str.ptr(), str.length())))
    {
      my_error(ER_OUT_OF_RESOURCES, MYF(0));
      return NULL;
    }
    ​
    return (uchar *)p;
    }
    ​
    /*
      Format the current GTID state as a string, for returning the value of
      @@global.gtid_slave_pos.
    ​
      If the flag use_binlog is true, then the contents of the binary log (if
      enabled) is merged into the current GTID state (@@global.gtid_current_pos).
    */
    int
    rpl_append_gtid_state(String *dest, bool use_binlog)
    {
      int err;
      rpl_gtid *gtid_list= NULL;
      uint32 num_gtids= 0;
    ​
      if (use_binlog && opt_bin_log &&
          (err= mysql_bin_log.get_most_recent_gtid_list(&gtid_list, &num_gtids)))
        return err;
    ​
      err= rpl_global_gtid_slave_state->tostring(dest, gtid_list, num_gtids);
      my_free(gtid_list);
    ​
      return err;
    }
  • gtid_strict_mode

    GTID strict mode打开的时候 , 一些会导致binlogserver间一些场景会额外抛错出来。例如:

    1. 如果一个slave尝试复制比当前binlog中对应replication domainsequence number还要小的GTID时候会报错出来。

    2. 尝试手动设置一个比当前sequence number还要小的GTID(通过@@SESSION.gtid_seq_no)时候报错。

    3. 如果slave的开始GTID位点在master中无法找到对应binlog , 那么即使存在更大sequence numberGTID也会报错出来。

  • gtid_domain_id

    GlobalSession变量 , 用来决定新产生GTIDdomain id

  • last_gtid

    最后一个写入binlog的事务或者StatementGTID

  • server_id

    GlobalSession变量。用来设置GTID中的server id

  • gtid_seq_no

    Session变量。用来设置即将写入GTIDsequence number

  • gtid_ignore_duplicates

    当设置后 , 多源复制中从不同Master中复制到的GTID , 只有一个会被应用 , 其他的会忽略。这样对于指定domain的复制 , 只有一个sequence number用来决定一个给定的GTID是否被应用了。

1.3 与MySQL的不同

MySQLGTIDserver_uuidtransaction_id组成 , 没有用于多源复制的domain_id概念。

GTID = source_id:transaction_id

MariaDBGTID相关执行信息都是用position , 即单个GTID信息表示。在MySQL中使用了表达信息更多的GTID Set , 用GTID集合来表示已经执行的GTID信息。例如某个servergtid_executed为’528c2958-6966-11e8-8cd1-7cd30ac42730:1-9’。

DBA可以在MySQLRESET MASTER后 , 设置gtid_purged来重置gtid_executed信息 , gtid_purged也是GTID集合。在MariaDB中 , RESET MASTER可以通过gtid_binlog_state来重置gtid信息 , 也可以动态设置gtid_slave_pos

MySQL可以设置gtid_next来确定session中下一个执行的GTID。但在session中不可以设置server_id , MySQL这是一个全局变量。在MariaDB中 , 可以在session上设置gtid_domain_idserver_idgtid_seq_no来指定下一个GTID信息。

可以说MariaDBMySQL GTID相比多了domain的概念 , 在server已执行GTID信息表示上 , MariaDB使用的是最后一个执行的GTID来表示 , 而MySQL使用的是GTID Set

2. 复制位点指定

MariaDB除了使用指定master binlog文件名和位点的方式开始replication外 , 还支持通过master_user_gtid来使master自动寻找binlog位点开始同步。

master_user_gtid的指定支持current_posslave_pos两种方式 , 其实位点分别使用gtid_current_posgtid_slave_pos

MariaDBstart_slave_threads的时候会获取要使用的GTID位点到mi->gtid_current_pos中 , 当使用current_pos方式时候 , 和对应变量意义一样 , 会包含binlog写入的GTID信息。当使用slave_pos就只用复制来的slave position来定位。然后通过设置IO线程和Master连接的slave_connect_state变量来告诉Master初始位点。

int start_slave_threads()
{
  if (mi->using_gtid != Master_info::USE_GTID_NO &&
    !mi->slave_running && !mi->rli.slave_running)
  {
    error= rpl_load_gtid_state(&mi->gtid_current_pos, mi->using_gtid ==
                                         Master_info::USE_GTID_CURRENT_POS);
  }
​
}
​
/*
  Load the current GTID position into a slave_connection_state, for use when
  connecting to a master server with GTID.
​
  If the flag use_binlog is true, then the contents of the binary log (if
  enabled) is merged into the current GTID state (master_use_gtid=current_pos).
*/
int
rpl_load_gtid_state(slave_connection_state *state, bool use_binlog)
{
  int err;
  rpl_gtid *gtid_list= NULL;
  uint32 num_gtids= 0;
​
  if (use_binlog && opt_bin_log &&
      (err= mysql_bin_log.get_most_recent_gtid_list(&gtid_list, &num_gtids)))
    return err;
​
  err= state->load(rpl_global_gtid_slave_state, gtid_list, num_gtids);
  my_free(gtid_list);
​
  return err;
}
​
static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi)
{
  query_str.append(STRING_WITH_LEN("SET @slave_connect_state='"),
                 system_charset_info);
  if (mi->gtid_current_pos.append_to_string(&query_str))
  {
  }
}

从表达意义上 , MariaDBgtid_current_posMySQLgtid_executed更像 , 表达了执行过的GTID , 而不只是复制来的。而且gtid_current_pos可以在server没有做过slave, slave_pos为空的情况下自动开始复制。

但是MariaDBgtid_current_pos仅带有每个domain上的位点信息 , 主要是sequence number。如果MasterSlave搭建的是双向同步通道 , 当MasterSlave之间复制关系中断一下 , 在恢复之前Master上有写入 , 那么就会出现当Master上再次start slave , 这个时候搭建复制关系的时候sequence number比对端大 , 就会出现复制中断。宕机HA切换后 , 新Master上有写入或者老的Master有数据未同步到 , 再和重新启动的slave之间搭建复制关系也很容易出错。

例如在双向复制建立的情况下 , 当数据完全同步后 , 做如下操作 , 就会看到对应报错信息。

server_id 161003
stop slave;
​
server_id 161002
stop slave;
insert into t values(10);
start slave;
​
这时候show slave status可以看到报错
Got fatal error 1236 from master when reading data from binary log: 'Error: connecting slave requested to start from GTID 0-161002-2, which is not in the master's binlog'

如果使用slave_pos , 就不会出现上述问题。

2.1 与MySQL不同

MySQL可以用MASTER_AUTO_POSITION1 , 自动使用retrieved_set来作为位点标识。当retrieved_set集合并不是Master端子集的时候并不会导致IO线程报错。所以上述master_posMariaDB中的问题并不会出现在MySQL中。

3. MariaDB并发复制

MariaDB中仅记录了最后一个应用的binlog position信息 , 在并发复制的时候 , MariaDB设计的是会保证同一个domainsequence number的单调递增。其并发也是在这一前提下实现的。

并发参数slave_parallel_mode的可以配置的值有none, minimal, conservative, optimistic, aggressive

  • none : 取消并发复制。

  • minimal : 只有在事务commit阶段并发。

  • conservative : 在主库group commit的事务可以在slave并发执行。

  • optimistic : 乐观的并发方式 , 尽可能的并发执行事务 , 对于发生冲突的事务做回滚操作 , 然后让前面的事务执行完 , 再重试后面的事务。在已知冲突事务比较少的时候使用。

  • aggressive : optimistic的时候 , 如果在master上发生锁等待 , 或者设置了skip_parallel_replication , 那么在slave上执行的时候 , 事务时不会并发的。但如果设置为aggressive , 就依然会并发执行这些操作。

3.1 与MySQL的不同

MySQL5.7中可以通过设置slave_parallel_type指定并发方式为DATABASE或者LOGICAL_CLOCK

指定DATABASE方式 , 即按照事务涉及到的DB Name做并发 , 可以很容易根据该模式改为基于TableName

指定LOGICAL_CLOCK方式 , 可以按照主库执行时候存在加锁重叠 , 即在主库执行明确不会有冲突的情况就可以并发。可以参考月报MySQL 5.7 LOGICAL_CLOCK 并行复制原理及实现分析。

同时MySQL中并发执行的时候 , 在binlog中记录的event group顺序是可以和主库不一样的 , gtid_executed在中间时刻可能存在空洞。

mariadb gtid 复制 - 鱼儿也疯狂 - 博客园

4. 配置一主一从的gtid复制

环境:

主机IP

OS版本

MySQL版本

角色(master/slave)

数据状态

192.168.71.7

Rocky9

Mariadb 11.4.4

master_gtid

全新实例

192.168.71.11

Rocky9

Mariadb 11.4.4

slave1_gtid

全新实例

这里为了实验,重新删除原本的mairadb的数据信息

[root@master02 ~]# rm -rf /var/lib/mysql/*

之后重新生成新的系统数据库信息

[root@master02 ~]# mariadb-install-db --user mysql
Installing MariaDB/MySQL system tables in '/var/lib/mysql' ...
OK

To start mariadbd at boot time you have to copy
support-files/mariadb.service to the right place for your system


Two all-privilege accounts were created.
One is root@localhost, it has no password, but you need to
be system 'root' user to connect. Use, for example, sudo mysql
The second is root@localhost, it has no password either, but
you need to be the system 'root' user to connect.
After connecting you can set the password, if you would need to be
able to connect as any of these users with a password and without sudo

See the MariaDB Knowledgebase at https://mariadb.com/kb

You can start the MariaDB daemon with:
cd '/usr' ; /usr/bin/mariadbd-safe --datadir='/var/lib/mysql'

You can test the MariaDB daemon with mariadb-test-run.pl
cd '/usr/share/mariadb-test' ; perl mariadb-test-run.pl

Please report any problems at https://mariadb.org/jira

The latest information about MariaDB is available at https://mariadb.org/.

Consider joining MariaDB's strong and vibrant community:
https://mariadb.org/get-involved/

之后直接启动即可

systemctl start maridb

主节点配置文件, 基本上和传统的主从模式配置一样

[mysqld]
log-bin=master-bin
sync-binlog=1
server-id=7
binlog_format=ROW  
skip-name-resolve 

从节点配置文件,

[mysqld]
log-bin=slave-bin
relay_log=relay-log    
server-id=11
read-only                                            
binlog_format=row     

配置专门用户复制的用户

MariaDB [(none)]> CREATE USER repl@'192.168.71.%' IDENTIFIED BY 'P@ssword01!';
Query OK, 0 rows affected (0.012 sec)

MariaDB [(none)]>  GRANT replication slave on *.* to repl@'192.168.71.%';
Query OK, 0 rows affected (0.009 sec)

因为master上的binlog没有删除过 , 所以在slave上直接change master to配置连接参数。

MariaDB [(none)]> CHANGE MASTER TO
 MASTER_HOST='192.168.71.7',
 MASTER_USER='repl',
 MASTER_PASSWORD='P@ssword01!',
 MASTER_PORT=3306,
 MASTER_USE_GTID=slave_pos;
 
MariaDB [(none)]> start replica;
Query OK, 0 rows affected (0.023 sec)

可以看到正常启动之后slave状态

MariaDB [(none)]> show slave status \G;
*************************** 1. row ***************************
                Slave_IO_State: Waiting for master to send event
                   Master_Host: 192.168.71.7
                   Master_User: repl
                   Master_Port: 3306
                 Connect_Retry: 60
               Master_Log_File: master-bin.000001
           Read_Master_Log_Pos: 1259
                Relay_Log_File: relay-log.000002
                 Relay_Log_Pos: 1559
         Relay_Master_Log_File: master-bin.000001
              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: 1259
               Relay_Log_Space: 1862
               Until_Condition: None
                Until_Log_File: 
                 Until_Log_Pos: 0
            Master_SSL_Allowed: Yes
            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: Yes
                 Last_IO_Errno: 0
                 Last_IO_Error: 
                Last_SQL_Errno: 0
                Last_SQL_Error: 
   Replicate_Ignore_Server_Ids: 
              Master_Server_Id: 7
                Master_SSL_Crl: 
            Master_SSL_Crlpath: 
                    Using_Gtid: Slave_Pos
                   Gtid_IO_Pos: 0-7-6
       Replicate_Do_Domain_Ids: 
   Replicate_Ignore_Domain_Ids: 
                 Parallel_Mode: optimistic
                     SQL_Delay: 0
           SQL_Remaining_Delay: NULL
       Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
              Slave_DDL_Groups: 4
Slave_Non_Transactional_Groups: 2
    Slave_Transactional_Groups: 0
          Replicate_Rewrite_DB: 
1 row in set (0.001 sec)

5. 添加一个新从节点

这里会像上一篇文章一样删除掉部分二进制日志, 然后再实现新的从节点加入到之前的主从复制中

目前master上的binlog使用情况如下 , 不难发现绝大多数操作都集中在master-bin.000001这个binlog中。

[root@master01 ~]# ll /var/lib/mysql/*bin*
-rw-rw---- 1 mysql mysql 10057349 Dec 15 02:33 /var/lib/mysql/master-bin.000001
-rw-rw---- 1 mysql mysql        0 Dec 15 01:26 /var/lib/mysql/master-bin.000001.idx
-rw-rw---- 1 mysql mysql       20 Dec 15 01:26 /var/lib/mysql/master-bin.index

purge已有的binlog

MariaDB [(none)]> flush logs;
Query OK, 0 rows affected (0.025 sec)

MariaDB [(none)]>  PURGE BINARY logs to 'master-bin.000002';
Query OK, 0 rows affected (0.018 sec)
[root@master01 ~]# cat /var/lib/mysql/master-bin.index 
./master-bin.000002

环境

主机IP

OS版本

MySQL版本

角色(master/slave)

数据状态

192.168.71.7

Rocky9

Mariadb 11.4.4

master_gtid

purgebinlog

192.168.71.11

Rocky9

Mariadb 11.4.4

slave1_gtid

已同步

192.168.71.29

Rocky9

Mariadb 11.4.4

slave2_gtid

全新实例

其中slave2的配置文件和slave1的配置文件完全相同 :

[mysqld]
log-bin=slave-bin
relay_log=relay-log    
server-id=29
read-only                                            
binlog_format=row     

这里需要使用mariadb-backup备份主节点已经生成的数据库

  1. 备份master

    # master上执行 , 备份所有数据 : 
    [root@master ~]# mkdir /backdir   # 备份目录
    [root@master01 ~]# mariadb-backup -uroot -pP@ssword01! --backup --target-dir=/backdir  # 准备数据
    [root@master01 ~]# scp /backdir root@192.168.71.29:/tmp/
  2. 将备份恢复到slave2

    slave2上执行 :

    [root@slave02 ~]# systemctl stop mariadb
    [root@slave02 ~]# rm -rf /var/lib/mysql/*                               # 恢复前必须先清空数据目录
    [root@slave02 ~]# mariadb-backup --prepare --target-dir=/tmp/backdir/   # 预准备备份数据
    [root@slave02 ~]# mariadb-backup --copy-back --target-dir=/tmp/backdir/ #复制到数据库目录
    [root@slave02 ~]# chown -R mysql.mysql /var/lib/mysql/
    [root@slave02 ~]# systemctl start mariadb
  3. 设置gtid_slave_pos , 连接master , 开启复制功能。

    由于mariabackup备份数据集却不备份binlog , 所以必须先获取此次备份结束时的最后一个事务ID , 并在slave上明确指定跳过这些事务 , 否则slave会再次从master上复制这些binlog并执行 , 导致数据重复执行。

    可以从slave2数据目录中的mariadb_backup_info 文件中获取。如果不是mariabackup备份的 , 那么可以直接从mastershow global variables like "gtid_binlog_pos";中获取 , 它表示master中已执行过的事务。

    [root@slave02 ~]# cat /var/lib/mysql/mariadb_backup_info 
    uuid = 74cbe163-ba4c-11ef-8546-fa163e63ccf1
    name = 
    tool_name = mariadb-backup
    tool_command = -uroot -p... --backup --target-dir=/backdir
    tool_version = 11.4.4-MariaDB
    ibbackup_version = 11.4.4-MariaDB
    server_version = 11.4.4-MariaDB-log
    start_time = 2024-12-15 02:51:30
    end_time = 2024-12-15 02:51:40
    lock_time = 0
    binlog_pos = filename 'master-bin.000002', position '387', GTID of the last change '0-7-59'
    innodb_from_lsn = 0
    innodb_to_lsn = 47717
    partial = N
    incremental = N
    format = file
    compressed = N

    其中binlog_pos中的GTID对应的就是已备份的数据对应的事务。换句话说 , 这里的gtid集合0-7-59表示这59个事务不需要进行复制。

    可以在启动slave线程之前使用gtid_purged变量来指定需要跳过的gtid集合。

    MariaDB [(none)]> reset master ;
    Query OK, 0 rows affected (0.032 sec)
    
    MariaDB [(none)]> set global gtid_slave_pos='0-7-59';
    Query OK, 0 rows affected (0.031 sec)

    设置好gtid_slave_pos之后 , 就可以开启复制线程了。

    MariaDB [(none)]> CHANGE MASTER TO
     MASTER_HOST='192.168.71.7',
     MASTER_USER='repl',
     MASTER_PASSWORD='P@ssword01!',
     MASTER_PORT=3306,
     MASTER_USE_GTID=slave_pos;
     
    
    MariaDB [(none)]> start slave;
    Query OK, 0 rows affected (0.039 sec)

    这里主从复制就已经配置完成

    MariaDB [(none)]> show slave status \G ;
    *************************** 1. row ***************************
                    Slave_IO_State: Waiting for master to send event
                       Master_Host: 192.168.71.7
                       Master_User: repl
                       Master_Port: 3306
                     Connect_Retry: 60
                   Master_Log_File: master-bin.000002
               Read_Master_Log_Pos: 387
                    Relay_Log_File: relay-log.000002
                     Relay_Log_Pos: 687
             Relay_Master_Log_File: master-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: 387
                   Relay_Log_Space: 990
                   Until_Condition: None
                    Until_Log_File: 
                     Until_Log_Pos: 0
                Master_SSL_Allowed: Yes
                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: Yes
                     Last_IO_Errno: 0
                     Last_IO_Error: 
                    Last_SQL_Errno: 0
                    Last_SQL_Error: 
       Replicate_Ignore_Server_Ids: 
                  Master_Server_Id: 7
                    Master_SSL_Crl: 
                Master_SSL_Crlpath: 
                        Using_Gtid: Slave_Pos
                       Gtid_IO_Pos: 0-7-59
           Replicate_Do_Domain_Ids: 
       Replicate_Ignore_Domain_Ids: 
                     Parallel_Mode: optimistic
                         SQL_Delay: 0
               SQL_Remaining_Delay: NULL
           Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
                  Slave_DDL_Groups: 0
    Slave_Non_Transactional_Groups: 0
        Slave_Transactional_Groups: 0
              Replicate_Rewrite_DB: 
    1 row in set (0.001 sec)

6. mariadb其他使用

6.1 GTID 复制与传统复制切换

mariadbgtid配置方式与MySQL不相同,二者之间不兼容。MaraDB10.0.2之后的版本默认是启用的,即使从服务器使用的是binlogposition进行主从复制,但他仍是采用GTID进行追踪,所以进行GTID与传统复制进行切换的时候 ,直接使用master_use_gtid的参数进行切换即可

  1. GTID复制切换到传统复制

    stop slave;
    
    change master to master_use_gtid=no;
    
    start slave;
    
    show slave status\G 
    Using_Gtid: No 可以确认已经由GTID复制切换到传统复制。
    
    show slave status\G
  2. 传统复制切换到GTID复制

    stop slave;
    
    change master to master_host='IP',master_port=3306,master_user='rep',master_password='xxx',master_use_gtid=slave_pos;
    
    或者
    
    change master to master_host='IP',master_port=3306,master_user='rep',master_password='xxx',master_use_gtid=current_pos;
    
    start slave;
    
    show slave status\G
    
    确认复制已经切换成功。
    
    可以开启 gtid_strict_mode 防止从库做了更新,主库确不知道.如果从库更新,同步就会报错.目前是关闭状态
    set global gtid_strict_mode=on;
  3. master_use_gtid = { slave_pos | current_pos | no }有3种选项:

    slave_pos:slaveMaster最后一个GTIDposition复制到本地,Slave主机可通过gtid_slave_pos变量查看最后一个GTIDposition

    current_pos假设有AB两台主机,AMaster,当A故障后,B成为MasterA修复后以Slave的身份重新添加,A之前从没担任过slave角色,所以没有之前复制的GTID号,此时gtid_slave_pos为空,为了能让A能自动添加为Slave,此时就用到该选项。该选项是大多数情况下使用的选项,因为他简单易用,不必在意服务器之前是Master还是Slave角色。但要注意不要让从服务器在binlog日志中写入事务。

    建议在服务器上启用gtid_strict_mode,这样非Master产生的事物将被拒绝。如果从服务器没有开启binlog上面两种方式等价。

    no关闭GTID功能

6.2 主从GTID复制结构中Master切换

A(M)-->B(S) 切换为 A(S)<--B(M) 结构

主从GTID复制结构中Master切换非常简单。

1、先确认从库B已经完全追上主库A

Master_Log_File: mysql-bin.000056 = Relay_Master_Log_File: mysql-bin.000056 && Read_Master_Log_Pos: 10390 = Exec_Master_Log_Pos: 10390 

2、A 上执行

change master to master_host='B',master_port=,master_user='rep',master_password='xxx',master_use_gtid=current_pos;start slave;

这里把 master_use_gtid 配置成 current_pos。

因为该主库没有做过其他数据库的从库,所以slave_pos为空,需要用current_pos。二者区别可以看后面的定义。


参考链接

数据库内核月报 - 2018/06 - MariaDB · 特性分析 · 基于GTID的复制分析 - 《数据库内核月报》 - 书栈网 · BookStack

mariadb gtid 复制 - 鱼儿也疯狂 - 博客园

熊熊