mysql8.0高可用集群架构实战

MySQL :: MySQL Shell 8.0 :: 7 MySQL InnoDB Cluster

基本概述

InnoDB Cluster是MySQL官方实现高可用+读写分离的架构方案,其中包含以下组件

  • MySQL Group Replication,简称MGR,是MySQL的主从同步高可用方案,包括数据同步及角色选举
  • Mysql Shell 是InnoDB Cluster的管理工具,用来创建和管理集群
  • Mysql Router 是业务流量入口,支持对MGR的主从角色判断,可以配置不同的端口分别对外提供读写服务,实现读写分离

MySQL Router与组复制和MySQL Shell高度整合,只有将其与组复制和MySQL Shell共同使用,才能够称为InnoDB Cluster。

集群架构

nnoDB Cluster将三个MySQL数据库实例构成一个高可用集群。其中一个实例是具有读/写能力的主要成员,其他两个实例是具有只读能力的次要成员。组复制将数据从主要成员复制到次要成员。MySQL Router将客户端应用程序连接到集群的主要成员。

搭建一主两从InnoDB集群
1. 安装3个数据库实例

参考:Docker 安装 MySQL8.0 

可以利用docker快速部署3个MySQL实例

# 创建组复制的网络  保证三个mysql容器之间可以通过容器名访问
docker network create --driver bridge --subnet 172.19.0.0/24 --gateway 172.19.0.1 mgr-network

mkdir -p /mysql/mgr/node1/data /mysql/mgr/node1/conf /mysql/mgr/node1/log
mkdir -p /mysql/mgr/node2/data /mysql/mgr/node2/conf /mysql/mgr/node2/log
mkdir -p /mysql/mgr/node3/data /mysql/mgr/node3/conf /mysql/mgr/node3/log

#以mgr-node1配置为例,创建/mysql/mgr/node1/conf/custom.cnf,添加以下配置:
vim /mysql/mgr/node1/conf/custom.cnf
[mysql]
# 设置mysql客户端默认编码
default-character-set=utf8
[mysqld]
#指定sever_id,三个Mysql实例需要分别改为对应的sever_id
server_id=1
# 必须开启GTID支持
gtid_mode=ON
enforce_gtid_consistency=ON
# 启用二进制日志
log-bin=mysql-bin
#启用并行复制
binlog_transaction_dependency_tracking=WRITESET
replica_preserve_commit_order=ON
replica_parallel_type=LOGICAL_CLOCK
transaction_write_set_extraction=XXHASH64
#对于Group Replication,数据必须存储在InnoDB事务存储引擎中
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"

# mgr-node2和mgr-node3同上,注意配置文件路径和修改server_id
vim /mysql/mgr/node2/conf/custom.cnf
[mysql]
# 设置mysql客户端默认编码
default-character-set=utf8
[mysqld]
#指定sever_id,三个Mysql实例需要分别改为对应的sever_id
server_id=2
# 必须开启GTID支持
gtid_mode=ON
enforce_gtid_consistency=ON
# 启用二进制日志
log-bin=mysql-bin
#启用并行复制
binlog_transaction_dependency_tracking=WRITESET
replica_preserve_commit_order=ON
replica_parallel_type=LOGICAL_CLOCK
transaction_write_set_extraction=XXHASH64
#对于Group Replication,数据必须存储在InnoDB事务存储引擎中
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"

vim /mysql/mgr/node3/conf/custom.cnf
[mysql]
# 设置mysql客户端默认编码
default-character-set=utf8
[mysqld]
#指定sever_id,三个Mysql实例需要分别改为对应的sever_id
server_id=3
# 必须开启GTID支持
gtid_mode=ON
enforce_gtid_consistency=ON
# 启用二进制日志
log-bin=mysql-bin
#启用并行复制
binlog_transaction_dependency_tracking=WRITESET
replica_preserve_commit_order=ON
replica_parallel_type=LOGICAL_CLOCK
transaction_write_set_extraction=XXHASH64
#对于Group Replication,数据必须存储在InnoDB事务存储引擎中
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"

#运行mysql容器
# 为了便于测试,启动容器时指定好IP、hostname
docker run  -d  \
--name mgr-node1 \
--privileged=true \
--restart=always \
--ip 172.19.0.10 \
--hostname mgr-node1 \
--add-host  mgr-node2:172.19.0.11 \
--add-host  mgr-node3:172.19.0.12 \
--network  mgr-network \
-p 3321:3306 \
-v /mysql/mgr/node1/data:/var/lib/mysql \
-v /mysql/mgr/node1/conf:/etc/mysql/conf.d  \
-v /mysql/mgr/node1/log:/logs \
-e MYSQL_ROOT_PASSWORD=123456 \
-e TZ=Asia/Shanghai mysql:8.0.27 \
--lower_case_table_names=1


