环境说明
两台虚拟机环境:
主机名 | ip地址 | OS版本 | 内存、CPU | 节点角色 | 数据库端口 |
---|---|---|---|---|---|
mysql91 | *.*.*.10 | CentOS Stream release 8 | 4G 、 1个双核 | 主节点 | 3306 |
mysql92 | *.*.*.11 | CentOS Stream release 8 | 4G 、 1个双核 | 主节点 | 3306 |
keepalived vip:*.*.*.20
MySQL 9.0.0双主搭建过程
安装 MySQL SERVER 9.0.0
两个节点都安装,安装方法请参考:MySQL 9.0.0 创新版悄悄地来了
修改/etc/my.cnf
*.*.*.10:
datadir=/data/data
socket=/data/data/mysql.sock
log-error=/data/data/mysqld.log
pid-file=/data/data/mysqld.pid
auto_increment_increment = 2 #表示自增列值的步长
auto_increment_offset = 1 #表示自增列值的偏移量,即起始点
server_id=10 #server_id参数必须不同
gtid-mode=on # 启用gtid类型,否则就是普通的复制架构
enforce-gtid-consistency=true # 强制GTID的一致性
log-slave-updates=1
*.*.*.11:
datadir=/data/data
socket=/data/data/mysql.sock
log-error=/data/data/mysqld.log
pid-file=/data/data/mysqld.pid
auto_increment_increment = 2 #表示自增列值的步长
auto_increment_offset = 2 #表示自增列值的偏移量,即起始点
server_id=11 #server_id参数必须不同
gtid-mode=on # 启用gtid类型,否则就是普通的复制架构
enforce-gtid-consistency=true # 强制GTID的一致性
log-slave-updates=1
重启 MySQL SERVER 服务
两个节点都重启mysqld服务
[root@mysql91 data]# systemctl restart mysqld
[root@mysql92 data]# systemctl restart mysqld
配置主从同步
创建复制用户并授权
两个节点都执行:
mysql> create user 'repl'@'192.%' identified by 'Wel%1234';
Query OK, 0 rows affected (0.03 sec)
mysql> grant replication slave,replication client,super,reload,process on *.* to 'repl'@'192.%';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
开启主从同步(*.*.*.10->*.*.*.11)
*.*.*.11上执行:
mysql> CHANGE REPLICATION SOURCE TO source_host='*.*.*.10',source_user='repl',source_password='Wel%1234',source_AUTO_POSITION=1,get_source_public_key=1;
Query OK, 0 rows affected, 2 warnings (0.05 sec)
mysql> start replica;
Query OK, 0 rows affected (0.03 sec)
mysql> show replica status\G;
*************************** 1. row ***************************
Replica_IO_State: Waiting for source to send event
Source_Host: *.*.*.10
Source_User: repl
Source_Port: 3306
Connect_Retry: 60
Source_Log_File: binlog.000004
Read_Source_Log_Pos: 158
Relay_Log_File: mysql92-relay-bin.000002
Relay_Log_Pos: 369
Relay_Source_Log_File: binlog.000004
Replica_IO_Running: Yes
Replica_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Source_Log_Pos: 158
Relay_Log_Space: 582
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Source_SSL_Allowed: No
Source_SSL_CA_File:
Source_SSL_CA_Path:
Source_SSL_Cert:
Source_SSL_Cipher:
Source_SSL_Key:
Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Source_Server_Id: 10
Source_UUID: 274652be-3928-11ef-ac20-000c2946aecd
Source_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
Source_Retry_Count: 10
Source_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Source_SSL_Crl:
Source_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Source_TLS_Version:
Source_public_key_path:
Get_Source_public_key: 1
Network_Namespace:
1 row in set (0.00 sec)
ERROR:
No query specified
创建数据库测试
*.*.*.10上创建数据库,*.*.*.11上检查同步情况
经检查,同步正常。截图如下:
插入表数据测试
*.*.*.10:
mysql> create table tab1(id int auto_increment primary key,name varchar(20));
Query OK, 0 rows affected (0.03 sec)
mysql> insert into tab1(name) values('a');
Query OK, 1 row affected (0.01 sec)
mysql> insert into tab1(name) values('b');
Query OK, 1 row affected (0.01 sec)
mysql> select * from tab1;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 3 | b |
+----+------+
2 rows in set (0.00 sec)
开启主从同步(*.*.*.11->*.*.*.10)
*.*.*.10上执行:
mysql> CHANGE REPLICATION SOURCE TO source_host='*.*.*.11',source_user='repl',source_password='Wel%1234',source_AUTO_POSITION=1,get_source_public_key=1;
Query OK, 0 rows affected, 2 warnings (0.05 sec)
mysql> start replica;
Query OK, 0 rows affected (0.03 sec)
mysql> show replica status\G;
*************************** 1. row ***************************
Replica_IO_State: Waiting for source to send event
Source_Host: *.*.*.11
Source_User: repl
Source_Port: 3306
Connect_Retry: 60
Source_Log_File: binlog.000004
Read_Source_Log_Pos: 158
Relay_Log_File: mysql92-relay-bin.000002
Relay_Log_Pos: 369
Relay_Source_Log_File: binlog.000004
Replica_IO_Running: Yes
Replica_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Source_Log_Pos: 158
Relay_Log_Space: 582
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Source_SSL_Allowed: No
Source_SSL_CA_File:
Source_SSL_CA_Path:
Source_SSL_Cert:
Source_SSL_Cipher:
Source_SSL_Key:
Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Source_Server_Id: 10
Source_UUID: 274652be-3928-11ef-ac20-000c2946aecd
Source_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
Source_Retry_Count: 10
Source_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Source_SSL_Crl:
Source_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Source_TLS_Version:
Source_public_key_path:
Get_Source_public_key: 1
Network_Namespace:
1 row in set (0.00 sec)
ERROR:
No query specified
创建数据库测试
*.*.*.11上创建数据库,*.*.*.10上检查同步情况
经检查,同步正常。截图如下:
插入表数据测试
*.*.*.11
mysql> insert into tab1(name) values('c');
Query OK, 1 row affected (0.00 sec)
mysql> insert into tab1(name) values('d');
Query OK, 1 row affected (0.00 sec)
mysql> select * from tab1;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 3 | b |
| 4 | c |
| 6 | d |
+----+------+
结论:
1、双主架构下,对于存在自增列的表,每个节点都可以插入数据,并且数据发生不会冲突。需要注意的是:id自增列值不连续。1个节点插入完数据,另1个节点插入数据的时候是以表中自增列当前最大的值为基础进行增加的。比如:节点1已经插入了id为1,3的数据,节点2就不能插入2这条数据了,自增列只能从4开始;节点1已经插入了id为1,3,5的数据,节点2就不能插入4这条数据了,自增列只能从6开始。
2、双主架构下,对于不存在自增列的表,每个节点都插入数据很可能造成数据的不一致。
综上,双主架构+双写其实比较容易出现数据不一致的问题,因此最好借助keepalived,通过vip进行登录,在1个节点做数据库操作,也即进行双主单写。如果数据库出现问题导致vip发生了切换,也不需要人工干预,业务自动连接另一个正常的节点进行操作。但是,需要注意的是,运维同事一定要通过vip连接到数据库主机上,不能直接通过物理ip连接到数据库主机上进行数据的增删改查,否则也很容易会造成数据的不一致。下面是keepalived的搭建过程。
keepalived搭建过程
keepalived下载
下载地址:https://www.keepalived.org/download.html
keepalived安装
两个节点都安装keepalived。
[root@mysql91 ~]# tar -zxvf keepalived-2.3.1.tar.gz
[root@mysql91 ~]# cd keepalived-2.3.1/
[root@mysql91 keepalived-2.3.1]# ./configure --prefix=/data/keepalived
[root@mysql91 keepalived-2.3.1]# make && make install
安装完成后会在以下路径生成:
/data/keepalived/etc/keepalived/keepalived.conf.sample
/data/keepalived/etc/sysconfig/keepalived
/data/keepalived/sbin/keepalived
keepalived配置
两个节点都配置keepalived。
[root@mysql91 ~]# mkdir -p /etc/keepalived
[root@mysql91 keepalived]# cp /data/keepalived/etc/keepalived/keepalived.conf.sample /etc/keepalived/keepalived.conf
[root@mysql91 keepalived]# ll /etc/keepalived/
total 4
-rw-r--r--. 1 root root 3625 Jul 4 14:00 keepalived.conf
配置/etc/keepalived/keepalived.conf脚本:
*.*.*.10
--检测脚本
vrrp_script chkmysql {
script "/root/chkmysql.sh" # 检测脚本的位置
interval 3 # 每隔 3 秒执行一次
weight -20 # 权重 -20 ,根据检测脚本的返回值去判断是否要减掉
}
vrrp_instance VI_1 {
state MASTER
interface ens160
virtual_router_id 51
priority 100 #权重
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
*.*.*.20/24
}
# Allow packets addressed to the VIPs above to be received
accept
#检查脚本,与vrrp_script对应
track_script{
chkmysql
}
}
*.*.*.11
vrrp_script chkmysql {
script "/root/chkmysql.sh" # 检测脚本的位置
interval 3 # 每隔 3 秒执行一次
weight -20 # 权重 -20 ,根据检测脚本的返回值去判断是否要减掉
}
vrrp_instance VI_1 {
state MASTER
interface ens160
virtual_router_id 51
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
*.*.*.20/24
}
# Allow packets addressed to the VIPs above to be received
accept
#检查脚本,与vrrp_script对应
track_script{
chkmysql
}
}
配置检测脚本
两个节点/root/chkmysql.sh 脚本内容相同。
[root@mysql91 ~]# cat /root/chkmysql.sh
#!/bin/bash
counter=$(netstat -na|grep "LISTEN"|grep "3306"|wc -l)
if [ "${counter}" -eq 0 ]; then
systemctl stop keepalived
fi
keepalived测试
--在*.*.*.10节点操作:
[root@mysql91 ~]# ip a|grep 192
inet *.*.*.10/24 brd *.*.*.255 scope global noprefixroute ens160
inet *.*.*.20/24 scope global secondary ens160
[root@mysql91 ~]# systemctl stop mysqld
[root@mysql91 ~]# ip a|grep 192
inet *.*.*.10/24 brd *.*.*.255 scope global noprefixroute ens160
--在*.*.*.11节点操作:
[root@mysql92 ~]# ip a|grep 192
inet *.*.*.11/24 brd *.*.*.255 scope global noprefixroute ens160
inet *.*.*.20/24 scope global secondary ens160:1
可以看到,关掉*.*.*.10节点的mysql数据库后,vip已经飘到了*.*.*.11节点。
--在*.*.*.10节点操作:
[root@mysql91 ~]# systemctl start mysqld
[root@mysql91 ~]# ip a|grep 192
inet *.*.*.10/24 brd *.*.*.255 scope global noprefixroute ens160
[root@mysql91 ~]# systemctl start keepalived
[root@mysql91 ~]# ip a|grep 192
inet *.*.*.10/24 brd *.*.*.255 scope global noprefixroute ens160
inet *.*.*.20/24 scope global secondary ens160
--在*.*.*.11节点操作:
[root@mysql92 ~]# ip a|grep 192
inet *.*.*.11/24 brd *.*.*.255 scope global noprefixroute ens160
可以看到,当把*.*.*.10上面的mysql库和keepalived启动后,由于*.*.*.10上面的keepalived优先级比*.*.*.10的高,所以vip又发生了回切。
碰到的问题
show replica status\G;报错:
Last_IO_Errno: 2061
Last_IO_Error: Error connecting to source 'repl@*.*.*.10:3306'. This was attempt 1/10, with a delay of 60 seconds between attempts. Message: Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection.
解决办法:
1.从库执行 stop slave;
2.清除从库配置:reset slave all;
3.重新配置主库信息
CHANGE REPLICATION SOURCE TO source_host='*.*.*.10',source_user='repl',source_password='Wel%1234',source_AUTO_POSITION=1,get_source_public_key=1;
4.开启复制 start replica;
5.查询复制状态:show replica status\G;
参考文档
https://dev.mysql.com/doc/refman/9.0/en/change-replication-source-to.html
https://www.cnblogs.com/xiaoyaozhe/p/17671354.html
总结
MYSQL双主+keepalived架构的安装配置过程还是非常丝滑的~~~
乐知乐享,把知识分享出来,大家一起进步~