作者: wangxiyuan
本文介绍Mysql 8.0的Innodb cluster架构,以及在arm64上的部署流程
概述
Mysql Innodb cluster是Mysql 在HA场景下推荐的一种部署模型。支持多节点集群部署,保证Mysql的高可用性。需要配套Mysql Router使用,并建议使用Mysql shell进行部署。
架构
如图所以,一个Mysql Innodb cluster主要由三个部分组成:
Mysql HA集群。集群中包含多个Mysql服务,每个服务使用Innodb后端,并配置Group Replication。
Mysql Router。提供前端Load Balance能力。
Mysql Shell以及其他Client。前端客户端,用来部署、使用Cluster。
实战
本文使用源码编译的方式部署。
要求
3节点ARM64环境。
Mysql使用Innodb存储引擎,并开启了Group Replication功能。
Mysql Shell依赖Python。需要安装python3和python3-dev
必要的C/C++编译工具,例如gcc、gcc-c++、autoconf、cmake、make等等,不再赘述。
安装
Mysql Server
Mysql Server 8.0编译很简单。
1
2
3
4
5git clone https://github.com/mysql/mysql-server
mkdir mysql-server/bld
cd mysql-server/bld
cmake .. -DDOWNLOAD_BOOST=1 -DWITH_BOOST={boost download folder}
make -j8Mysql-shell
Mysql官方没提供arm64的安装包,需要手动编译。
1
2
3
4
5$ git clone https://github.com/mysql/mysql-shell
$ mkdir mysql-shell/bld
$ cd mysql-shell/bld
$ cmake .. -DDOWNLOAD_BOOST=1 -DENABLE_DOWNLOADS=1 -DMYSQL_SOURCE_DIR=/opt/mysql-server -DMYSQL_BUILD_DIR=/opt/mysql-server/bld -DHAVE_PYTHON=1
$ make -j4这里有个问题:
1
2
3
4
5
6
7
8
9Mysql-shell依赖protobuf和Mysql server,而Mysql server也依赖protobuf。这两个protobuf要版本一致。不一致的话Mysql-shell无法编译通过
但是Mysql server在代码中内置了自己fork的非官方protobuf。在默认编译参数下,Mysql Server会使用这个protobuf。
因此这里有两个解决方法:
1. 统一使用Mysql server的非官方protobuf,注意这里的protobuf必须是静态编译的(即有libprotobuf.a文件,而不是.so),这是Mysql-shell的依赖要求。但Mysql8.0默认动态编译protobuf,因此在编译Mysql需要给cmake命令添加 `-Dprotobuf_BUILD_SHARED_LIBS=OFF`参数。
2. 统一使用官方protobuf,提前安装好protobuf,并在编译Mysql server时指定 `-DWITH_PROTOBUF=system`,编译Mysql-shell时指定`-DProtobuf_INCLUDE_DIR`Mysql Router
Mysql Router官方也没有提供arm64安装包,也需要手动编译。但自Mysql 8.0以后,Mysql Router的源码已经合并到Mysql server中,因此编译Mysql server后,自带了Mysql Router。
部署
官方提供了两种部署方式:
沙盒(测试)环境。用户可以在单节点上体验、测试Innodb Cluster。
生产环境。多节点部署Innodb Cluster
本文先使用沙盒模式体验一下Innodb Cluster,然后再部署生产环境并测试Innodb Cluster。
沙盒环境
进入mysql-shell的bld/bin目录,执行
./mysqlsh
。mysql-shell支持多种语言的API,我们在前面章节编译的mysql-shell使用的是python,因此执行./mysqlsh后,可以看到mysql-py >
这样的命令行提示符。Mysql官方文档使用的是mysql-js,与本文不同。以下的操作和命令都在mysql-py命令行中执行。创建sandbox Instance
1
dba.deploy_sandbox_instance(3310)
根据提示创建密码后报错,找不到mysql,这里需要把之前编译要的Mysq server加入到PATH中
1
PATH=$PATH:/opt/mysql-server/bld/bin/
然后重复执行创建命令,成功后显示如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14mysql-py> dba.deploy_sandbox_instance(3310)
A new MySQL sandbox instance will be created on this host in
/root/mysql-sandboxes/3310
Warning: Sandbox instances are only suitable for deploying and
running on your local machine for testing purposes and are not
accessible from external networks.
Please enter a MySQL root password for the new instance: ****
Deploying new MySQL instance...
Instance localhost:3310 successfully deployed and started.
Use shell.connect('root@localhost:3310') to connect to the instance.此时在
$HOME
目录下生成了/mysql-sandboxes/3310
目录。并且拉起了两个如下进程。1
2./bin/mysqld --user mysql
/root/mysql-sandboxes/3310/bin/mysqld --defaults-file=/root/mysql-sandboxes/3310/my.cnf --user=root然后在拉起两个Instance,组成Cluster
1
2dba.deploy_sandbox_instance(3320)
dba.deploy_sandbox_instance(3330)查看进程,发现多了两个sandbox进程,分别对应新创的Instance。
组成Cluster
3个Mysql Instance创建成功后,我们把他们配置成Cluster。登录Instance并创建cluster。
1
2
3shell.connect('root@localhost:3310')
cluster=dba.create_cluster('testCluster')报错
1
2
3Traceback (most recent call last):
File "<string>", line 1, in <module>
SystemError: RuntimeError: Dba.create_cluster: error installing plugin 'group_replication': 127.0.0.1:3310: Can't open shared library '/opt/mysql-server/bld/lib/plugin/group_replication.so' (errno: 0 /opt/mysql-server/bld/lib/plugin/group_replication.so: cannot open shared object file: No such file or directory)这是mysql编译后直接只用bld目录的问题,手动创建该软连接。
1
2$ ln -s /opt/mysql-server/bld/plugin_output_directory/ /opt/mysql-server/bld/lib/
$ mv /opt/mysql-server/bld/lib/plugin_output_directory/ /opt/mysql-server/bld/lib/plugin/再次执行create命令,成功。然后给Cluster中添加Instance。
1
2cluster.add_instance('root@localhost:3320')
cluster.add_instance('root@localhost:3330')至此,sandbox Innodb Cluster部署完成,查询Cluster状态。
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
42mysql-py []> cluster.status()
{
"clusterName": "testCluster",
"defaultReplicaSet": {
"name": "default",
"primary": "127.0.0.1:3310",
"ssl": "REQUIRED",
"status": "OK",
"statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
"topology": {
"127.0.0.1:3310": {
"address": "127.0.0.1:3310",
"mode": "R/W",
"readReplicas": {},
"replicationLag": null,
"role": "HA",
"status": "ONLINE",
"version": "8.0.21"
},
"127.0.0.1:3320": {
"address": "127.0.0.1:3320",
"mode": "R/O",
"readReplicas": {},
"replicationLag": null,
"role": "HA",
"status": "ONLINE",
"version": "8.0.21"
},
"127.0.0.1:3330": {
"address": "127.0.0.1:3330",
"mode": "R/O",
"readReplicas": {},
"replicationLag": null,
"role": "HA",
"status": "ONLINE",
"version": "8.0.21"
}
},
"topologyMode": "Single-Primary"
},
"groupInformationSourceMember": "127.0.0.1:3310"
}配置Mysql Router
Mysql Server 8.0自带了Mysql Router,命令是
mysqlrouter
,在bld的bin目录下。执行初始化命令:1
mysqlrouter --bootstrap root@localhost:3310 --user=root
返回如下信息:
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- Creating account(s) (only those that are needed, if any)
- Verifying account (using it to run SQL queries that would be run by Router)
- Storing account in keyring
- Adjusting permissions of generated files
- Creating configuration /opt/mysql-server/bld/mysqlrouter.conf
# MySQL Router configured for the InnoDB Cluster 'testCluster'
After this MySQL Router has been started with the generated configuration
$ /etc/init.d/mysqlrouter restart
or
$ systemctl start mysqlrouter
or
$ mysqlrouter -c /opt/mysql-server/bld/mysqlrouter.conf
the cluster 'testCluster' can be reached by connecting to:
## MySQL Classic protocol
- Read/Write Connections: localhost:6446
- Read/Only Connections: localhost:6447
## MySQL X protocol
- Read/Write Connections: localhost:64460
- Read/Only Connections: localhost:64470该命令会在
mysql-server/bld/
生成mysqlrouter.conf
配置文件。根据返回提示信息,启动mysql router:
1
mysqlrouter -c /opt/mysql-server/bld/mysqlrouter.conf
又报错了:
1
Error: Loading plugin for config-section '[metadata_cache:testCluster]' failed: /opt/mysql-server/bld/runtime_output_directory/../lib/mysqlrouter/metadata_cache.so: cannot open shared object file: No such file or directory
这个错误和之前group_replication.so的问题一样,添加新的软链接即可:
1
2
3$ ln -s /opt/mysql-server/bld/plugin_output_directory/ /opt/mysql-server/bld/lib/
$ mv /opt/mysql-server/bld/lib/plugin_output_directory /opt/mysql-server/bld/lib/mysqlrouter再次启动,成功。这时就可以通过Mysql Router的6446端口访问Mysql Innodb Cluster了。在Mysql-shell中:
1
2
3
4
5
6
7
8mysql-py> \connect root@localhost:6446
mysql-py []> \sql
mysql-sql []> select @@port;
+--------+
| @@port |
+--------+
| 3310 |
+--------+成功登入
生产环境
这里我手里没有3个物理环境,因此采用容器化方式模拟三节点,刚好可以测试一下msyql的容器化能力。
准备
提前准备三个my.cnf
,命名为my1.cnf
my2.cnf
my3.cnf
, 注意配置项report-host
依次为172.8.0.100
172.8.0.101
172.8.0.102
, server_id
依次为1
2
3
1 | # For advice on how to change settings please see |
再创建自定义docker网络
1 | docker network create --subnet=172.18.0.0/24 my_bridge |
部署
使用docker启动3个mysql容器,我这里准备的my.cnf
文件在root
目录下.另外,由于在使用mysql-shell部署集群中,需要重启mysql,为了保证容器不退出,这里在mysql2和mysql3上手动执行死循环命令。
1 | docker run --name=mysql1 --network=my_bridge --ip 172.18.0.100 -v /root/my1.cnf:/etc/my.cnf -d mysql/mysql-server:8.0.22 |
由于改写了mysql2和3的容器命令,这里我们要手动拉起其中的myql,以mysql2为例
1 | $ docker exec -it mysql2 bash |
初始化配置
查看mysql初始密码:
1 | docker logs mysql1 2>&1 | grep GENERATED |
依次登录mysql容器并配置。以mysql1为例
1 | docker exec -it mysql1 bash |
验证,登录mysql:
1 | mysql -h172.18.0.100 -uroot -proot |
集群配置
使用mysql-shell进行配置,由于我的环境没有mysql-shell,直接进入mysql1容器使用自带的mysql-shell
1 | $ docker exec -it mysql1 bash |
- 检查配置项
以此执行dba.checkInstanceConfiguration("root@{三个容器的IP}:3306")
,返回OK
1 | { |
- 连接主节点,创建集群
1 | shell.connect('root@172.18.0.100:3306') |
- 新增节点
1 | cluster.addInstance('root@172.18.0.101:3306') |
注意,在添加节点过程中,mysql会重启,但mysql-shell会拉起服务失败,需要手动上去拉起,另开一个bash:
1 | $ docker exec -ti mysql2 bash |
- 检查状态
此时,3节点Innodb Cluster已经部署完成,检查集群状态:
1 | cluster.status() |
- Mysql router
mysql官方没有提供mysql router的arm64版本,mysql-server镜像中也没有集成mysql router。因此只能使用非容器化方式,步骤与上一章沙箱方式一样,不再赘述。
使用
Mysql-shell主要提供了两大类命令:dba.xxx和cluster.xxxx。使用cluster的命令要先获取cluster对象,使用dba.get_cluster()
命令。通过命令\help dba
和\help cluster
查询命令详情。使用Mysql-shell可以配置、使用Mysql innodb cluster。 当然直接使用mysql client也是可以的。
普通用户直接访问mysql router对外暴露的统一端口即可。