docker run  -d  \
--name mgr-node2 \
--privileged=true \
--restart=always \
--ip 172.19.0.11 \
--hostname mgr-node2 \
--add-host  mgr-node1:172.19.0.10 \
--add-host  mgr-node3:172.19.0.12 \
--network  mgr-network \
-p 3322:3306 \
-v /mysql/mgr/node2/data:/var/lib/mysql \
-v /mysql/mgr/node2/conf:/etc/mysql/conf.d  \
-v /mysql/mgr/node2/log:/logs \
-e MYSQL_ROOT_PASSWORD=123456 \
-e TZ=Asia/Shanghai mysql:8.0.27 \
--lower_case_table_names=1

docker run  -d  \
--name mgr-node3 \
--privileged=true \
--restart=always \
--ip 172.19.0.12 \
--hostname mgr-node3 \
--add-host  mgr-node1:172.19.0.10 \
--add-host  mgr-node2:172.19.0.11 \
--network  mgr-network \
-p 3323:3306 \
-v /mysql/mgr/node3/data:/var/lib/mysql \
-v /mysql/mgr/node3/conf:/etc/mysql/conf.d  \
-v /mysql/mgr/node3/log:/logs \
-e MYSQL_ROOT_PASSWORD=123456 \
-e TZ=Asia/Shanghai mysql:8.0.27 \
--lower_case_table_names=1


# 在宿主机上配置mysql容器的ip和host映射
vim /etc/hosts
172.19.0.10  mgr-node1
172.19.0.11  mgr-node2
172.19.0.12  mgr-node3

 所有实例分别配置远程访问

# 以node1为例
docker exec -it mgr-node1 /bin/bash
mysql -u root -p123456
#进入mysql执行
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
flush privileges;

2. 安装mysqlrouter和安装mysqlshell

MySQL Router是MySQL Proxy的后继产品,它提供了MySQL协议的路由器功能,可以用来实现读写分离、负载均衡和高可用性解决方案。

安装mysql-router

下载地址:https://downloads.mysql.com/archives/router/

# 以centos7为例
wget https://downloads.mysql.com/archives/get/p/41/file/mysql-router-community-8.0.27-1.el7.x86_64.rpm
rpm -ivh mysql-router-community-8.0.27-1.el7.x86_64.rpm

安装mysql-shell

下载地址:MySQL :: Download MySQL Shell (Archived Versions)

# 以centos7为例
wget https://downloads.mysql.com/archives/get/p/43/file/mysql-shell-8.0.27-1.el7.x86_64.rpm
rpm -ivh mysql-shell-8.0.27-1.el7.x86_64.rpm
# 远程连接mysql
mysqlsh root@192.168.65.223:3321 --js
mysqlsh root@mgr-node1:3306 --js

 MySQL Shell 教程: 有道云笔记

3. InnoDB Cluster 初始化
3.1 参数及权限配置预需求检测

在添加实例到集群中前,使用该方法检查实例配置是否满足InnoDB 集群要求。

mysqlsh root@192.168.65.223:3321 --js
// 检查实例是否符合InnoDB Cluster的参数及权限配置要求
dba.checkInstanceConfiguration('root@mgr-node1:3306')
dba.checkInstanceConfiguration('root@mgr-node2:3306')
dba.checkInstanceConfiguration('root@mgr-node3:3306')

如果验证通过返回ok。 

如果验证没通过,比如出现下面的日志提示,需要mysql实例开启gtid和指定server_id

搭建InnoDB Cluster需要满足的要求如下:

InnoDB集群使用了Group Replication,因此必须满足使用组复制的要求。具体可以参考https://dev.mysql.com/doc/refman/8.0/en/group-replication-requirements.html。其中比较重要的几点有:

  • 必须开启二进制日志,并且日志格式为ROW,即--log-bin和binlog_format=row(默认);
  • 必须开启副本更新日志,即log_replica_updates=ON(默认) ;
  • 必须开启GTID,即gtid_mode=ON和enforce_gtid_consistency=ON。
  • 存储引擎只能使用InnoDB。最好禁用其他存储引擎:
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
  • 从8.0.23开始,集群中的实例要启用并行复制。需要配置以下系统变量:
binlog_transaction_dependency_tracking=WRITESET
slave_preserve_commit_order=ON
slave_parallel_type=LOGICAL_CLOCK
transaction_write_set_extraction=XXHASH64
 3.2 初始化InnoDB Cluster相关配置
// 对实例配置InnoDB Cluster相关参数
dba.configureInstance('root@mgr-node1:3306')
dba.configureInstance('root@mgr-node2:3306')
dba.configureInstance('root@mgr-node3:3306')

4.创建一主两从InnoDB集群 

集群常用命令

