zoukankan      html  css  js  c++  java
  • MySQL全同步复制基于GR集群架构实现(Centos7)

    一. 理论概述

    概述

    本案例操作的是针对于MySQL的复制类型中的全同步复制,对几种复制类型简单总结下:

    1. 异步复制:MySQL默认的复制类型就是异步复制,主库在执行完客户端提交的事务后会立即将结果返回给客户端.可能出现的问题就是,数据在主库上写入成功,主库返回给客户端结果,主库在这时crash掉了,那很可能,该crash掉的主库数据还没有完全同步到从库,随后,从库提升为新的主库,客户端查询刚才的请求结果没有.
    2. 全同步复制:主库执行完一个事务,所有的从库都执行了该事务才返回给客户端,不足之处是返回客户端的响应速度会变慢
    3. 半同步复制:介于前两者之间主库执行完事务后不会立刻返回客户端,而是至少等待一个从库接收到,并且该从库写到其relay log 中才返回给客户端结果.降低了出错的肯能,同事也相对全同步复制来说减少了一些响应时间,但是也有其不足之处.
      • 问题:客户端事务在存储引擎提交后,在得到从库确认的过程中宕机了,可能有两种情况:
        • 事务还没有发送到从库上: 客户端收到事务提交失败信息,再次重新提交到新的主库上,宕机修复好的主库重新启动之后,是以从库的身份加入到集群中,但是该事务之前该事务就有了,随后又会同步一次.有了两份
        • 事务已经发送到从库上:此时从库已同步完成该该事务,但是由于主库宕机,客户端再次提交事务到新的主库.有了两份
    4. 随之,基于之前版本基础上了loss-less半同步复制,MySQL5.7.2之后的版本支持,引入了一个新的参数进行控制rpl_semi_sync_master_wait_point.
    • 我一直在想可能是修改一些配置就OK了,但是逻辑完全出问题了.由于我要配置的是全同步,网上各大网站的文档,上来就贴配置,思路有没有写,重点是只要设置为相应的模式即是在使用相应的同步策略.
    • 而全同步同步策略的配置方式是基于组复制(GR)实现的接下来就研究一下GR,对GR的实现在大脑里有点思路
    1. MySQL的组复制可以配置为单主模型和多主模型两种工作模式,它们都能保证MySQL的高可用。以下是两种工作模式的特性简介:
      1. 单主模型:从复制组中众多个MySQL节点中自动选举一个master节点,只有master节点可以写,其他节点自动设置为read only。当master节点故障时,会自动选举一个新的master节点,选举成功后,它将设置为可写,其他slave将指向这个新的master。
      2. 多主模型:复制组中的任何一个节点都可以写,因此没有master和slave的概念,只要突然故障的节点数量不太多,这个多主模型就能继续可用。

    参考文章

    本文主要针对于全同步复制

    二. 部署

    二进制包MySQL5.7.24版本

    主机名 IP地址 角色
    master 192.168.111.3 主库
    slave1 192.168.111.4 从库
    slave2 192.168.111.5 从库
    [root@localhost ~]# vim /etc/hosts
    
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    192.168.111.3   master
    192.168.111.4   slave1
    192.168.111.5   slave2
    
    [root@localhost ~]# scp /etc/hosts root@192.168.111.4:/etc/
    root@192.168.111.4's password: 
    hosts                                                                                                             100%  221   170.1KB/s   00:00    
    [root@localhost ~]# scp /etc/hosts root@192.168.111.5:/etc/
    
    [root@localhost ~]# hostname master
    [root@localhost ~]# bash
    [root@master ~]# uname -n
    master
    
    [root@localhost ~]# hostname slave1
    [root@localhost ~]# bash
    [root@slave1 ~]# uname -n
    slave1
    
    [root@localhost ~]# hostname slave2
    [root@localhost ~]# bash
    [root@slave2 ~]# uname -n
    slave2
    
    安装mysql二进制安装
    [root@localhost ~]# yum -y install libaio
    [root@localhost ~]# wget http://mirrors.sohu.com/mysql/MySQL-5.7/mysql-5.7.24-linux-glibc2.12-x86_64.tar.gz
    [root@localhost ~]# tar zxf mysql-5.7.24-linux-glibc2.12-x86_64.tar.gz 
    [root@localhost ~]# mv mysql-5.7.24-linux-glibc2.12-x86_64 /usr/local/mysql
    
    [root@localhost mysql]# /usr/local/mysql/bin/mysqld --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --initialize
    将随机生成的登录密码记录下来
    2019-05-18T08:43:11.094845Z 1 [Note] A temporary password is generated for root@localhost: 2Gk75Zvp&!-y
    
    
    • 配置
    主库操作
    新建配置文件
    [root@localhost ~]# vim /etc/my.cnf 
    
    [root@localhost ~]# uuidgen
    5f21777b-9a91-457e-9f0a-33ceba505a24
    #查看uuid
    [root@localhost ~]# /etc/init.d/mysqld stop
    #所有机器关掉服务
    [root@localhost ~]# rm -rf /usr/local/mysql/data/*
    #全部如此操作,删除数据目录下所有文件
    [root@localhost ~]# vim /etc/my.cnf 
    
    [mysqld]
    server-id=1
    #这些设置将server配置为使用唯一标识号,以启动全局事物标示符号
    datadir=/usr/local/mysql/data
    socket=/tmp/mysql.sock
    gtid_mode=ON
     #打开gtid保证半同步,因为组复制基于GTID,所以必须开启gtid_mode和enforce_gtid_consistency
    enforce_gtid_consistency=ON
    #强制持续打开
    relay_log_info_repository=TABLE
    master_info_repository=TABLE
    #master的信息存放在系统表中,而不是文件中;组复制要将master和relay log的元数据写入到mysql.slave_master_info和mysql.slave_relay_log_info中
    binlog_checksum=NONE
    #它设置 server 打开二进制日志记录,使用基于行的格式并禁用二进制日志事件校验和;由于MySQL对复制事件校验的设计缺陷,组复制不能对他们校验,所以设置binlog_checksum=none
    log-bin=mysql-binlog
    #二进制日志文件功能开启
    sync-binlog=1
    #sync_binlog是为了保证每次事务提交都立刻将binlog刷盘,保证出现故障也不丢失日志。
    binlog_format=ROW
    #二进制文件格式
    log-slave-updates=ON
    #组中的每个节点都保留了完整的数据副本,它是share-nothing的模式。所以所有节点上都必须开启log_slave_updates,这样新节点随便选哪个作为donor都可以进行异步复制。
    transaction_write_set_extraction=XXHASH64
    #server必须为每个事务收集写集合,并使用 XXHASH64哈希算法将其编码为散列。
    loose-group_replication_group_name="5f21777b-9a91-457e-9f0a-33ceba505a24"
    #告知插件,正在加入或创建的组要命名为5f21777b-9a91-457e-9f0a-33ceba505a24
    loose-group_replication_start_on_boot=off
    #server 启动时不自动启动组复制。
    loose-group_replication_local_address="192.168.111.3:24901"
    #插件使用的ip地址,端口用于接受来自组中其他成员的传入连接
    loosegroup_replication_group_seeds="192.168.111.3:24901,192.168.111.4:24902,192.168.111.5:24903" 
    #种子成员,集群内所有成员的IP及端口,注意端口一样的话报错,不知为啥
    loose-group_replication_bootstrap_group=off
    #插件是否自动引导,注意此选项在任何时候只能在一个 server 实例上使用,通常是首次引导组时(或在整个组被崩溃然后恢复的情况下)。 如果您多次引导组,例如,当多个 server 实例设置了此选项,则它们可能会人为地造成脑裂的情况,其中存在两个具有相同名称的不同组。 在第一个server 实例加入组后禁用此选项。组中的所有 server 成员的配置都非常相似。(此配置项如报错,就删除)
    loose-group_replication_member_weigth = 40
    #设置该节点的权重,MySQL5.7.20以后版本才支持,否则就不配置,会根据uuid来选举master
    
    
    
    [root@localhost ~]# /usr/local/mysql/support-files/mysql.server start
    Starting MySQL.Logging to '/usr/local/mysql/data/mysql.log'.
     SUCCESS! 
    [root@localhost ~]# netstat -lnpt | grep 3306
    tcp6       0      0 :::3306                 :::*                    LISTEN      64636/mysqld 
    
    
    [root@localhost mysql]# cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
    #添加到系统服务
    
    [root@localhost mysql]# ln -s /usr/local/mysql/bin/* /usr/local/bin/
    #便于使用
    
    [root@master ~]# mysqladmin -u root -p'2Gk75Zvp&!-y' password '123456'
    mysqladmin: [Warning] Using a password on the command line interface can be insecure.
    Warning: Since password will be sent to server in plain text, use ssl connection to ensure password safety.
    [root@master ~]# mysql -uroot -p123456
    #更改密码,连接数据库
    
    mysql> grant replication slave on *.* to rep@'192.168.111.%' identified by'123456';
    Query OK, 0 rows affected, 1 warning (0.30 sec)
    
    mysql> flush privileges;
    Query OK, 0 rows affected (0.00 sec)
    #授权用户
    
    • 配置节点加组时的通道。这是组复制的一个关键。
    在新节点加入组时,首先要选择donor。新节点和donor之间的异步复制就是通过一个名为group_replication_recovery的通道(通道名固定,不可使用自定义通道)进行数据恢复的,经过数据恢复后,新节点填充了它缺失的那部分数据,这样就和组内其他节点的数据保持了同步。
    mysql> change master to master_user='rep',master_password='123456' for channel 'group_replication_recovery';
    #也可以称之为专门的术语:通道凭据(channel credentials)
    #当执行完上面的语句后,就生成了一个该通道的relay log文件(注意称呼:该通道的relay log,后面还有另一个通道的relaylog)。如下,其中前缀"relay-log"是配置文件中"relay_log"选项配置的值。
    #group_replication_recovery通道的relay log用于新节点加入组时,当新节点联系上donor后,会从donor处以异步复制的方式将其binlog复制到这个通道的relaylog中,新节点将从这个recovery通道的relay log中恢复数据。
    
    • 前面配置文件中已经指定了master和relay log的元数据信息要记录到表中,所以这里可以先查看下关于relay log的元数据。
    mysql> select * from mysql.slave_relay_log_infoG;
    *************************** 1. row ***************************
      Number_of_lines: 7
       Relay_log_name: ./master-relay-bin-group_replication_recovery.000001
        Relay_log_pos: 4
      Master_log_name: 
       Master_log_pos: 0
            Sql_delay: 0
    Number_of_workers: 0
                   Id: 1
         Channel_name: group_replication_recovery
    1 row in set (0.01 sec)
    
    • 开启mysql实例的组复制功能
    mysql> install plugin group_replication soname 'group_replication.so';
    Query OK, 0 rows affected (0.03 sec)
    #安装该插件
    mysql> set @@global.group_replication_bootstrap_group=on;
    Query OK, 0 rows affected (0.00 sec)
    #这表示稍后启动的组复制功能将引导组,也就是创建组并配置组,这些都是自动的。配置引导变量为ON后,再开启组复制插件功能,也就是启动组复制。最后将引导变量设回OFF,之所以要设置回OFF,是为了避免下次重启组复制插件功能时再次引导创建一个组,这样会存在两个名称相同实际却不相同的组。
    mysql> start group_replication;
    Query OK, 0 rows affected (2.35 sec)
    #启动组复制
    mysql> set @@global.group_replication_bootstrap_group=off;
    Query OK, 0 rows affected (0.00 sec)
    

    这几个过程不适合放进配置文件中,强烈建议手动执行它们的。否则下次重启mysql实例时,会自动重新引导创建一个组。同理,除了第一个节点,其他节点启动组复制功能时,不应该引导组,所以只需执行其中的start语句,千万不能开启group_replication_bootstrap_group变量引导组

    这里的几个过程,应该形成一个习惯,在启动第一个节点时,这3条语句同时执行,在启动其他节点时,只执行start语句。

    至此,这个节点的组复制已经配置完成了。现在需要查看这个节点是否成功加入到组中,成功加入组的标志是被设置为"ONLINE"。只要没有设置为ONLINE,就表示组中的这个节点是故障的。

    mysql> select * from performance_schema.replication_group_membersG;
    *************************** 1. row ***************************
    CHANNEL_NAME: group_replication_applier
       MEMBER_ID: f7a5022e-7948-11e9-a40e-000c2935c4a6
     MEMBER_HOST: master
     MEMBER_PORT: 3306
    MEMBER_STATE: ONLINE
    1 row in set (0.00 sec)
    #member_host,它是对外连接的地址
    

    稍后加入其余两个节点,加入之前顺便测试一下开启组复制后,必须使用InnoDB、表中必须有主键的限制。

    下面创建4个表:t1和t4是InnoDB表,t3和t4具有主键。

    mysql> create database test;
    mysql> use test;
    Database changed
    mysql> create table t1(id int);
    mysql> create table t2(id int)engine=myisam;
    mysql> create table t3(id int primary key)engine=myisam;
    mysql> create table t4(id int primary key);
    mysql> insert into t1 values(1);
    ERROR 3098 (HY000): The table does not comply with the requirements by an external plugin.
    mysql> insert into t2 values(1);
    ERROR 3098 (HY000): The table does not comply with the requirements by an external plugin.
    mysql> insert into t3 values(1);
    ERROR 3098 (HY000): The table does not comply with the requirements by an external plugin.
    mysql> insert into t4 values(1);
    Query OK, 1 row affected (0.00 sec)
    
    #不支持非innodb存储引擎,和没有主键
    

    向组加入新节点

    • 生产环境有许多需要考虑的因素:对于一台已经运行许久的数据库,该数据库已经有大量数据文件,依靠组复制,复制大量数据,速度会非常慢,可以先通过备份恢复的方式,恢复到本地,在依靠组复制进行

    slave2:

    [root@slave1 ~]# vim /etc/my.cnf 
    
    [mysqld]
    server-id=2 #修改
    gtid_mode=ON
    enforce_gtid_consistency=ON
    master_info_repository=TABLE
    relay_log_info_repository=TABLE
    binlog_checksum=NONE
    log-bin=mysql-binlog
    log-slave-updates=ON
    binlog_format=ROW
    sync-binlog=1
    datadir=/usr/local/mysql/data
    socket=/tmp/mysql.sock
    transaction_write_set_extraction=XXHASH64
    loose-group_replication_group_name="5f21777b-9a91-457e-9f0a-33ceba505a24"
    loose-group_replication_start_on_boot=off
    loose-group_replication_local_address="192.168.111.4:24902" #修改为本机
    loose-group_replication_group_seeds="192.168.111.3:24901,192.168.111.4:24902,192.168.111.5:24903"
    loose-group_replication_member_weigth = 20 #修改
    [mysqld_safe]
    log-error=/usr/local/mysql/data/mysql.log
    pid-file=/usr/local/mysql/data/mysql.pid
    
    mysql> change master to master_user='rep',master_password='123456' for channel 'group_replication_recovery';
    
    #到master上查看新加入的节点
    mysql> select * from mysql.slave_master_infoG;
    *************************** 1. row ***************************
           Number_of_lines: 25
           Master_log_name: 
            Master_log_pos: 4
                      Host: <NULL>
                 User_name: 
             User_password: 
                      Port: 0
             Connect_retry: 60
               Enabled_ssl: 0
                    Ssl_ca: 
                Ssl_capath: 
                  Ssl_cert: 
                Ssl_cipher: 
                   Ssl_key: 
    Ssl_verify_server_cert: 0
                 Heartbeat: 30
                      Bind: 
        Ignored_server_ids: 0
                      Uuid: 
               Retry_count: 86400
                   Ssl_crl: 
               Ssl_crlpath: 
     Enabled_auto_position: 1
              Channel_name: group_replication_applier
               Tls_version: 
    *************************** 2. row ***************************
           Number_of_lines: 25
           Master_log_name: 
            Master_log_pos: 4
                      Host: 
                 User_name: rep
             User_password: 123456
                      Port: 3306
             Connect_retry: 60
               Enabled_ssl: 0
                    Ssl_ca: 
                Ssl_capath: 
                  Ssl_cert: 
                Ssl_cipher: 
                   Ssl_key: 
    Ssl_verify_server_cert: 0
                 Heartbeat: 0
                      Bind: 
        Ignored_server_ids: 0
                      Uuid: 
               Retry_count: 86400
                   Ssl_crl: 
               Ssl_crlpath: 
     Enabled_auto_position: 0
              Channel_name: group_replication_recovery
               Tls_version: 
    mysql> install plugin group_replication soname 'group_replication.so';
    mysql> start group_replication;
    
    

    slave3:

    [root@slave2 ~]# vim /etc/my.cnf 
    
    [mysqld]
    server-id=3
    gtid_mode=ON
    enforce_gtid_consistency=ON
    master_info_repository=TABLE
    relay_log_info_repository=TABLE
    binlog_checksum=NONE
    log-bin=mysql-binlog
    log-slave-updates=ON
    binlog_format=ROW
    sync-binlog=1
    datadir=/usr/local/mysql/data
    socket=/tmp/mysql.sock
    transaction_write_set_extraction=XXHASH64
    loose-group_replication_group_name="5f21777b-9a91-457e-9f0a-33ceba505a24"
    loose-group_replication_start_on_boot=off
    loose-group_replication_local_address="192.168.111.4:24903"
    loose-group_replication_group_seeds="192.168.111.3:24901,192.168.111.4:24902,192.168.111.5:24903"
    loose-group_replication_member_weigth = 10
    [mysqld_safe]
    log-error=/usr/local/mysql/data/mysql.log
    pid-file=/usr/local/mysql/data/mysql.pid
    
    mysql> change master to master_user='rep',master_password='123456' for channel 'group_replication_recovery';
    
    #到master上查看新加入的节点
    
    
    mysql> change master to master_user='rep',master_password='123456' for channel 'group_replication_recovery';
    mysql> select * from mysql.slave_master_infoG;
    mysql> install plugin group_replication soname 'group_replication.so';
    mysql> start group_replication;
    
    
    mysql> select * from performance_schema.replication_group_membersG
    *************************** 1. row ***************************
    CHANNEL_NAME: group_replication_applier
       MEMBER_ID: 72d428ee-7980-11e9-b073-000c2935c4a6
     MEMBER_HOST: master
     MEMBER_PORT: 3306
    MEMBER_STATE: ONLINE
    *************************** 2. row ***************************
    CHANNEL_NAME: group_replication_applier
       MEMBER_ID: 73d663df-62c0-11e9-9efa-000c2919fb90
     MEMBER_HOST: slave2
     MEMBER_PORT: 3306
    MEMBER_STATE: ONLINE
    *************************** 3. row ***************************
    CHANNEL_NAME: group_replication_applier
       MEMBER_ID: 7895461d-6984-11e9-bd58-000c294b0234
     MEMBER_HOST: slave1
     MEMBER_PORT: 3306
    MEMBER_STATE: ONLINE
    3 rows in set (0.00 sec)
    
    
    • slave1和slave2查看数据是否同步
    mysql> show tables from test;
    +----------------+
    | Tables_in_test |
    +----------------+
    | t1             |
    | t2             |
    | t3             |
    | t4             |
    +----------------+
    4 rows in set (0.00 sec)
    

    测试

    • 查找主节点
    mysql> select b.member_host the_master,a.variable_value master_uuid
        ->     from performance_schema.global_status a
        ->     join performance_schema.replication_group_members b
        ->     on a.variable_value = b.member_id
        ->     where variable_name='group_replication_primary_member';
    +------------+--------------------------------------+
    | the_master | master_uuid                          |
    +------------+--------------------------------------+
    | master     | 72d428ee-7980-11e9-b073-000c2935c4a6 |
    
    
    • 节点离组和选举新节点(最少3个节点的环境)

    当前是master是主,我将网卡关掉模拟故障

    [root@master ~]# ifdown ens32
    
    slave1:上查看日志
    
    2019-04-28T07:53:59.922705Z 0 [Warning] Plugin group_replication reported: 'Member with address master:3306 has become unreachable.'
    2019-04-28T07:54:00.179220Z 0 [Note] Plugin group_replication reported: '[GCS] Removing members that have failed while processing new view.'
    2019-04-28T07:54:00.927598Z 0 [Warning] Plugin group_replication reported: 'Members removed from the group: master:3306'
    2019-04-28T07:54:00.927632Z 0 [Note] Plugin group_replication reported: 'Primary server with address master:3306 left the group. Electing new Primary.'2019-04-28T07:54:00.927750Z 0 [Note] Plugin group_replication reported: 'A new primary with address slave2:3306 was elected, enabling conflict detection until the new primary applies all relay logs.'2019-04-28T07:54:00.927928Z 28 [Note] Plugin group_replication reported: 'This server is working as secondary member with primary member address slave2:3306.'2019-04-28T07:54:00.928013Z 0 [Note] Plugin group_replication reported: 'Group membership changed to slave2:3306, slave1:3306 on view 15581931615697484:7.'
    
    mysql> select b.member_host the_master,a.variable_value master_uuid from performance_schema.global_status a join performance_schema.replication_group on a.variable_value = b.member_id   
    +------------+--------------------------------------+
    | the_master | master_uuid                          |
    +------------+--------------------------------------+
    | slave2     | 73d663df-62c0-11e9-9efa-000c2919fb90 |
    +------------+--------------------------------------+
    1 row in set (0.00 sec)
    
    

    可以看到slave2已经切换为主了

    三.总结

    1. 本来就想着做一个MySQL的全同步复制类型,毕竟对于业务数据安全要求极其苛刻情况下,这点延时是可以接受的
    2. 结果就做了mysql组复制,非常感谢这篇文档受益匪浅.
    3. 最后测试,个人感觉也是没有做的很到位,首先,这点时间延迟,在测试环境中不太容易测出.
    4. 个人对于整个组复制高可用集群还是理解不够透彻,据说是mysql官方极力推荐的,如果以后用到,一定下点成本.
  • 相关阅读:
    OpenGL纹理数据块
    MFC应用真彩色图标资源
    PictureConverter命令行图片批量转换工具
    Google Earth6.1 tree
    OpenGL Render On Window Process
    纹理滤波(Texture Filter)
    使用开源OpenCTM进行常用三维格式互导
    《搅基辞》
    访问WebDAV服务
    linux 挂载一个文件夹到另一个文件夹
  • 原文地址:https://www.cnblogs.com/jojoword/p/10887827.html
Copyright © 2011-2022 走看看