X86架构服务器/虚拟机基于Docker和Keepalived搭建MySQL8.0.30主主复制集群
前置条件:1、各节点均已安装操作系统 OpenEuler 20.03 (LTS-SP3)
文章目录
十一、各节点通过Docker运行MySQL容器,并限制MySQL容器的CPU和内存资源
十二、各节点MySQL添加新账号test,并禁用root账号(生产环境,为了安全,通常禁用root账号)
MySQL主从复制和双主复制的区别:
- 主从复制(Master-Slave):指的是一个主MySQL服务器(Master)和一个从MySQL服务器(Slave)。在这种配置下,数据只会从Master流向Slave。Slave是Master的副本,用于读查询、备份等非改变数据的操作。
- 双主复制(Master-Master,也称为主主复制、双向复制或互为主从):是指两个MySQL服务器互相设置对方为主服务器和从服务器。在这种配置下,任何一个服务器上的数据改变都会实时同步到另一个服务器。可以结合Keepalived,基于双主复制,配置MySQL双活高可用。当一个MySQL实例宕机后,应用可以立即基于VIP切换到另一个MySQL实例。
节点名称 | IP地址 | CPU | 内存 | 磁盘 |
---|---|---|---|---|
主库01 | 192.168.111.198 | 8核 | 16GB | 500GB |
主库02 | 192.168.111.199 | 8核 | 16GB | 500GB |
前置条件:
1、各节点均已安装操作系统 OpenEuler 20.03 (LTS-SP3)
一、各节点文件夹创建
##创建文件夹
[root@localhost ~]# mkdir /home/data
##创建符号链接文件
[root@localhost ~]# ln -s /home/data /data
二、各节点配置静态IP
【主库01】修改
##修改参数
[root@localhost ~]# vi /etc/sysconfig/network-scripts/ifcfg-ens33
BOOTPROTO=static
DEFROUTE=yes
ONBOOT=yes
IPADDR=192.168.111.198
PREFIX=24
GATEWAY=192.168.111.1
DNS1=114.114.114.114
#其他参数不用修改...
##使配置生效。华为openeuler系统使用如下命令,其他linux系统可以使用systemctl restart network
[root@localhost ~]# nmcli con reload; nmcli con up ens33
【主库02】修改
##修改参数
[root@localhost ~]# vi /etc/sysconfig/network-scripts/ifcfg-ens33
BOOTPROTO=static
DEFROUTE=yes
ONBOOT=yes
IPADDR=192.168.111.199
PREFIX=24
GATEWAY=192.168.111.1
DNS1=114.114.114.114
#其他参数不用修改...
##使配置生效。华为openeuler系统使用如下命令,其他linux系统可以使用systemctl restart network
[root@localhost ~]# nmcli con reload; nmcli con up ens33
三、各节点关闭Selinux
## 永久配置
[root@localhost ~]# sed -i 's/enforcing/disabled/' /etc/selinux/config
## 临时配置
[root@localhost ~]# setenforce 0
## 查看结果
[root@localhost ~]# getenforce
四、各节点开启包转发功能和修改内核参数
参数说明:
- br_netfilter模块用于将桥接流量转发至iptables链,br_netfilter内核参数需要开启转发。
- net.ipv4.ip_forward=1 将Linux系统作为路由或者VPN服务就必须要开启IP转发功能。当linux主机有多个网卡时,一个网卡收到的信息是否能够传递给其他的网卡 ,如果设置成1 的话 可以进行数据包转发,可以实现VxLAN 等功能。不开启会导致docker部署应用无法访问。
1、动态地向内核中加载br_netfilter模块
[root@localhost ~]# modprobe br_netfilter
2、配置开机自动加载br_netfilter模块
- 新建rc.sysinit文件
[root@localhost ~]# vi /etc/rc.sysinit
#!/bin/bash
for file in /etc/sysconfig/modules/*.modules ; do
[ -x $file ] && $file
done
- 在/etc/sysconfig/modules/目录下新建br_netfilter.modules文件
[root@localhost ~]# vi /etc/sysconfig/modules/br_netfilter.modules
modprobe br_netfilter
- 配置执行权限
[root@localhost ~]# chmod +x /etc/sysconfig/modules/br_netfilter.modules
- 查看br_netfilter模块是否加载成功
[root@localhost ~]# lsmod | grep br_netfilter
br_netfilter 22256 0
bridge 155432 1 br_netfilter
3、修改内核参数
- 修改/etc/sysctl.conf文件
[root@localhost ~]# vi /etc/sysctl.conf
####注意:等号=左右不能有空格####
net.ipv4.ip_forward=1 #修改/新增这一行
#当keepalive打开的情况下,TCP发送keepalive消息的频率,默认值是7200(2小时)
net.ipv4.tcp_keepalive_time=1800
#TCP发送keepalive探测以确定该连接已经断开的次数,默认值是9
net.ipv4.tcp_keepalive_probes=5
#当探测没有确认时,重新发送探测的频度,默认值为75
net.ipv4.tcp_keepalive_intvl=5
#将桥接的IPv4流量传递到 iptables 的链
net.bridge.bridge-nf-call-ip6tables=1
net.bridge.bridge-nf-call-iptables=1
#调小TCP协议的time_wait超时时间,默认是240秒
net.ipv4.tcp_fin_timeout=30
- 执行生效
##加载指定的文件配置内核参数,-p后通常接一个文件路径,若为空,默认加载/etc/sysctl.conf中的内核参数
[root@localhost ~]# sysctl -p
##显示所有的内核参数
[root@localhost ~]# sysctl -a
##临时修改内核参数的值,重启后失效
[root@localhost ~]# sysctl -w net.ipv4.tcp_keepalive_time=1800
[root@localhost ~]# sysctl -w net.ipv4.tcp_keepalive_probes=5
[root@localhost ~]# sysctl -w net.ipv4.tcp_keepalive_intvl=5
##加载/etc/sysctl.d/目录下所有conf文件中的内核参数
[root@localhost ~]# sysctl --system
五、修改linux参数(调大最大文件句柄数)
方法一:
sudo vi /etc/security/limits.conf
在最后追加如下内容:
* soft nproc 65536
* hard nproc 65536
* soft nofile 65536
* hard nofile 65536
含义如下:
1)soft nproc: 可打开的文件描述符的最大数(软限制)
2)hard nproc: 可打开的文件描述符的最大数(硬限制)
3)soft nofile:单个用户可用的最大进程数量(软限制)
4)hard nofile:单个用户可用的最大进程数量(硬限制)
方法二:
sudo vi /etc/profile
#文件末尾添加下面这行,并保存:
ulimit -n 65535
# 重新加载修改的环境变量文件
sudo source /etc/profile
六、各节点添加YUM的Centos源和Docker镜像源
##下载
[root@localhost ~]# wget https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo \
-O /etc/yum.repos.d/CentOS-Base.repo
[root@localhost ~]# wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo \
-O /etc/yum.repos.d/docker-ce.repo
##更改名称
[root@localhost ~]# sed -i 's/\$releasever/8/g' /etc/yum.repos.d/docker-ce.repo
##清除缓存
[root@localhost ~]# yum clean all
##刷新缓存
[root@localhost ~]# yum makecache
七、各节点安装Docker
- 安装
[root@localhost ~]# yum install docker-ce docker-compose-plugin -y
- 启动
[root@localhost ~]# systemctl start docker
- 配置开机启动
[root@localhost ~]# systemctl enable docker
- 配置国内镜像地址
[root@localhost ~]# cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": [
"http://hub-mirror.c.163.com",
"https://9ca7kqhd.mirror.aliyuncs.com",
"https://registry.docker-cn.com"
]
}
EOF
- 重启
[root@localhost ~]# systemctl restart docker
八、各节点Docker与Firewalld冲突解决
资料参考:docker与firewalld冲突解决_docker firewalld-CSDN博客
说明:Firewall的底层使用iptables进行数据过滤,而Docker也使用iptables来进行网络隔离和管理。这可能导致Firewall与Docker产生冲突。当Firewalld启动或者重启的时候,将会从iptables中移除 Docker的规则,从而影响了 Docker 的正常工作。
##查询iptables链
[root@localhost ~]# iptables -L
##修改docker配置,绕过iptables,添加最后2行
[root@localhost ~]# vi /etc/docker/daemon.json
{
"registry-mirrors": [
"http://hub-mirror.c.163.com",
"https://9ca7kqhd.mirror.aliyuncs.com",
"https://registry.docker-cn.com"
],
"experimental" : true, #添加此行
"iptables": false #添加此行
}
##重启docker
[root@localhost ~]# systemctl daemon-reload
[root@localhost ~]# systemctl restart docker
##重启防火墙
[root@localhost ~]# systemctl restart firewalld
##配置防火墙开机自启
[root@localhost ~]# systemctl enable firewalld
##再次重启Docker
[root@localhost ~]# systemctl restart docker
此时,Docker容器的端口只能由本机(运行Docker容器的宿主机)访问,可以通过firewall-cmd命令开放其他主机访问本机的Docker容器。(详见:Linux系统中配置防火墙-CSDN博客)
九、各节点防火墙配置
##关闭iptables
[root@localhost ~]# systemctl stop iptables
##禁止开机启动iptables
[root@localhost ~]# systemctl disable iptables
##检查是否允许 NAT 转发,若是yes,表示已开启
[root@localhost ~]# firewall-cmd --query-masquerade
##若未开启,则如下配置
[root@localhost ~]# firewall-cmd --permanent --zone=public --add-masquerade
##开放端口,所有主机都可以访问
[root@localhost ~]# firewall-cmd --zone=public --add-port=3306/tcp --permanent
##配置防火墙,允许Keepalived的VRRP流量通过(注意,根据主机的网卡配置相应修改ens33)
[root@localhost ~]# firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 --in-interface ens33 --destination 224.0.0.18 --protocol vrrp -j ACCEPT
[root@localhost ~]# firewall-cmd --direct --permanent --add-rule ipv4 filter OUTPUT 0 --out-interface ens33 --destination 224.0.0.18 --protocol vrrp -j ACCEPT
##重新载入,使配置生效
[root@localhost ~]# firewall-cmd --reload
##查看配置结果
[root@localhost ~]# firewall-cmd --list-all
##查看防火墙所有开放的端口
[root@localhost ~]# firewall-cmd --zone=public --list-ports
十、各节点提前准备MySQL双主复制的配置文件
##创建文件夹
[root@localhost ~]# mkdir -p /data/docker/mysql/conf
##创建my.cnf文件
[root@localhost ~]# touch /data/docker/mysql/conf/my.cnf
【主库01】配置
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
[mysqld]
#日志留存时间180天
expire_logs_days = 180
#启用MySQL的通用查询日志,可以在该日志中查看SQL执行记录
general_log = 1
general_log_file = /var/log/mysql/general.log
#MySQL监听的IP地址,如果是127.0.0.1,表示仅本机访问
bind_address=0.0.0.0
#MySQL监听端口
port=3306
#以默认的mysql用户运行
user=mysql
#服务端默认编码(数据库级别)
character-set-server=utf8mb4
#最大可连接数
max_connections = 2000
#开启慢日志
slow_query_log=ON
#设置慢查询时间
long_query_time=10
#慢查询日志保存位置
slow_query_log_file=/var/log/mysql/slowquery.log
#记录所有没有用上索引全表扫描的语句
log_queries_not_using_indexes=1
#记录optimize table,analyze table和alter table等语句引发的慢查询
log_slow_admin_statements=1
#数据库实例唯一标识
#启用主从、双主和集群的时候必须指定,每个节点必须不同
#注意与【主库02】的区别
server-id=1
#设置中继日志位置和名称
relay_log=slave-relay-bin
#设置中继日志索引位置和名称
relay_log_index=slave-relay-bin.index
#从其他主库同步的数据也记录二进制文件
#8.0.23之前,使用log_slave_updates
log_replica_updates=1
#读写模式
read_only=0
#自动清空中继日志
relay_log_purge=1
#中继日志损坏自动恢复同步
relay_log_recovery=1
#二进制文件名称集路径
log_bin=master-bin
#二进制文件索引名称集路径
log_bin_index=master-bin.index
#基于行级别的日志,默认为MIXED混合模式
binlog_format=ROW
#在row模式下开启该参数,将把sql语句打印到binlog日志里面。默认是0(off);
binlog_rows_query_log_events=on
#binlog缓存大小
binlog_cache_size=4M
#binlog日志有效时间(14天)
binlog_expire_logs_seconds=604800
#提交事务刷新数据到磁盘,默认为0
#当设置为“1”的时候,是最安全但是性能损耗最大的设置。
#为“1”时,即使系统Crash,最多丢失binlog_cache中未完成的一个事务,对实际数据没有实质影响。
#对于高并发事务系统,“sync_binlog”设置为0和设置为1的系统写入性能差距可能高达5倍甚至更多。
sync_binlog=1000
#每次事务提交的时候,都把log buffer刷到文件系统中(os buffer)去
#并且调用文件系统的“flush”操作将缓存刷新到磁盘上去
innodb_flush_log_at_trx_commit=2
#指定并行工作线程的数量,可以显著提高复制效率
slave_parallel_workers=4
#最小化日志大小,默认情况下,binlog_row_image 的值是 FULL
binlog_row_image=MINIMAL
#启用全局事务ID,模式为3(默认为0)
gtid_mode=on
#强制启用GTID一致性
enforce_gtid_consistency=on
binlog_gtid_simple_recovery=1
#自增步长
auto_increment_increment=2
#自增起始值
#注意与【主库02】的区别
auto_increment_offset=1
#备份过滤不同步的库
replicate-ignore-db=mysql,information_schema,performance_schema,sys
#数据文件存放的目录
datadir=/var/lib/mysql
#为MySQL客户端程序和服务器之间的本地通讯指定一个套接字文件
socket=/var/run/mysqld/mysqld.sock
#错误日志文件
log-error=/var/log/mysql/mysqld-error.log
#pid文件所在目录
pid-file=/var/run/mysqld/mysqld.pid
#定义了MySQL应该支持的sql语法,用于数据校验,限制不合法操作
#MySQL8是没有 NO_AUTO_CREATE_USER,所有Sql_mode中不能包含这一项
sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'
#跳过域名解析。设置为ON可以提高连接速度,但是会导致无法使用主机名连接服务器。
skip_name_resolve
#定义日志文件的时间戳格式
log_timestamps = SYSTEM
#设置服务器的默认时区
default-time-zone = '+8:00'
#指定哪些数据库不写入二进制日志
binlog-ignore-db=mysql,information_schema,performance_schema,sys
【主库02】配置
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
[mysqld]
#日志留存时间180天
expire_logs_days = 180
#启用MySQL的通用查询日志,可以在该日志中查看SQL执行记录
general_log = 1
general_log_file = /var/log/mysql/general.log
#MySQL监听的IP地址,如果是127.0.0.1,表示仅本机访问
bind_address=0.0.0.0
#MySQL监听端口
port=3306
#以默认的mysql用户运行
user=mysql
#服务端默认编码(数据库级别)
character-set-server=utf8mb4
#最大可连接数
max_connections = 2000
#开启慢日志
slow_query_log=ON
#设置慢查询时间
long_query_time=10
#慢查询日志保存位置
slow_query_log_file=/var/log/mysql/slowquery.log
#记录所有没有用上索引全表扫描的语句
log_queries_not_using_indexes=1
#记录optimize table,analyze table和alter table等语句引发的慢查询
log_slow_admin_statements=1
#数据库实例唯一标识
#启用主从、双主和集群的时候必须指定,每个节点必须不同
#注意与【主库01】的区别
server-id=2
#设置中继日志位置和名称
relay_log=slave-relay-bin
#设置中继日志索引位置和名称
relay_log_index=slave-relay-bin.index
#从其他主库同步的数据也记录二进制文件
#8.0.23之前,使用log_slave_updates
log_replica_updates=1
#读写模式
read_only=0
#自动清空中继日志
relay_log_purge=1
#中继日志损坏自动恢复同步
relay_log_recovery=1
#二进制文件名称集路径
log_bin=master-bin
#二进制文件索引名称集路径
log_bin_index=master-bin.index
#基于行级别的日志,默认为MIXED混合模式
binlog_format=ROW
#在row模式下开启该参数,将把sql语句打印到binlog日志里面。默认是0(off);
binlog_rows_query_log_events=on
#binlog缓存大小
binlog_cache_size=4M
#binlog日志有效时间(14天)
binlog_expire_logs_seconds=604800
#提交事务刷新数据到磁盘,默认为0
#当设置为“1”的时候,是最安全但是性能损耗最大的设置。
#为“1”时,即使系统Crash,最多丢失binlog_cache中未完成的一个事务,对实际数据没有实质影响。
#对于高并发事务系统,“sync_binlog”设置为0和设置为1的系统写入性能差距可能高达5倍甚至更多。
sync_binlog=1000
#每次事务提交的时候,都把log buffer刷到文件系统中(os buffer)去
#并且调用文件系统的“flush”操作将缓存刷新到磁盘上去
innodb_flush_log_at_trx_commit=2
#指定并行工作线程的数量,可以显著提高复制效率
slave_parallel_workers=4
#最小化日志大小,默认情况下,binlog_row_image 的值是 FULL
binlog_row_image=MINIMAL
#启用全局事务ID,模式为3(默认为0)
gtid_mode=on
#强制启用GTID一致性
enforce_gtid_consistency=on
binlog_gtid_simple_recovery=1
#自增步长
auto_increment_increment=2
#自增起始值
#注意与【主库01】的区别
auto_increment_offset=2
#备份过滤不同步的库
replicate-ignore-db=mysql,information_schema,performance_schema,sys
#数据文件存放的目录
datadir=/var/lib/mysql
#为MySQL客户端程序和服务器之间的本地通讯指定一个套接字文件
socket=/var/run/mysqld/mysqld.sock
#错误日志文件
log-error=/var/log/mysql/mysqld-error.log
#pid文件所在目录
pid-file=/var/run/mysqld/mysqld.pid
#定义了MySQL应该支持的sql语法,用于数据校验,限制不合法操作
#MySQL8是没有 NO_AUTO_CREATE_USER,所有Sql_mode中不能包含这一项
sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'
#跳过域名解析。设置为ON可以提高连接速度,但是会导致无法使用主机名连接服务器。
skip_name_resolve
#定义日志文件的时间戳格式
log_timestamps = SYSTEM
#设置服务器的默认时区
default-time-zone = '+8:00'
#指定哪些数据库不写入二进制日志
binlog-ignore-db=mysql,information_schema,performance_schema,sys
十一、各节点通过Docker运行MySQL容器,并限制MySQL容器的CPU和内存资源
## 运行MySQL容器,若此时宿主机没有MySQL镜像,会自动从docker hub拉取镜像,请确保能连互联网
[root@localhost ~]# docker run --cpus=4 --memory=7g --memory-swap=1g \
--privileged=true --name 容器名 -p 3306:3306 \
-e MYSQL_ROOT_HOST=% -e MYSQL_ROOT_PASSWORD=root账号的密码 \
-v /etc/localtime:/etc/localtime \
-v /data/docker/mysql/conf/:/etc/mysql/conf.d \
-v /data/docker/mysql/logs:/var/log/mysql \
-v /data/docker/mysql/data:/var/lib/mysql \
--restart=always -d mysql:8.0.30
参数说明:
- -v /data/docker/mysql/conf/:/etc/mysql/conf.d是挂载MySQL的配置文件。当我们进入docker内部查看MySQL配置文件的时候,发现/etc/mysql/conf.d只是一个文件夹。在MySQL中,/etc/my.cnf 是默认配置文件,/etc/mysql/conf.d/ 下的文件为自定义配置文件。由于docker的/etc/mysql/conf.d文件挂载到本地系统的/data/docker/mysql/conf/,因此我们只需在本地系统的/data/docker/mysql/conf/写入自定义配置文件即可修改Docker容器中的MySQL配置。
- --cpus: 限制容器运行的核数,可以使用小数。等效于--cpu-period和--cpu-quota的设置,直接配置--cpus 即可。三者关系是:--cpus = --cpu-quota / --cpu-period。
- -m 或 --memory:设置内存的使用限额,格式是数字加单位,单位可以为 b,k,m,g,例如:100m,2g,最小为 4MB
- --memory-swap:内存+交换分区大小总限制,格式是数字加单位,单位可以为 b,k,m,g。
若宿主机只有一个容器,需要确保容器的CPU和内存限制到宿主机的50%以下。若宿主机上运行多个容器,多个容器之间需要协调配置,确保所有容器的CPU和内存限制到宿主机的50%以下。此例中,宿主机只有一个MySQL容器,宿主机的CPU的总核数是8核,给容器分配了4核,限制了容器运行时最多占用50%的CPU资源。宿主机的总内存是16GB,给容器分配了7GB的内存,另外分配了1GB的swap内存,限制了容器运行时最多占用50%的内存资源。
注意:
1、限制容器的CPU和内存后,可能出现容器频繁重启的问题,这时需要在docker run前,删除之前运行该Docker容器的数据。
2、通过docker run限制CPU和内存后,如果想临时修改CPU和内存的限额,可以通过如下命令:
#临时更新CPU的限额为2核,容器重启后失效
docker update --cpus=2 容器名
#临时更新内存的限额为4GB,容器重启后失效
docker update -m=4G 容器名
#查看是否生效
docker inspect 容器名
扩展知识:
默认情况下,--memory-swap和--memory两组参数默认为-1,即对容器内存和swap的使用没有限制。如果在启动容器时,只指定--memory而不指定--memory-swap, 那么--memory-swap默认为--memory的两倍。swap是交换分区空间,是用磁盘空间交换来的虚拟空间。宿主机的内存由内存空间memory和交换分区空间swap两部分构成,通过free -h可以查看。--memory-swap包含了--memory,--memory-swap减去--memory就得到容器可以占用的swap的空间。--memory-swap通常需要大于等于--memory。若禁用swap,只需确保--memory-swap和--memory的值一样即可。
一般有四种设置方式:
1. 不设置
如果不设置-m,--memory和--memory-swap,两组参数默认是-1,容器默认可以用完宿主机的所有内存和 swap 分区。不过注意,如果容器占用宿主机的所有内存和 swap 分区超过一段时间后,会被宿主机系统杀死(如果没有设置--oom-kill-disable的话)。2. 设置-m,--memory,不设置--memory-swap
给-m或--memory设置一个不小于 4M 的值,假设为 a,不设置--memory-swap。这种情况下,容器能使用的内存大小为 a,能使用的交换分区大小也为 a,因为 Docker 默认容器交换分区的大小和内存相同。如果在容器中运行一个一直不停申请内存的程序,你会观察到该程序最终能占用的内存大小为 2a。比如$ docker run -m 1G ubuntu:16.04,该容器能使用的内存大小为 1G,能使用的 swap 分区大小也为 1G。容器内的进程能申请到的总内存大小为 2G。3. 设置-m,--memory=a,--memory-swap=b,且b > a
给-m设置一个参数 a,给--memory-swap设置一个参数 b。a 是容器能使用的内存大小,b是容器能使用的 内存大小 + swap 分区大小。所以 b 必须大于 a。b -a 即为容器能使用的 swap 分区大小。比如$ docker run -m 1G --memory-swap 3G ubuntu:16.04,该容器能使用的内存大小为 1G,能使用的 swap 分区大小为 2G。容器内的进程能申请到的总内存大小为 3G。4. 设置-m,--memory=a,--memory-swap=-1
给-m参数设置一个正常值,而给--memory-swap设置成 -1。这种情况表示限制容器能使用的内存大小为 a,而不限制容器能使用的 swap 分区大小。这时候,容器内进程能申请到的内存大小为 a + 宿主机的 swap 大小。
十二、各节点MySQL添加新账号test,并禁用root账号(生产环境,为了安全,通常禁用root账号)
## 进入MySQL容器
[root@localhost ~]# docker exec -it 容器名 /bin/bash
## 通过MySQL命令行终端进入MySQL
bash-4.4# mysql –uroot –p
## 输入运行MySQL容器时设置的“root账号的密码”
## 认证成功,进入MySQL命令行终端
mysql >
## 创建test用户,并设置密码为TestDb0101
mysql> CREATE USER 'test'@'%' IDENTIFIED BY 'TestDb0101';
mysql> CREATE USER 'test'@'localhost' IDENTIFIED BY 'TestDb0101';
## 为test用户授权
mysql> GRANT ALL PRIVILEGES ON *.* TO 'test'@'%' WITH GRANT OPTION;
mysql> GRANT ALL PRIVILEGES ON *.* TO 'test'@'localhost' WITH GRANT OPTION;
## 删除root账号
mysql> DROP USER 'root'@'%';
mysql> DROP USER 'root'@'localhost';
## 重新加载MySQL授权表,刷新权限
mysql> FLUSH PRIVILEGES;
## 退出MySQL命令终端
mysql> exit
十三、各节点MySQL创建slave用户,并授权复制权限
【主库01】执行
## 通过MySQL命令行终端进入MySQL
bash-4.4# mysql –utest –pTestDb0101
## 认证成功,进入MySQL命令行终端
mysql >
## 创建slave用户专门用于双主复制,并设置密码
mysql >create user 'slave'@'%' identified with mysql_native_password by 'TestDbSync0101';
## 授予复制权限
mysql >grant replication slave on *.* to 'slave'@'%';
## 重新加载MySQL授权表,刷新权限
mysql >FLUSH PRIVILEGES;
【主库02】执行
## 通过MySQL命令行终端进入MySQL
bash-4.4# mysql –utest –pTestDb0101
## 认证成功,进入MySQL命令行终端
mysql >
## 创建slave用户专门用于双主复制,并设置密码
mysql >create user 'slave'@'%' identified with mysql_native_password by 'TestDbSync0101';
## 授予复制权限
mysql >grant replication slave on *.* to 'slave'@'%';
## 重新加载MySQL授权表,刷新权限
mysql >FLUSH PRIVILEGES;
十四、各节点MySQL配置主从复制
【主库01】执行
## 删除所有的binglog日志文件,并将日志索引文件清空,重新开始所有新的日志文件
## 用于第一次进行搭建双主复制库时,进行主库binlog的初始化工作
mysql> reset master;
## 停止复制功能
mysql> stop slave;
## 查看master状态
## 结果中的File对应后面设置【主库02】的MASTER_LOG_FILE
## 结果中的Position对应后面设置【主库02】的MASTER_LOG_POS
mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000001 | 157 | | | |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
【主库02】执行
## 删除所有的binglog日志文件,并将日志索引文件清空,重新开始所有新的日志文件
## 用于第一次进行搭建双主复制库时,进行主库binlog的初始化工作
mysql> reset master;
## 停止复制功能
mysql> stop slave;
## 查看master状态
## 结果中的File对应后面设置【主库01】的MASTER_LOG_FILE
## 结果中的Position对应后面设置【主库01】的MASTER_LOG_POS
mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000001 | 157 | | | |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
【主库01】执行
## 将【主库02】设置为本节点的master
## MASTER_LOG_FILE对应【主库02】show master status查询结果的File
## MASTER_LOG_POS对应【主库02】show master status查询结果的Position
mysql> CHANGE MASTER TO MASTER_HOST='192.168.111.199',MASTER_PORT=3306,
MASTER_USER='slave',MASTER_PASSWORD='TestDbSync0101',
MASTER_AUTO_POSITION=1;
## 启用复制功能
mysql> start slave;
【主库02】执行
## 将【主库01】设置为本节点的master
## MASTER_LOG_FILE对应【主库01】show master status查询结果的File
## MASTER_LOG_POS对应【主库01】show master status查询结果的Position
mysql> CHANGE MASTER TO MASTER_HOST='192.168.111.198',MASTER_PORT=3306,
MASTER_USER='slave',MASTER_PASSWORD='TestDbSync0101',
MASTER_AUTO_POSITION=1;
## 启用复制功能
mysql> start slave;
MYSQL数据库双主复制已经配置好了,【主库01】和【主库02】上可以通过show slave status\G命令查看slave的状态,只要Slave_IO_Running和Slave_SQL_Running都是Yes,就表示双主复制配置成功。
【主库01】执行
## 查看slave状态
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.111.199
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master-bin.000003
Read_Master_Log_Pos: 197
Relay_Log_File: slave-relay-bin.000008
Relay_Log_Pos: 375
Relay_Master_Log_File: master-bin.000003
Slave_IO_Running: Yes
Slave_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_Master_Log_Pos: 197
Relay_Log_Space: 755
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 2
Master_UUID: 7397c458-0f68-11ef-a48b-0242ac110002
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Replica has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set: 5e8fbcfe-0f68-11ef-a4bd-0242ac110002:1-494
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
Master_public_key_path:
Get_master_public_key: 0
Network_Namespace:
1 row in set, 1 warning (0.00 sec)
【主库02】执行
## 查看slave状态
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.111.198
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master-bin.000003
Read_Master_Log_Pos: 197
Relay_Log_File: slave-relay-bin.000008
Relay_Log_Pos: 375
Relay_Master_Log_File: master-bin.000003
Slave_IO_Running: Yes
Slave_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_Master_Log_Pos: 197
Relay_Log_Space: 755
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1
Master_UUID: 5e8fbcfe-0f68-11ef-a4bd-0242ac110002
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Replica has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set: 5e8fbcfe-0f68-11ef-a4bd-0242ac110002:1-494
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
Master_public_key_path:
Get_master_public_key: 0
Network_Namespace:
1 row in set, 1 warning (0.01 sec)
到这一步,就可以使用MySQL客户端(如:Heidisql、Navicat)连接【主库01】192.168.111.198:3306或【主库02】192.168.111.199:3306访问MySQL数据库了,账号是test,密码是TestDb0101。
十五、验证双主复制
在【主库01】新建一个数据库/表,可以立即在【主库02】查询到。反之亦然。
十六、部署Keepalived
1、各节点安装Keepalived:
## 创建目录,并进入该目录
[root@localhost ~]# yum install -y keepalived
2、各节点修改配置文件keepalived.conf
说明:采用 keepalived 作为高可用方案时,两个节点最好都设置成 BACKUP模式,避免因为意外情况下(比如:脑裂),相互抢占导致往两个节点写入相同数据而引发冲突;
【主库01】修改
## 修改Keepalived配置文件
[root@localhost ~]# vi /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
#标识本节点的字符串
router_id 192.168.111.198
script_user root
enable_script_security
}
vrrp_script chk_mysql {
#检查mysql状态的脚本
script "/etc/keepalived/chk_mysql.sh"
#指定脚本执行的间隔。单位是秒。默认为1s。
interval 1
}
vrrp_instance VI_1 {
#标识主节点服务(只有MASTER和BACKUP两种,大写)
state BACKUP
#根据网卡配置
interface ens33
#虚拟路由id,两台服务器配置一样唯一id
virtual_router_id 1
#优先级,高于另一台服务器的值即可
priority 100
#两台服务器配置一样,不抢占ip
nopreempt
#MASTER和BACKUP节点之间的同步检查时间间隔,单位为秒
advert_int 1
#验证类型和验证密码
authentication {
#PAAS(默认),HA
auth_type PASS
#各节点的keepalived使用相同明文才可以互通
auth_pass 1111
}
#有多个vip可在此处继续增加,每个IP一行,不用逗号分隔
virtual_ipaddress {
192.168.111.195
}
track_script {
chk_mysql
}
}
【主库02】修改
## 修改Keepalived配置文件
[root@localhost ~]# vi /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
#标识本节点的字符串
router_id 192.168.111.199
script_user root
enable_script_security
}
vrrp_script chk_mysql {
#检查mysql状态的脚本
script "/etc/keepalived/chk_mysql.sh"
#指定脚本执行的间隔。单位是秒。默认为1s。
interval 1
}
vrrp_instance VI_1 {
#标识主节点服务(只有MASTER和BACKUP两种,大写)
state BACKUP
#根据网卡配置
interface ens33
#虚拟路由id,两台服务器配置一样唯一id
virtual_router_id 1
#优先级,低于另一台服务器的值即可
priority 50
#两台服务器配置一样,不抢占ip
nopreempt
#MASTER和BACKUP节点之间的同步检查时间间隔,单位为秒
advert_int 1
#验证类型和验证密码
authentication {
#PAAS(默认),HA
auth_type PASS
#各节点的keepalived使用相同明文才可以互通
auth_pass 1111
}
#有多个vip可在此处继续增加,每个IP一行,不用逗号分隔
virtual_ipaddress {
192.168.111.195
}
track_script {
chk_mysql
}
}
3、各节点添加脚本文件check_mysql.sh,内容都一样,如下:
脚本说明:
- 判断本节点3306端口是否存在。若不存在,就停止本节点的Keepalived进程,让VIP漂移到另一节点;
- 需要先启动MySQL容器,再启动Keepalived。由于一个节点开机时,MySQL容器可能还未启动,而Keepalived进程可能先启动。这时为了防止因为没有3306端口,导致已启动的Keepalived进程被停止,需要基于系统启动时间是否小于60秒判断是否为刚刚开机。若刚开机,则不检测MySQL的状态。
## 检测mysql状态的脚本
[root@localhost ~]# vi /etc/keepalived/check_mysql.sh
#!/bin/bash
##判断是否刚开机
#获取系统启动时间
up_time=$(uptime | awk '{print $3}' | cut -d',' -f1)
#打印系统启动时间(格式:X小时:Y分,如1:28表示1小时28分钟)
echo 系统已开机(格式:X小时:Y分钟)$up_time
#将开机时间基于冒号分隔转换成秒
up_seconds=$(echo $up_time | awk -F: '{print $1*60*60+$2*60}')
#打印系统启动时间,单位:秒
echo 系统已开机(单位:秒)$up_seconds
# 如果uptime输出小于60秒,则系统可能刚启动
if [ $up_seconds -lt 60 ]; then
echo "系统刚刚启动"
else
echo "系统已运行一段时间"
##检测mysql的3306端口,若3306端口不存在,则关闭keepalived进程
count=$(netstat -na|grep "LISTEN"|grep -w "3306"|wc -l)
echo "count=="${count}
if [ "${count}" -eq 0 ]; then
systemctl stop keepalived
echo "stopped keepalived-------"
fi
fi
4、为脚本文件check_mysql.sh赋予执行权限
[root@localhost ~]# chmod 755 /etc/keepalived/chk_mysql.sh
5、启动keepalived,并让其开机启动
## 启动Keepalived
[root@localhost ~]# systemctl start keepalived
## 设置开机自启
[root@localhost ~]# systemctl enable keepalived
到这一步,就可以使用MySQL客户端(如:Heidisql、Navicat)访问VIP:192.168.111.195:3306的MySQL数据库了,账号是test,密码是TestDb0101。
至此,MySQL 双主复制已部署完成。
在两个节点中,可以执行如下命令查看VIP目前漂移到哪个节点:
## 查看192.168.111网段的IP地址
[root@localhost ~]# ip ad | grep 111
由上图可见,当前VIP:192.168.111.195 漂移到【主库01】:192.168.111.198上。这时,若将【主库01】主机关机 / 重启,再执行如下命令,将看到VIP:192.168.111.195 又漂移到【主库02】:192.168.111.199上了。
## 查看192.168.111网段的IP地址
[root@localhost ~]# ip ad | grep 111
用户可以关机/重启任意一个节点(不论VIP当前漂移到哪个节点),依赖MySQL数据库的应用都能正常运行,由此实现了MySQL的高可用HA。
十七、常见问题
问题1描述:使用show slave status\G命令时,发现:Last_IO_Error: error connecting to master
...
Slave_IO_Running: Connecting
Slave_SQL_Running: Yes
...
Last_IO_Error: error connecting to master 'slave@192.168.111.199:3306' - retry-time: 60 retries: 580 message: Can't connect to MySQL server on '192.168.111.199:3306' (113)
...
问题1分析:这是由于七、各节点Docker与Firewalld冲突解决 与 八、各节点防火墙配置 这2部分设置了防火墙,而后面由于相关原因 执行systemctl stop firewalld命令 关闭了防火墙造成的。再次开启防火墙,并重新执行 十三、各节点MySQL配置主从复制 部分的操作,就解决问题了。
问题2描述:
当一个系统平台的数据库搭建的是双主复制,当VIP漂移到某个节点时,将该节点关机/重启。若此时,某个用户正在操作平台,页面可能报错:CommunicationsException:Communications link failure。
问题2分析:
这是由于Keepalived在进行VIP漂移时,对漂移前的数据库的访问已经发生,而访问响应还未返回造成的。该问题在VIP漂移完成后,可以自动解决。漂移完成后,就不会存在该问题了。
所以,可以在节点关机 / 重启10到15秒后,再在系统平台上进行操作。
另外,为了用户友好性,系统平台服务端可以拦截该异常,并在页面上显示更友好的提示信息。
问题3描述:
当停电或手动关机某个节点一段时间后,这时,即使恢复数据库同步,当某个节点的数据过多时,也可能出现数据不一致问题。
问题3分析:
第一步:检查两个节点的数据,查看哪个节点的数据量更多。
第二步:进入该节点的数据库中,备份每一个业务数据库的数据到sql脚本中。
第三步:删除两个节点的所有业务数据库。
第四步:参照 十四、各节点MySQL配置主从复制 进行操作,确保主从复制状态正常。
第五步:使用数据库客户端通过VIP和3306端口连接数据库,导入备份的sql脚本进行数据库还原操作。
第六步:比较两个节点的数据库客户端以及VIP的数据库客户端中,数据量大小是否一致。如某个业务数据库仍然存在数据量不一致的问题,重新在VIP数据库客户端中,删除该业务数据库,然后重新执行第五步操作。
十八、资料参考
- MYSQL+Keepalived实现双主复制
- 在Docker下搭建MySQL双主双重集群(单机展示,与多机原理一致)https://www.cnblogs.com/yumq/p/14259964.html
- 双主方案docker mysql和服务 mysql keepalived双主双活https://blog.51cto.com/u_14112/8475290
- 《Docker极简教程》--Docker在生产环境的应用--Docker在生产环境的优化
- 一文搞定Docker容器资源限制
- Docker容器CPU、memory资源限制https://www.cnblogs.com/zhuochong/p/9728383.html
- Docker资源(CPU/内存/磁盘IO/GPU)限制与分配指南
- docker与firewalld冲突解决_docker firewalld-CSDN博客
更多推荐
所有评论(0)