#会列出dba相关指令
dba.help();
#列出详细指令的用法
dba.help('deploySandboxInstance');
#检查节点配置实例,用于加入cluster之前
dba.checkInstanceConfiguration("root@hostname:3306");  
#节点初始化
dba.configureInstance('root@hostname:3306'); 
#重启集群
dba.rebootClusterFromCompleteOutage('myCluster');  
#会列出集群相关指令
cluster.help();       
#创建集群
var cluster = dba.createCluster('myCluster');                              
#获取当前集群实例
var cluster = dba.getCluster('myCluster');   
查看集群状态
cluster.status();             
#检查cluster节点状态 
cluster.checkInstanceState("root@hostname:3306") ;                             
#增加节点 
cluster.addInstance("root@hostname:3306") ;               
#删除节点 
cluster.removeInstance("root@hostname:3306") ;            
#强制删除节点
cluster.removeInstance('root@hostname:3306',{force:true});    
#  状态为missing的节点可以重新加入集群 
cluster.rejoinInstance("root@hostname:3306")
#解散集群 
cluster.dissolve({force:true}) ;                          
#集群描述 
cluster.describe();  

进入主节点创建集群

初始化完第一个实例后,就可以创建集群了。

# 进入主节点创建集群
mysqlsh root@192.168.65.223:3321 --js
# 创建一个 cluster,命名为 'myCluster'    
var cluster = dba.createCluster('myCluster');
# 创建成功后,查看cluster状态
cluster.status();

当前集群的状态如下

 

添加副本实例

添加副本实例到创建好的集群。

#初始化第二个和第三个实例:
cluster.addInstance('root@mgr-node2:3306');
cluster.addInstance('root@mgr-node3:3306');
#查看cluster状态
cluster.status();

如果提示副本实例的GTID与集群不一致,选择通过Clone方式覆盖副本实例上的数据即可。

 

小结:完整的集群创建步骤
#进入主节点
mysqlsh root@mgr-node1:3306 --js

#mgr-node1 
# 参数权限检查
dba.checkInstanceConfiguration('root@mgr-node1:3306');
# 初始化
dba.configureInstance('root@mgr-node1:3306');
# 创建集群
var cluster = dba.createCluster('myCluster');
#查看cluster状态
cluster.status();

#mgr-node2
# 参数权限检查
dba.checkInstanceConfiguration('root@mgr-node2:3306');
# 初始化
dba.configureInstance('root@mgr-node2:3306');
# 添加副本
cluster.addInstance('root@mgr-node2:3306');

#mgr-node3
# 参数权限检查
dba.checkInstanceConfiguration('root@mgr-node3:3306');
# 初始化
dba.configureInstance('root@mgr-node3:3306');
# 添加副本
cluster.addInstance('root@mgr-node3:3306');

#查看cluster状态
cluster.status();

 搭建一主两从集群架构最终效果如下:

注意到集群状态已变为"status": "OK"和"statusText": "Cluster is ONLINE and can tolerate up to ONE failure."。

集群节点状态:

  • ONLINE - 节点状态正常。
  • OFFLINE - 实例在运行,但没有加入任何Cluster。
  • RECOVERING - 实例已加入Cluster,正在同步数据。
  • ERROR - 同步数据发生异常。
  • UNREACHABLE - 与其他节点通讯中断,可能是网络问题,可能是节点crash。
  • MISSING - 节点已加入集群,但未启动group replication

测试数据是否同步

#主节点 mgr-node1
[root@192-168-65-223 ~]# docker exec -it mgr-node1 bash
root@mgr-node1:/# mysql -uroot -p123456
mysql>
create database test;
use test;
create table t(x int primary key auto_increment,y int);
insert into t(x,y) value(1,1);

注意:如果创建表没有设置主键,会抛出错误:ERROR 3098 (HY000): The table does not comply with the requirements by an external plugin. 

# 查看其他节点,数据是否同步
[root@192-168-65-223 ~]# docker exec -it mgr-node2 bash
root@mgr-node2:/# mysql -uroot -p123456
mysql> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select * from t;
+---+------+
| x | y    |
+---+------+
| 1 |    1 |
+---+------+
1 row in set (0.00 sec)
测试主从切换 
#停掉主节点
[root@192-168-65-223 ~]# docker stop mgr-node1

# 连接到mgr-node2
MySQL  mgr-node1:3306 ssl  JS > \connect root@mgr-node2:3306
# 获取集群实例
 MySQL  mgr-node2:3306 ssl  JS > var cluster=dba.getCluster();
