MariaDB 数据库是 MySQL 的一个分支,主要由开源社区维护,采用 GPL 授权许可 MariaDB 的目的是完全兼容 MySQL,包括 API 和命令行,使之能轻松成为 MySQL 的代替品。在存储引擎方面,使用 XtraDB 来代替 MySQL 的 InnoDB。
本文部署 3 个 MariaDB 服务器,采用一主多从架构(1 个 Master,2 个 Slave),来演示如何实现基于 MySQL Replication 的主从复制。
1. 部署环境
IP 地址(本地测试环境):192.168.0.10
操作系统:Linux CentOS 7.9
Docker 版本: 20.10.7
Docker Compose 版本: 2.6.1
MariaDB 集群目录:/home/docker/mysql_cluster
2. 创建 docker-compose.yml
$ cd /home/docker/mysql_cluster
$ vim docker-compose.yml
version: "3"
services:
mariadb_master:
image: mariadb:10.4
container_name: mariadb_master-10.4
ports:
- "3306:3306"
restart: always
environment:
- MARIADB_ROOT_PASSWORD=123456
volumes:
- /home/docker/mysql_cluster/master/conf:/etc/mysql/conf.d
- /home/docker/mysql_cluster/master/data:/var/lib/mysql
- /home/docker/mysql_cluster/master/log:/var/log/mysql
mariadb_node_1:
image: mariadb:10.4
container_name: mariadb_node_1-10.4
ports:
- "3307:3307"
restart: always
environment:
- MARIADB_ROOT_PASSWORD=123456
volumes:
- /home/docker/mysql_cluster/node_1/conf:/etc/mysql/conf.d
- /home/docker/mysql_cluster/node_1/data:/var/lib/mysql
- /home/docker/mysql_cluster/node_1/log:/var/log/mysql
mariadb_node_2:
image: mariadb:10.4
container_name: mariadb_node_2-10.4
ports:
- "3308:3308"
restart: always
environment:
- MARIADB_ROOT_PASSWORD=123456
volumes:
- /home/docker/mysql_cluster/node_2/conf:/etc/mysql/conf.d
- /home/docker/mysql_cluster/node_2/data:/var/lib/mysql
- /home/docker/mysql_cluster/node_2/log:/var/log/mysql
3. 配置文件
1) 创建 master 的 my_mariadb.cnf 文件
在 /home/docker/mysql_cluster/master/conf 目录下,创建 my_mariadb.cnf 文件,内容如下:
[mysqld]
server-id=1
port=3306
#basedir=/usr/local/mysql
#tmpdir=/tmp
datadir=/var/lib/mysql
# 查询日志,默认在 /var/lib/mysql 目录下
#general_log=1
#general_log_file=mysql_general-1.log
# 二进制日志,默认在 /var/lib/mysql 目录下
log_bin=mysql_binlog-1
# 慢查询日志,默认在 /var/log/mysql 目录下
#slow_query_log=1
#long_query_time=1
#slow_query_log_file=mysql_slow_query-1.log
# 错误日志,指定到 /var/log/mysql 目录
log_error=/var/log/mysql/mysql_err-1.log
注:MariaDB (MySQL) 的默认配置文件是 /etc/mysql/my.cnf 文件。如果想要自定义配置,在 /etc/mysql/conf.d 目录中创建 *.cnf 文件。新建的文件可以任意起名,只要保证后缀名是 cnf 即可。新建的文件中的配置项可以覆盖 /etc/mysql/my.cnf 中的配置项。
2) 创建 node_1 的 my_mariadb.cnf 文件
在 /home/docker/mysql_cluster/node_1/conf 目录下,创建 my_mariadb.cnf 文件,内容如下:
[mysqld]
server-id=2
port=3307
#basedir=/usr/local/mysql
#tmpdir=/tmp
datadir=/var/lib/mysql
# 查询日志,默认在 /var/lib/mysql 目录下
#general_log=1
#general_log_file=mysql_general-2.log
# 二进制日志,默认在 /var/lib/mysql 目录下
#log_bin=mysql_binlog-2
# 慢查询日志,默认在 /var/log/mysql 目录下
#slow_query_log=1
#long_query_time=1
#slow_query_log_file=mysql_slow_query-2.log
# 错误日志,指定到 /var/log/mysql 目录
log_error=/var/log/mysql/mysql_err-2.log
# relay-log
relay-log=mysql-relaylog-2
3) 创建 node_2 的 my_mariadb.cnf 文件
在 /home/docker/mysql_cluster/node_2/conf 目录下,创建 my_mariadb.cnf 文件,内容如下:
[mysqld]
server-id=3
port=3308
#basedir=/usr/local/mysql
#tmpdir=/tmp
datadir=/var/lib/mysql
# 查询日志,默认在 /var/lib/mysql 目录下
#general_log=1
#general_log_file=mysql_general-3.log
# 二进制日志,默认在 /var/lib/mysql 目录下
#log_bin=mysql_binlog-3
# 慢查询日志,默认在 /var/log/mysql 目录下
#slow_query_log=1
#long_query_time=1
#slow_query_log_file=mysql_slow_query-3.log
# 错误日志,指定到 /var/log/mysql 目录
log_error=/var/log/mysql/mysql_err-3.log
# relay-log
relay-log=mysql-relaylog-3
4. 启动
$ cd /home/docker/mysql_cluster # 进入 docker-compose.yml 所在目录
$ docker-compose up -d # 在后台运行
[+] Running 4/4
⠿ Network mysql_cluster_default Created 0.0s
⠿ Container mariadb_node_2-10.4 Started 0.6s
⠿ Container mariadb_master-10.4 Started 0.6s
⠿ Container mariadb_node_1-10.4 Started 0.7s
注:本地 docker 没有所需要的镜像时,会自动下载所需的镜像。遇到无法自动下载的情况,可以使用 docker pull 命令下载所需的镜像,再运行 docker-compose up 命令。
$ docker images # 查看镜像
REPOSITORY TAG IMAGE ID CREATED SIZE
mariadb 10.4 801fdf0164b2 2 weeks ago 404MB
$ docker-compose ps # 类似 docker ps 的作用
NAME COMMAND SERVICE STATUS PORTS
mariadb_master-10.4 ... mariadb_master running 0.0.0.0:3306->3306/tcp,...
mariadb_node_1-10.4 mariadb_node_1 running 0.0.0.0:3307->3307/tcp,...
mariadb_node_2-10.4 mariadb_node_2 running 0.0.0.0:3308->3308/tcp,...
容器内的程序要在挂载的 log 目录下创建 log 文件,需要确保 root/root 以外的用户也有 log 目录的写权限,修改 log 目录的权限,命令如下:
$ chmod a+w /home/docker/mysql_cluster/master/log /home/docker/mysql_cluster/node_1/log /home/docker/mysql_cluster/node_2/log
修改后需要重启容器,命令如下:
$ docker restart mariadb_master-10.4 mariadb_node_1-10.4 mariadb_node_2-10.4
5. 配置主从复制
1) master 配置
$ docker exec -it mariadb_master-10.4 /bin/bash # 进入 master 容器
# 进入容器后,使用 ip addr 命令查看容器内 IP 地址
root@986cfd3cdf63:/# ip addr
...
124: eth0@if125: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:19:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.25.0.4/16 brd 172.25.255.255 scope global eth0
valid_lft forever preferred_lft forever
注:这里容器内 IP 地址为 172.25.0.4
# 进入 MySQL 命令行控制台
root@986cfd3cdf63:/# mysql -u root -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
...
# 运行以下 MariaDB 命令,查看 log-bin 的开启状态,ON 表示开启,OFF 表示关闭
MariaDB [(none)]> show variables where variable_name like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin | ON |
+---------------+-------+
1 row in set (0.001 sec)`
# 创建数据库用户
MariaDB [(none)]> grant replication slave on *.* to 'node_copy'@'%' identified by '123456';
Query OK, 0 rows affected (0.002 sec)
MariaDB [(none)]> show grants for 'node_copy';
+--------------------------------------------------------------+
| Grants for node_copy@% |
+--------------------------------------------------------------+
| GRANT REPLICATION SLAVE ON *.* TO `node_copy`@`%` ...
+--------------------------------------------------------------+
1 row in set (0.000 sec)
# 查看主机状态
MariaDB [(none)]> show master status;
+-----------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-----------------------+----------+--------------+------------------+
| mysql_binlog-1.000001 | 333 | | |
+-----------------------+----------+--------------+------------------+
1 row in set (0.000 sec)
注:做主从复制前,最好将主数据库进行备份。
2) node_1 配置
$ docker exec -it mariadb_node_1-10.4 /bin/bash # 进入 node_1 容器
# 进入 MySQL 命令行控制台
root@59cf938b5a35:/# mysql -P 3307 -u root -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
...
MariaDB [(none)]> stop slave;
Query OK, 0 rows affected (0.006 sec)
# 运行如下命令连接到 master
MariaDB [(none)]> change master to master_host='172.25.0.4',master_port=3306,
-> master_user='node_copy',master_password='123456',
-> master_log_file='mysql_binlog-1.000001', master_log_pos=333;
参数说明:
master_host:主数据库的 IP 地址;
master_port:主数据库的运行端口;
master_user:在主数据库创建的用于同步数据的用户账号;
master_password:在主数据库创建的用于同步数据的用户密码;
master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取 File 参数;
master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取Position 参数;
master_connect_retry:连接失败重试的时间间隔,单位为秒。
注:如果 change master 不成功,可以尝试运行 reset slave; 后再试。
master_host、master_log_file 和 master_log_pos,在运行 docker-compose down 命令后,
再运行 docker-compose up 命令,会发生变化,需要重新配置。
MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.001 sec)
MariaDB [(none)]> show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.25.0.4
Master_User: node_copy
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql_binlog-1.000001
Read_Master_Log_Pos: 672
Relay_Log_File: mysql-relaylog-2.000001
Relay_Log_Pos: 707
Relay_Master_Log_File: mysql_binlog-1.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...
1 row in set (0.000 sec)
注:Slave_IO_Running 和 Slave_SQL_Running 都是 Yes,表示 node_1 已经连接上 Master。
3) node_2 配置
$ docker exec -it mariadb_node_2-10.4 /bin/bash # 进入 node_2 容器
# 进入 MySQL 命令行控制台
root@43302d136143:/# mysql -P 3308 -u root -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
...
MariaDB [(none)]> stop slave;
Query OK, 0 rows affected (0.006 sec)
# 运行如下命令连接到 master
MariaDB [(none)]> change master to master_host='172.25.0.4', master_port=3306,
-> master_user='node_copy', master_password='123456',
-> master_log_file='mysql_binlog-1.000001', master_log_pos=333;
MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.001 sec)
MariaDB [(none)]> show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.25.0.4
Master_User: node_copy
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql_binlog-1.000001
Read_Master_Log_Pos: 333
Relay_Log_File: mysql-relaylog-3.000002
Relay_Log_Pos: 560
Relay_Master_Log_File: mysql_binlog-1.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...
1 row in set (0.000 sec)
注:Slave_IO_Running 和 Slave_SQL_Running 都是 Yes,表示 node_2 已经连接上 Master。
4) 测试
在 master 的 MariaDB 命令行下,运行如下命令:
MariaDB [(none)]> CREATE DATABASE IF NOT EXISTS testdb;
Query OK, 1 row affected (0.000 sec)
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| testdb |
+--------------------+
4 rows in set (0.001 sec)
在 node_1 的 MariaDB 命令行下,运行如下命令:
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| testdb |
+--------------------+
4 rows in set (0.000 sec)
在 node_2 的 MariaDB 命令行下,运行如下命令:
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| testdb |
+--------------------+
4 rows in set (0.000 sec)
测试成功,node_1 和 node_2 上都出现了 testdb 数据库。
5) 命令说明
show master status; # 查看 master 的状态,当前的日志及位置
show slave status; # 查看 slave 的状态.
reset slave; # 重置 slave 状态,用于删除 slave 数据库的 relaylog 日志文件,并重新启用新的 relay-log 文件。并会重置主从关系,删除 master.info 文件和 relay-log.info 文件
start slave; # 启动 slave 状态 (开始监听 msater 的变化)
stop slave; # 停止 slave 状态;
set global sql_slave_skip_counter = n # 跳过导致复制终止的n个事件,仅在 slave 线程没运行的状况下使用