docker-compose之mysql-router(MGR单主模式)

MGR介绍

MGR 即 MySQL Group Replication

MGR 的特点

高一致性,基于原生复制及 paxos 协议的组复制技术,并以插件的方式提供,提供一致数据安全保证

主从复制分析

传统主从复制,一主多从,主库提供读写功能,从库提供写功能。当一个事务在 master 提交成功时,会把 binlog 文件同步到从库服务器上落地为 relay log 给 slave 端执行,这个过程主库是不考虑从库是否有接收到 binlog 文件,有可能当主库 commit 一个事务后,数据库发生宕机,刚好它的 binlog 还没来得及传送到 slave 端,这个时候任何一个 slave 端都会丢失这个事务,造成数据不一致情况

为了避免出现主从数据不一致的情况,MySQL 引入了半同步复制,添加了从库反馈机制,反馈机制有两种方式:

  1. 主库执行完事务后,同步 binlog 给从库,从库 ack 反馈接收到 binlog,主库提交 commit 反馈给客户端,释放会话

  2. 主库执行完事务后,主库提交 commit,同步 binlog 给从库,从库 ack 反馈接收到 binlog 反馈给客户端,释放会话 但还是有问题,虽然满足了一主多从、读写分离、数据一致,依旧有两个弊端:

  3. 写操作集中在 master 服务器上

  4. master 宕机后,需要人为选择新主并重新给其它的 slave 端执行 change master(可自行写第三方工具实现,但是 mysql 的复制就是没提供,所以也算是弊端)

于是官方于 2016 年 12月 12 日正式发布了 MySQL Group Replication

MGR优点

  1. 可以有多个主节点,在同一个 group 里边的所有实例,每一个实例都可以执行读写操作,需要注意的是,多主情况下,当执行一个事务时,需要确保同个组内的每个实例都认可这个事务无冲突异常,才可以 commit,如果设置的是单主,其它实例 ReadOnly,则不需要进行上面的判断。多主情况下,事务并发冲突问题就凸显出来了,如何避免呢?数据库内部有一个认证程序,当不同实例并发对同一行发起修改,在同个组内广播认可时,会出现并发冲突,那么会按照先执行的提交,后执行的回滚

  2. 弹性,同个 Group Replication 中,节点的加入或者移除都是自动调整,如果新加入一个节点,该节点会自动从 Group 的其他节点同步数据,直到与其他节点一致。如果移除一个节点,那么剩下的实例会自动更新,不再向这个节点广播事务操作,当然,这里要注意,假设一个 Group 的节点有 n 个(max (n) =9,同个 Group 最多节点数为 9)移除或者宕机的节点数应该小于等于( (n-1)/2) 并且是向下取整。如果是单主模式,宕机的是单主,则需要人为选择新主后,其它节点也会自动从新主同步数据

  3. 更高性能的同步机制

一个复制组由若干个节点(数据库实例)组成,组内各个节点维护各自的数据副本(Share Nothing)通过一致性协议 paxos 实现原子消息和全局有序消息,来实现组内实例数据的一致

扩展:paxos 协议,paxos 用于解决分布式系统中一致性问题。分布式一致性算法(Consensus Algorithm)是一个分布式计算领域的基础性问题,其最基本的功能是为了在多个进程之间对某个(某些)值达成一致(强一致)简单来说就是确定一个值,一旦被写入就不可改变。paxos 用来实现多节点写入来完成一件事情。paxos 协议只是一个协议,不是具体的一套解决方案。目的是解决多节点写入问题。paxos 协议用来解决的问题可以用一句话来简化:将所有节点都写入同一个值,且被写入后不再更改

  1. 高容错性,只要不是大多数节点坏掉就可以继续工作,有自动检测机制,当不同节点产生资源争用冲突时,不会出现错误,按照先到者优先原则进行处理,并且内置了自动化脑裂防护机制

  2. 高扩展性,节点的新增和移除都是自动的,新节点加入后,会自动从其他节点上同步状态,直到新节点和其他节点保持一致,如果某节点被移除了,其它节点自动更新组信息,自动维护新的组信息

  3. 高灵活性,有单主模式和多主模式,单主模式下,会自动选主,所有更新操作都在主上进行;多主模式下,所有 server 都可以同时处理更新操作

MGR要求

  1. 引擎必须为 innodb,因为需事务支持在 commit 时对各节点进行冲突检查
  2. 每个表必须有主键,在进行事务冲突检测时需要利用主键值对比
  3. 必须开启 binlog 且为 row 格式
  4. 开启 GTID,且主从状态信息存于表中(–master-info-repository=TABLE 、–relay-log-info-repository=TABLE)–log-slave-updates 打开
  5. 一致性检测设置 –transaction-write-set-extraction=XXHASH64

扩展:什么是 GTID?

GTID (Global Transaction ID) 是对于一个已提交事务的编号,并且是一个全局唯一的编号。GTID 实际上是由 UUID+TID 组成的。其中 UUID 是一个 MySQL 实例的唯一标识。TID 代表了该实例上已经提交的事务数量,并且随着事务提交单递增。GTID 的具体形式如:3E11FA47-71CA-11E1-9E33-C80AA9429562:23