# 查看集群状态
MySQL  mgr-node2:3306 ssl  JS > cluster.status()
{
    "clusterName": "myCluster", 
    "defaultReplicaSet": {
        "name": "default", 
        "primary": "mgr-node2:3306", 
        "ssl": "REQUIRED", 
        "status": "OK_NO_TOLERANCE", 
        "statusText": "Cluster is NOT tolerant to any failures. 1 member is not active.", 
        "topology": {
            "mgr-node1:3306": {
                "address": "mgr-node1:3306", 
                "memberRole": "SECONDARY", 
                "mode": "n/a", 
                "readReplicas": {}, 
                "role": "HA", 
                "shellConnectError": "MySQL Error 2003: Could not open connection to 'mgr-node1:3306': Can't connect to MySQL server on 'mgr-node1:3306' (113)", 
                "status": "(MISSING)"
            }, 
            "mgr-node2:3306": {
                "address": "mgr-node2:3306", 
                "memberRole": "PRIMARY", 
                "mode": "R/W", 
                "readReplicas": {}, 
                "replicationLag": null, 
                "role": "HA", 
                "status": "ONLINE", 
                "version": "8.0.27"
            }, 
            "mgr-node3:3306": {
                "address": "mgr-node3:3306", 
                "memberRole": "SECONDARY", 
                "mode": "R/O", 
                "readReplicas": {}, 
                "replicationLag": null, 
                "role": "HA", 
                "status": "ONLINE", 
                "version": "8.0.27"
            }
        }, 
        "topologyMode": "Single-Primary"
    }, 
    "groupInformationSourceMember": "mgr-node2:3306"
}

 

可以看到mgr-node2升级为主节点

# 启动mgr-node1节点
[root@192-168-65-223 ~]# docker start mgr-node1
# 查看集群状态,发现mgr-node1正在恢复,最终正常
 MySQL  mgr-node2:3306 ssl  JS > cluster.status()
{
    "clusterName": "myCluster", 
    "defaultReplicaSet": {
        "name": "default", 
        "primary": "mgr-node2:3306", 
        "ssl": "REQUIRED", 
        "status": "OK_NO_TOLERANCE", 
        "statusText": "Cluster is NOT tolerant to any failures. 1 member is not active.", 
        "topology": {
            "mgr-node1:3306": {
                "address": "mgr-node1:3306", 
                "instanceErrors": [
                    "NOTE: group_replication is stopped."
                ], 
                "memberRole": "SECONDARY", 
                "memberState": "OFFLINE", 
                "mode": "R/O", 
                "readReplicas": {}, 
                "role": "HA", 
                "status": "(MISSING)", 
                "version": "8.0.27"
            }, 
            "mgr-node2:3306": {
                "address": "mgr-node2:3306", 
                "memberRole": "PRIMARY", 
                "mode": "R/W", 
                "readReplicas": {}, 
                "replicationLag": null, 
                "role": "HA", 
                "status": "ONLINE", 
                "version": "8.0.27"
            }, 
            "mgr-node3:3306": {
                "address": "mgr-node3:3306", 
                "memberRole": "SECONDARY", 
                "mode": "R/O", 
                "readReplicas": {}, 
                "replicationLag": null, 
                "role": "HA", 
                "status": "ONLINE", 
                "version": "8.0.27"
            }
        }, 
        "topologyMode": "Single-Primary"
    }, 
    "groupInformationSourceMember": "mgr-node2:3306"
}
MySQL  mgr-node2:3306 ssl  JS > cluster.status()
{
    "clusterName": "myCluster", 
    "defaultReplicaSet": {
        "name": "default", 
        "primary": "mgr-node2:3306", 
        "ssl": "REQUIRED", 
        "status": "OK", 
        "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.", 
        "topology": {
            "mgr-node1:3306": {
                "address": "mgr-node1:3306", 
                "memberRole": "SECONDARY", 
                "mode": "R/O", 
                "readReplicas": {}, 
                "replicationLag": null, 
                "role": "HA", 
                "status": "ONLINE", 
                "version": "8.0.27"
            }, 
            "mgr-node2:3306": {
                "address": "mgr-node2:3306", 
                "memberRole": "PRIMARY", 
                "mode": "R/W", 
                "readReplicas": {}, 
                "replicationLag": null, 
                "role": "HA", 
                "status": "ONLINE", 
                "version": "8.0.27"
            }, 
            "mgr-node3:3306": {
                "address": "mgr-node3:3306", 
                "memberRole": "SECONDARY", 
                "mode": "R/O", 
                "readReplicas": {}, 
                "replicationLag": null, 
                "role": "HA", 
                "status": "ONLINE", 
                "version": "8.0.27"
            }
        }, 
        "topologyMode": "Single-Primary"
    }, 
    "groupInformationSourceMember": "mgr-node2:3306"
}

更多的常见操作

参数配置

可以用cluster.options()查看当前集群的配置属性,集群参数配置分为两种方式:

  • cluster.setOption() 用来设置所有节点的参数
  • cluster.setInstanceOption() 用来对指定节点配置属性
# 将所有节点的权重都改为50
var cluster = dba.getCluster()
cluster.setOption("memberWeight",50)
# 重新加入集群重试次数改为5次
cluster.setOption("autoRejoinTries",5)

