搭建说明
- 两主一从,从本质上说,只不过是机器 master-a 和 master-b 互为主从机(热备),然后通过 keepalived 进行高可用配置,使得在同一时间内只会有一台对外提供服务,实现单写机制,另一个机器 slave 则作为 master-a 的从机存在(冷备)。
- 从机 slave 无法直接将虚拟IP(VIP)作为主机:正常运行时,slave 绑定了一个主机 master-a, 一旦绑定之后,在 master-a 不可用的时候,无法自动切换到 master-b,因为需要考虑 二进制日志文件名(master_log_file)及位置(master_log_pos)在 master-a 和 master-b 上是不一致的,此时只有在 master-a 恢复可用时,master-a 从 master-b 同步数据之后,slave 数据最终才会和 master-a 保持一致。
环境准备
- 三台 centos7 的服务器,服务器ip为 192.168.86.124(master-a)、192.168.86.125(master-b)、192.168.86.126(slave)
- 一个虚拟IP(VIP):192.168.86.250
- mysql-5.7.24-linux-glibc2.12-x86_64 安装包
数据库安装
- 将 mysql 安装包上传到三台服务器上
- 解压安装包
tar -zxvf mysql-5.7.24-linux-glibc2.12-x86_64.tar.gz
- 创建 mysql 安装路径,然后移动刚才解压的文件夹并重命名
mkdir /data #创建安装路径 mv mysql-5.7.24-linux-glibc2.12-x86_64 /data/mysql #移动文件并重命名
- 创建 mysql 用户和组、创建mysql运行需要的文件夹及赋权
groupadd mysql #创建用户组 useradd -r -g mysql mysql #创建用户 cd /data/mysql #切换到安装目录 mkdir data #创建数据存放目录 mkdir mysql-log #创建日志存放目录 mkdir mysql-log/err-log mkdir mysql-log/slow-log mkdir mysql-log/relay-log mkdir mysql-log/bin-log chown -R root:mysql . #将当前目录以及子目录,所有者改变为 mysql,所属组修改为 mysql chown -R mysql:mysql data chown -R mysql:mysql mysql-log
- 设置用户操作系统资源限制
vi /etc/security/limits.conf # 在文件中加入以下内容 mysql soft nproc 2047 mysql hard nproc 16384 mysql soft nofile 1024 mysql hard nofile 65536
- 设置链接和服务
cp /data/mysql/support-files/mysql.server /etc/init.d/mysql # 可以使用service mysql start ln -s /data/mysql/bin/mysql /usr/bin #任何路径可以使用 mysql 命令
- 配置 /etc/my.cnf
vi /etc/my.cnf
- master-a
[mysqld] port = 3306 #端口 basedir = /data/mysql #mysql安装路径 datadir = /data/mysql/data/ #mysql数据存放路径 #日志设置 log-error = /data/mysql/mysql-log/err-log/db-err.log #错误日志路径 slow-query-log-file = /data/mysql/mysql-log/slow-log/db-slow.log #慢SQL日志路径 relay-log=/data/mysql/mysql-log/relay-log/relay-log long-query-time = 20 #怎样才算是慢sql,单位是秒 #开启 binlog 同步 server_id = 0001 #一个集群内的 MySQL 服务器 ID,全局唯一 log-bin = /data/mysql/mysql-log/bin-log/db-binlog #开启 Binlog 并写明存放日志的位置 max-binlog-cache_size = 64M #binlog 最大能够使用cache的内存大小 max-binlog-size = 1G #binlog 日志每达到设定大小后,会使用新的 binlog 日志 expire_logs_days = 15 #只保留最近15天的bin日志 binlog-format = mixed #混合模式复制 innodb_flush_log_at_trx_commit = 1 #和 sync_binlog 控制MySQL磁盘写入策略以及数据安全性 sync-binlog = 1 #控制数据库的binlog刷到磁盘上去 ## 主主同步配置 replicate-do-db=db_test #需要从主库-2同步的数据库1 replicate-do-db=db_dev #需要从主库-2同步的数据库2 auto-increment-increment=2 auto-increment-offset=1 log-slave-updates=1 #性能调优配置 innodb_buffer_pool_size = 24576M max_connections = 5000 max_connect_errors = 6000 external-locking = FALSE max_allowed_packet = 64M join_buffer_size = 64M sort_buffer_size = 2M read_rnd_buffer_size = 16M #SQL模式 sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
- master-b
[mysqld] port = 3306 basedir = /data/mysql datadir = /data/mysql/data #日志设置 slow-query-log-file=/data/mysql/mysql-log/slow-log/db-slow.log log-error=/data/mysql/mysql-log/err-log/db-err.log relay-log=/data/mysql/mysql-log/relay-log/relay-log long-query-time = 20 #怎样才算是慢sql,单位是秒 #开启 binlog 同步 server_id = 0002 #一个集群内的 MySQL 服务器 ID,全局唯一 log-bin = /data/mysql/mysql-log/bin-log/db-binlog #开启 Binlog 并写明存放日志的位置 max-binlog-cache_size = 64M #binlog 最大能够使用cache的内存大小 max-binlog-size = 1G #binlog 日志每达到设定大小后,会使用新的 binlog 日志 expire_logs_days = 15 #只保留最近15天的日志 binlog-format = mixed #混合模式复制 innodb_flush_log_at_trx_commit = 1 #和 sync_binlog 控制MySQL磁盘写入策略以及数据安全性 sync-binlog = 1 #控制数据库的binlog刷到磁盘上去 #主主设置 replicate-do-db=db_test #需要从主库-1同步的数据库1 replicate-do-db=db_dev #需要从主库-1同步的数据库2 auto-increment-increment=2 auto-increment-offset=2 log-slave-updates=1 #性能调优设置 innodb_buffer_pool_size = 24576M max_connections = 5000 max_connect_errors = 6000 external-locking = FALSE max_allowed_packet = 64M join_buffer_size = 64M sort_buffer_size = 2M read_rnd_buffer_size = 16M #SQL模式 sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
- slave
[mysqld] port = 3306 basedir = /data/mysql datadir = /data/mysql/data #日志设置 expire_logs_days = 15 long-query-time = 3 slow-query-log-file=/data/mysql/mysql-log/slow-log/db-slow.log log-error=/data/mysql/mysql-log/err-log/db-err.log #主从设置 server_id = 0003 #这里需要在集群中保持唯一 replicate-do-db=db_test #需要从主库同步的数据库1 replicate-do-db=db_dev #需要从主库同步的数据库2 read_only=1 #只读设置 #性能调优设置 innodb_buffer_pool_size = 24576M max_connections = 5000 max_connect_errors = 6000 external-locking = FALSE max_allowed_packet = 64M join_buffer_size = 64M sort_buffer_size = 2M read_rnd_buffer_size = 16M #SQL模式 sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
- master-a
数据库初始化
- 初始化数据库
cd /data/mysql/bin/ ./mysqld --defaults-file=/etc/my.cnf --user=mysql --initialize #初始化
- 查看密码(初始化数据库之后会生成一个 root 账户的默认密码)
cat /data/mysql/mysql-log/err-log/db-err.log
- 启动 mysql
service mysql start
- 登录并修改 root 密码
mysql -u root -p set password = password('root'); flush privileges; #如果需要使用 root 进行远程连接,执行以下语句 use mysql; update user set host = '%' where user = 'root'; flush privileges;
- 创建用户并赋权
- 主机 master-a、master-b
#创建一个用于和从机“通信”的用户,具有同步权限 grant replication slave on *.* to 'copy'@'%' identified by 'copy' flush privileges; #创建一个用于访问和操作某些特定的库的用户,不应该让应用直接使用 root 用户. grant all privileges on db_test.* to "app_user"@'%' identified by "app_user"; flush privileges;
- 从机 slave
#创建一个用于访问和操作某些特定的库的用户,不应该让应用直接使用 root 用户. grant all privileges on db_test.* to "app_user"@'%' identified by "app_user"; flush privileges;
- 主机 master-a、master-b
主从同步启动
- 主机 master-a
- 在 master-b 中获得二进制日志文件名(master_log_file)及位置(master_log_pos)
show master status
- 在 master-a 中执行以下命令
stop slave; #暂停 reset slave; #重置 change master to master_host="master-b 的IP", master_user="copy",master_password="copy",master_log_file="db-binlog.000002",master_log_pos=2532; #设置和主机同步的用户信息,日志文件信息 start slave; #启动 show slave status G #查看从机状态,主要是看 Slave_IO_Running Slave_SQL_Running 上是否都是 yes
- 在 master-b 中获得二进制日志文件名(master_log_file)及位置(master_log_pos)
- 主机 master-b、从机 slave
- 在 master-a 中获得二进制日志文件名(master_log_file)及位置(master_log_pos)
show master status
- 在 master-b和 slave 中执行以下命令
stop slave; #暂停 reset slave; #重置 change master to master_host="master-a 的IP", master_user="copy",master_password="copy",master_log_file="db-binlog.000002",master_log_pos=2532; #设置和主机同步的用户信息,日志文件信息 start slave; #启动 show slave status G #查看从机状态,主要是看 Slave_IO_Running Slave_SQL_Running 上是否都是 yes
- 在 master-a 中获得二进制日志文件名(master_log_file)及位置(master_log_pos)
keepalived 安装启动(master-a、master-b)
- keepalived 安装
yum install -y keepalived
- keepalived 配置
文件内容为:vi /etc/keepalived/keepalived.conf
global_defs { router_id LVS_DEVEL } vrrp_sync_group VG_1 { group { VI_1 } } vrrp_instance VI_1 { state BACKUP #两个机器都是这个值,不要设置为 MASTER,使用下面的 priority 来控制 interface ens33 #通过 ifconfig 查看 virtual_router_id 51 priority 100 #优先级,另一台机器设置为 90 advert_int 1 nopreempt # 另一台优先级低的机器不设置此参数! authentication { auth_type root auth_pass root } virtual_ipaddress { 192.168.86.250 # 这个是VIP } } virtual_server 192.168.86.250 3306 { # 这个是VIP delay_loop 2 lb_algo rr lb_kind DR persistence_timeout 50 protocol TCP real_server 192.168.86.124 3306 { # 这是机器的IP地址 weight 3 notify_down /data/mysql/bin/mysql.sh TCP_CHECK { connect_timeout 5 nb_get_retry 3 delay_before_retry 3 connect_port 3306 } } }
- 创建一个关闭 keepalived 的脚本,用于在 mysql 无法访问时,关闭 keepalived 以释放 VIP
文件内容为:vi /data/mysql/bin/mysql.sh
将文件设置为可执行文件:#!/bin/sh pkill keepalived
chmod +x /data/mysql/bin/mysql.sh
- keepalived 启动
systemctl start keepalived
- keepalived 其它相关命令
systemctl enable keepalived # 开机自启动 systemctl start keepalived # 启动 systemctl stop keepalived # 暂停 systemctl restart keepalived # 重启 systemctl status keepalived # 查看状态 tail -f /var/log/messages
测试
- 首先,所有机器、软件都正常运行
- 通过各个 IP和VIP 连接数据库查看均能正常连接到数据库
- master-a 获得了 vip
ip addr
- 通过各个 IP和VIP 连接数据库查看均能正常连接到数据库
- 通过 VIP 连接数据库,之后创建一个 db_test 库以及 tb_user表
- master-a、master-b、slave 均存在创建的库和表
- 连接 master-a 的数据库,并新增一条数据
- master-b、slave 均有新增的数据
- 连接 master-b 的数据库,并新增一条数据
- master-a、slave 均有新增的数据
- 关闭 master-a 的mysql
service mysql stop #关闭 mysql systemctl status keepalived #查看 keepalived 状态
- master-a 的 keepalived 自动关闭了,原因是 mysql 关闭会触发 keepalived 配置的 notify_down 脚本
- master-b 获得了 vip
- 通过 VIP 连接数据库,并插入一条数据
- master-a(无法连接)
- master-b (存在新增数据)
- slave(不存在新增数据,因为 master-a 挂掉了)
- 重启 master-a 的 mysql 和 keepalived
- vip 仍然在 master-b ,因为 master-a keepalived 配置了非抢占模式 nopreempt,因此若是主机故障排除后需要将主机的keepalived重启,然后重启从机的keepalived,需要让主机获取到 VIP
- master-a、master-b 同步了刚刚新增的数据
- 关闭 master-b、slave 的mysql,通过 master-a 新增一条数据,之后重启 master-b、slave 的 mysql,以及 master-b 的 keepalived
- master-b存在新增数据
- slave 存在新增数据
- vip 仍然在 master-a