MGR使用限制

  1. 和普通复制 binlog 校验不能共存,需设置 –binlog-checksum=none
  2. 不支持 gap lock(间隙锁)隔离级别需设置为 read_committed
  3. 不支持对表进行锁操作(lock/unlock table)不会发送到其他节点执行,影响需要对表进行加锁操作的情况,列入 mysqldump 全表备份恢复操作
  4. 不支持 serializable(序列化)隔离级别
  5. DDL 语句不支持原子性,不能检测冲突,执行后需自行校验是否一致
  6. 多主模式下不支持外键,单主模式不存在此问题
  7. 最多支持 9 个节点,超过 9 台 server 无法加入组

部署MGR集群

docker-compose.yaml

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
version: "2"
services:
  xbd-cluster-1:
    build:
      context: ./
      dockerfile: ./config/Dockerfile/Dockerfile-cluster
    image: xbd-cluster-1
    restart: always
    container_name: xbd-cluster-1
    volumes:
      - /var/lib/mysql/xbd-cluster-1:/var/lib/mysql
    ports:
      - 3306:3306
    environment:
      - TZ=Asia/Shanghai
      - MYSQL_ROOT_PASSWORD=root
    privileged: true
    command: ['--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=xbd-cluster-1-bin',
              '--binlog_format=ROW',
              '--transaction_write_set_extraction=XXHASH64',
              '--plugin_load_add=group_replication.so',
              '--loose-group_replication_group_name=aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
              '--loose-group_replication_start_on_boot=off',
              '--loose-group_replication_local_address=xbd-cluster-1:33061',
              '--loose-group_replication_group_seeds=xbd-cluster-1:33061,xbd-cluster-2:33062,xbd-cluster-3:33063',
              '--loose-group_replication_bootstrap_group=off',
              '--loose-group_replication_single_primary_mode=on',
              '--loose-group_replication_enforce_update_everywhere_checks=off',
              '--lower_case_table_names=1',
              '--character-set-server=utf8',
              '--collation-server=utf8_general_ci',
              '--sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION']

  xbd-cluster-2:
    build:
      context: ./
      dockerfile: ./config/Dockerfile/Dockerfile-cluster
    image: xbd-cluster-2
    restart: always
    container_name: xbd-cluster-2
    volumes:
      - /var/lib/mysql/xbd-cluster-2:/var/lib/mysql
    ports:
      - 3307:3306
    environment:
      - TZ=Asia/Shanghai
      - MYSQL_ROOT_PASSWORD=root
    privileged: true
    command: ['--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=xbd-cluster-2-bin',
              '--binlog_format=ROW',
              '--transaction_write_set_extraction=XXHASH64',
              '--plugin_load_add=group_replication.so',
              '--loose-group_replication_group_name=aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
              '--loose-group_replication_start_on_boot=off',
              '--loose-group_replication_local_address=xbd-cluster-2:33062',
              '--loose-group_replication_group_seeds=xbd-cluster-1:33061,xbd-cluster-2:33062,xbd-cluster-3:33063',
              '--loose-group_replication_bootstrap_group=off',
              '--loose-group_replication_single_primary_mode=on',
              '--loose-group_replication_enforce_update_everywhere_checks=off',
              '--lower_case_table_names=1',
              '--character-set-server=utf8',
              '--collation-server=utf8_general_ci',
              '--sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION']

  xbd-cluster-3:
    build:
      context: ./
      dockerfile: ./config/Dockerfile/Dockerfile-cluster
    image: xbd-cluster-3
    restart: always
    container_name: xbd-cluster-3
    volumes:
      - /var/lib/mysql/xbd-cluster-3:/var/lib/mysql
    ports:
      - 3308:3306
    environment:
      - TZ=Asia/Shanghai
      - MYSQL_ROOT_PASSWORD=root
    privileged: true
    command: ['--server-id=3',
              '--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=xbd-cluster-3-bin',
              '--binlog_format=ROW',
              '--transaction_write_set_extraction=XXHASH64',
              '--plugin_load_add=group_replication.so',
              '--loose-group_replication_group_name=aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
              '--loose-group_replication_start_on_boot=off',
              '--loose-group_replication_local_address=xbd-cluster-3:33063',
              '--loose-group_replication_group_seeds=xbd-cluster-1:33061,xbd-cluster-2:33062,xbd-cluster-3:33063',
              '--loose-group_replication_bootstrap_group=off',
              '--loose-group_replication_single_primary_mode=on',
              '--loose-group_replication_enforce_update_everywhere_checks=off',
              '--lower_case_table_names=1',
              '--character-set-server=utf8',
              '--collation-server=utf8_general_ci',
              '--sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION']

  xbd-mysql-router:
    build:
      context: ./
      dockerfile: ./config/Dockerfile/Dockerfile-router
    image: xbd-mysql-router
    restart: always
    container_name: xbd-mysql-router
    ports:
      - 6446:6446
      - 6447:6447
    environment:
      - TZ=Asia/Shanghai
      - MYSQL_HOST=xbd-cluster-1
      - MYSQL_PORT=3306
      - MYSQL_USER=root
      - MYSQL_PASSWORD=root
      - MYSQL_INNODB_CLUSTER_MEMBERS=3
    privileged: true
    depends_on:
      - xbd-cluster-1
      - xbd-cluster-2
      - xbd-cluster-3

部署:docker-compose build 运行:docker-compose up -d xbd-cluster-1 xbd-cluster-2 xbd-cluster-3

参考