# 将其中一个节点的权重改为75
cluster.setInstanceOption("mgr-node2:3306","memberWeight",75)
# 重新加入集群重试次数改为10次
cluster.setInstanceOption("mgr-node2:3306","autoRejoinTries",10)

配置节点权重

memberWeight选项的值域为0到100之间的整数,缺省值为50。该值是故障转移时自动选举主节点的百分比权重,具有较高memberWeight值的实例更有可能在单主群集中被选为主节点

// 查看集群的参数配置(包括memberWeight优先级配置)
cluster.options()

// 在集群创建时配置
dba.createCluster('myCluster', {memberWeight:75}) // 第一个节点配置方式
var cluster = dba.getCluster() 
cluster.addInstance('mgr-node2:3306',{memberWeight:50})
cluster.addInstance('mgr-node3:3306',{memberWeight:25})

// 在集群创建完成后修改权重
var cluster = dba.getCluster()
cluster.setInstanceOption('mgr-node1:3306','memberWeight',100)
cluster.setInstanceOption('mgr-node2:3306','memberWeight',50)
cluster.setInstanceOption('mgr-node3:3306','memberWeight',25)

将节点重新加入集群

状态为mssing的节点,通常是组复制关闭或中断状态,可以用cluster.rejoinInstance()重新加入集群,会重新对该节点设置MGR相关参数(持久化到mysqld-auto.conf中)

 

cluster.removeInstance('root@hostname:3306',{force:true});    

如果一些参数做了修改,如server_uuid变更,导致rejoin失败,则需要将节点从集群中删除后重新加入

cluster.removeInstance("root@hostname:3306",{force:true})
cluster.rescan()
cluster.addInstance("root@hostname:3306")

 

集群多数节点异常,恢复

当集群多个节点异常,则失去了仲裁机制,剩下的一个节点

// 将集群剥离为单节点运行
JS > cluster.forceQuorumUsingPartitionOf("root@hostname:3306")

// 重新加另外2个节点加入
JS > cluster.rejoinInstance("root@hostname2:3306")
JS > cluster.rejoinInstance("root@hostname3:3306")

集群节点角色切换

在MGR的管理下提供了一下3种方式进行角色切换,mysqlsh对其进行了封装调用

  • group_replication_set_as_primary(member_uuid);
    • cluster.setPrimaryInstance("homename:3306")
  • group_replication_switch_to_single_primary_mode()
    • cluster.switchToSinglePrimaryMode("homename:3306")
  • group_replication_switch_to_multi_primary_mode()
    • cluster.switchToMultiPrimaryMode()

 单主模式-指定主节点切换

var cluster = dba.getCluster()
cluster.setPrimaryInstance('homename:3306')
cluster.status()

单主模式和多主模式相互切换

// 切换为多主模式
var cluster = dba.getCluster()
cluster.switchToMultiPrimaryMode()

// 指定明确的主节点将多主模式切换为单主模式
cluster.switchToSinglePrimaryMode("homename:3306")

将单主模式切换为多主模式的效果

销毁集群

删除与群集关联的所有元数据和配置,并禁用实例上的组复制,但不会删除在实例之间复制的任何数据。要再次创建集群,使用dba.createCluster()

var cluster = dba.getCluster()
cluster.dissolve()

 创建集群管理用户

cluster.setupAdminAccount('fox')

# 经典MySQL协议连接 mysqlsh --mysql -hmgr-node1 -ufox # X协议连接 mysqlsh --mysqlx -hmgr-node1 -ufox 

7.使用MySQL Router连接集群 

配置路由器

mysqlrouter --bootstrap root@mgr-node2:3306 --force --user=root
#或者指定host
mysqlrouter --bootstrap root@mgr-node2:3306 --force --user=root --report-host mgr

注意,如果用户之前为该实例配置过路由,则可以通过指定force选项强制引导启动。

上面的内容是引导启动路由器时输出的信息,信息提示,MySQL经典协议使用6446端口和6447端口,X协议使用6448端口和6449端口,每种协议使用的两个端口分别用于读写和只读。

在一个运行的集群中,AdminAPI 可以引导多个路由器。用户可以使用cluster.listRouters()方法显示所有注册的路由器列表。

启动路由器:mysqlrouter &

路由器已经成功启动。现在,使用MySQL Shell连接路由器进行验证 

#连接mysqlrouter
[root@192-168-65-223 ~]# mysqlsh root@localhost:6446 --sql
MySQL  localhost:6446 ssl  SQL > use test;
MySQL  localhost:6446 ssl  test  SQL > select * from t;

 查看集群成员信息

MySQL  localhost:6446 ssl  test  SQL > select * from performance_schem

测试

测试读写端口6446

用户可以通过连接本机的6446端口连接到MySQL实例

6446为读写端口,也可以插入数据 

 

测试只读端口6647:插入数据报错 

MySQL InnoDB ReplicaSet

基本概述

MySQL Innodb Cluster = MySQL Shell + MySQL Router + MySQL Group Replication(MGR),全程由 MySQL Shell 来管理操作 MGR 的聚合套件。MySQL 8.0.19 发布后,这种组合延伸到 MySQL Replication(主从复制),也就是 MySQL Shell + MySQL Router + MySQL Replication。

InnoDB ReplicaSet至少由两个MySQL服务器实例组成,并提供用户熟知的主从复制功能,例如读取横向扩展和数据安全性。InnoDB ReplicaSet使用以下MySQL技术。

  • MySQL Shell:MySQL的高级客户端、管理工具,可以用来管理复制集。
  • MySQL复制:一组MySQL实例,通过复制能够提供可用性和异步读取的横向扩展。
  • MySQL Router:一种轻量级的中间件,可在应用程序和InnoDB ReplicaSet之间提供透明的路由。InnoDB ReplicaSet的接口类似于InnoDB Cluster,用户可以利用MySQL Shell使用MySQL实例和MySQL Router。

与InnoDB集群相比,InnoDB ReplicaSet具有多个限制,因此,官方建议尽可能部署InnoDB群集。通常,InnoDB ReplicaSet本身不能提供高可用性。InnoDB ReplicaSet的限制包括:

  • 没有自动故障转移。如果主服务器不可用,则需要使用AdminAPI手动触发故障转移,然后才能再次进行任何更改。但是,辅助实例仍然可用于读取。
  • 无法防止因意外停止或不可用而导致部分数据丢失。暂停之前尚未应用的事务可能会丢失。
  • 无法防止崩溃或不可用后出现不一致情况。如果故障转移在辅助节点仍可用的情况下提升了辅助节点(例如,由于网络分区),则可能会因脑裂而引起不一致。
搭建一主一从的复制集

1. 安装2个数据库实例

参考:Docker 安装 MySQL8.0 

可以利用docker快速部署2个MySQL实例

# 创建组复制的网络  保证三个mysql容器之间可以通过容器名访问
docker network create --driver bridge --subnet 172.20.0.0/24 --gateway 172.20.0.1 rs-network

mkdir -p /mysql/rs/node1/data /mysql/rs/node1/conf /mysql/rs/node1/log
mkdir -p /mysql/rs/node2/data /mysql/rs/node2/conf /mysql/rs/node2/log


#以rs-node1配置为例,创建/mysql/rs/node1/conf/custom.cnf,添加以下配置:
vim /mysql/rs/node1/conf/custom.cnf
[mysql]
# 设置mysql客户端默认编码
default-character-set=utf8
[mysqld]
#指定sever_id,多个Mysql实例需要分别改为对应的sever_id
server_id=21
# 必须开启GTID支持
gtid_mode=ON
enforce_gtid_consistency=ON
# 启用二进制日志
log-bin=mysql-bin
#启用并行复制
binlog_transaction_dependency_tracking=WRITESET
replica_preserve_commit_order=ON
replica_parallel_type=LOGICAL_CLOCK
transaction_write_set_extraction=XXHASH64

# rs-node2同上,注意配置文件路径和修改server_id
vim /mysql/rs/node2/conf/custom.cnf
[mysql]
# 设置mysql客户端默认编码
default-character-set=utf8
[mysqld]
#指定sever_id,多个Mysql实例需要分别改为对应的sever_id
server_id=22
# 必须开启GTID支持
gtid_mode=ON
enforce_gtid_consistency=ON
# 启用二进制日志
log-bin=mysql-bin
#启用并行复制
binlog_transaction_dependency_tracking=WRITESET
replica_preserve_commit_order=ON
replica_parallel_type=LOGICAL_CLOCK
transaction_write_set_extraction=XXHASH64


#运行mysql容器
# 为了便于测试,启动容器时指定好IP、hostname
docker run  -d  \
--name rs-node1 \
--privileged=true \
--restart=always \
--ip 172.20.0.20 \
--hostname rs-node1 \
--add-host  rs-node2:172.20.0.21 \
--network  rs-network \
-p 3331:3306 \
-v /mysql/rs/node1/data:/var/lib/mysql \
-v /mysql/rs/node1/conf:/etc/mysql/conf.d  \
-v /mysql/rs/node1/log:/logs \
-e MYSQL_ROOT_PASSWORD=123456 \
-e TZ=Asia/Shanghai mysql:8.0.27 \
--lower_case_table_names=1


docker run  -d  \
--name rs-node2 \
--privileged=true \
--restart=always \
--ip 172.20.0.21 \
--hostname rs-node2 \
--add-host  rs-node1:172.20.0.20 \
--network  rs-network \
-p 3332:3306 \
-v /mysql/rs/node2/data:/var/lib/mysql \
-v /mysql/rs/node2/conf:/etc/mysql/conf.d  \
-v /mysql/rs/node2/log:/logs \
-e MYSQL_ROOT_PASSWORD=123456 \
-e TZ=Asia/Shanghai mysql:8.0.27 \
--lower_case_table_names=1



# 在宿主机上配置mysql容器的ip和host映射
vim /etc/hosts
172.20.0.20  rs-node1
172.20.0.21  rs-node2

所有实例分别配置远程访问

# 以node1为例
docker exec -it rs-node1 /bin/bash
mysql -u root -p123456
#进入mysql执行
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
flush privileges;

 

 

 

 

2. 配置复制集

1)初始化主节点,创建复制集

#进入主节点
mysqlsh root@rs-node1:3306 --js
# 初始化
dba.configureReplicaSetInstance('root@rs-node1:3306')
# 创建复制集,使用异步复制
var rs = dba.createReplicaSet("myrs")
#查看状态
rs.status()

 

2)添加副本节点 

#将实例添加到复制集
rs.addInstance('root@rs-node2:3306')

 

 

测试数据是否同步

#主节点 rs-node1
[root@192-168-65-223 ~]# docker exec -it rs-node1 bash
root@mgr-node1:/# mysql -uroot -p123456
mysql>
create datebase test;
use test;
create table t(x int primary key auto_increment,y int);
insert into t(x,y) value(1,1);
select * from t;

# 进入从节点rs-node2,查看数据是否同步过来
[root@192-168-65-223 ~]# docker exec -it rs-node2 bash
root@rs-node2:/# mysql -uroot -p123456
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 1596
Server version: 8.0.27 MySQL Community Server - GPL

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

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> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select * from t;
+---+------+
| x | y    |
+---+------+
| 1 |    1 |
+---+------+
1 row in set (0.00 sec)

3. 配置 MySQL Router 路由器

[root@192-168-65-223 ~]# mysqlrouter --bootstrap root@rs-node1:3306 --force --user=root

 

 

重启Mysql Router

[root@192-168-65-223 ~]# ps -ef|grep mysqlrouter
root     16993 14238  6 11:30 pts/1    00:18:01 mysqlrouter
root     21637 14178  0 16:22 pts/0    00:00:00 grep --color=auto mysqlrouter
[root@192-168-65-223 ~]# kill -9 16993
# 启动Mysql Router
[root@192-168-65-223 ~]# mysqlrouter &

4. 测试

用户可以通过连接本机的6446端口连接到MySQL实例

[root@192-168-65-223 ~]# mysqlsh root@localhost:6446 --sql
# 可以查询到插入的测试数据
 MySQL  localhost:6446 ssl  SQL > select * from test.t;
+---+---+
| x | y |
+---+---+
| 1 | 1 |
+---+---+

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/541091.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于SpringBoot+Vue的健身器材用品网站(源码+文档+部署+讲解)

一.系统概述 随着我国经济的高速发展与人们生活水平的日益提高,人们对生活质量的追求也多种多样。尤其在人们生活节奏不断加快的当下,人们更趋向于足不出户解决各种问题,必录德健身器材用品网展现了其蓬勃生命力和广阔的前景。与此同时&#…

AugmentedReality之路-平面检测(5)

本文介绍通过AR检测水平平面和垂直平面,并将检测到的平面转化为Mesh 1、在首页添加功能入口 在首页添加一个按钮,命名为Start World Track 2、自定义ExecStartAREvent 创建ARSessionConfig并取名为ARSessionConfig_World 自定义ExecStartAREvent&…

2024年你应该防范的11个WordPress安全漏洞问题:由资深程序员撰写

微软创始人比尔盖茨曾说过,“安全对每个人都有同样的影响。在网站安全方面,没有特定的主题、目标或受众。” 但WordPress是互联网上最受欢迎的CMS。它也是被黑客攻击次数最多的。针对WordPress的攻击次数超过了每秒2800次。网络攻击会浪费时间、精力和金…

camera驱动学习总结记录

https://www.yuque.com/u2132176/yfiyal/ch1zsrgzevcwf1rw 视频教程里面对应的gc2053c驱动源码注解: gc2053.c(60 KB) 对应的驱动文档: Rockchip_Driver_Guide_VI_CN_v1.1.1(2).pdf(2.3 MB) 视频里面对应的mipi协议文档汇总: MIPI标准文档大…

MoCo v1(CVPR 2020)原理与代码解读

paper:Momentum Contrast for Unsupervised Visual Representation Learning official implementation:https://github.com/facebookresearch/moco 背景 最近的一些研究提出使用对比损失相关的方法进行无监督视觉表征学习并取得了不错的结果。尽管是受…

springcloud第4季 springcloud-alibaba之nacos篇

一 nacos 1.1 nacos作用介绍 nacos是一个分布式的配置中心和注册发现中心。 nacos是 dynamic naming configuration service nacosconfigbus 实现动态刷新;nacosconsul 1.2 各个注册中心对比 注册中心CAP模型控制台管理社区活跃度EureakaAp支持低zkcp不支持中…

leetcode73 矩阵置零

题目描述 给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用原地算法。 输入:matrix [[1,1,1],[1,0,1],[1,1,1]] 输出:[[1,0,1],[0,0,0],[1,0,1]] 输入:matrix [[0,1,2,0],[3,4…

使用 Python 标记具有相同名称的条目

如果大家想在 Python 中标记具有相同名称的条目,可以使用字典(Dictionary)或集合(Set)来实现。这取决于你们希望如何存储和使用这些条目。下面我将提供两种常见的方法来实现这个目标。 1、问题背景 在处理数据时&…

PE文件的分析和构造超详细过程

本文详细讲述如何从0构造一个PE文件,运行该文件会弹出一个HelloPE的窗口 目录 预备知识 1. 构造DOS头IMAGE_DOS_HEADER 1.1 构造DOS_MZ头 1.2 构造DOS_STUB 2、构造PE头IMAGE_NT_HEADERS 248字节 2.1 signature 2.2 IMAGE_FILE_HEADER 2.3 IMAGE_OPTI…

Python爬虫:蝉妈妈返回参数data解密

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ 🐴作者:秋无之地 🐴简介:CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作,主要擅长领域有:爬虫、后端、大数据开发、数据分析等。 🐴欢迎小伙伴们点赞👍🏻、收藏⭐️、…

Spring Boot | Spring Boot 整合 “Servlet三大组件“ ( Servlet / Filter / Listene )

目录: Spring Boot 整合 "Servlet三大组件" :1. 使用 "组件注册" 的方式 "整合Servlet三大组件" ( 实际操作为 : 创建自定义的"三大组件"对象 结合刚创建"的自定义组件对象"来 将 XxxRegistrationBean对象 通过…

sparkSql join 关联机制

💐💐扫码关注公众号,回复 spark 关键字下载geekbang 原价 90 元 零基础入门 Spark 学习资料💐💐 join 实现机制 Join 有 3 种实现机制,分别是 NLJ(Nested Loop Join)、SMJ&#xf…

【VUE】使用Vue和CSS动画创建滚动列表

使用Vue和CSS动画创建滚动列表 在这篇文章中,我们将探讨如何使用Vue.js和CSS动画创建一个动态且视觉上吸引人的滚动列表。这个列表将自动滚动显示项目,类似于轮播图的方式,非常适合用于仪表盘、排行榜或任何需要在有限空间内展示项目列表的应…

【Altium Designer 20 笔记】隐藏PCB上的信号线(连接线)

使用网络类隐藏特定类型的信号线 如果你想要隐藏特定类型的信号线(例如电源类),你可以首先创建一个网络类。使用快捷键DC调出对象类浏览器,在Net Classes中右击添加类,并重命名(例如为“Power”&#xff0…

【Qt 学习笔记】QWidget的geometry属性及window frame的影响

博客主页:Duck Bro 博客主页系列专栏:Qt 专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ QWidget的geometry属性 文章编号:Qt 学习笔记 / 16 文章目…

spring boot学习第十七篇:OAuth2概述及使用GitHub登录第三方网站

0. 导言 我们在浏览器上可以访问成百上千个网站,使用每个网站的服务一般都要先注册账号,那么我们为了更好地记忆,一般都会在多个网站使用相同的账号和密码进行注册。那么问题就来了,如果在你注册的网站中有某些个网站的系统设计不…

C++进阶03 模板与群体数据

听课笔记简单整理,供小伙伴们参考~🥝🥝 第1版:听课的记录代码~🧩🧩 编辑:梅头脑🌸 审核:文心一言 目录 🐳课程来源 🐋模板 🐋8.…

小区烟火AI检测/楼道杂物堆积消防隐患AI智能识别方案

一、背景需求 据新闻报道,今年4月7日,安徽省合肥市肥东县一民房发生火灾,致1死11伤,起火点是“一楼楼道杂物间”。 因为小区居民楼楼道堆积大量杂物而导致的消防火灾事故也不在少数。楼道堆积杂物是一个长期存在的问题&#xff…

安装ODBC方法

1、运行 搜索 ODBC数据源管理程序 32位或者 64位 2、在用户DSN或者系统DSN选择添加(建议前者),此处以添加access数据库的odbc驱动为例 3、安装成功

2024妈妈杯数学建模A 题思路分析-移动通信网络中 PCI 规划问题

# 1 赛题 A 题 移动通信网络中 PCI 规划问题 物理小区识别码(PCI)规划是移动通信网络中下行链路层上,对各覆盖 小区编号进行合理配置,以避免 PCI 冲突、 PCI 混淆以及 PCI 模 3 干扰等 现象。 PCI 规划对于减少物理层的小区间互相干扰(ICI),增…