MySQL数据库在线热备(主从复制之AB复制)
Posted 锦衣admin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL数据库在线热备(主从复制之AB复制)相关的知识,希望对你有一定的参考价值。
mysql数据库在线热备(主从复制之AB复制)
MySQL主从复制的搭建(AB复制)
环境准备操作
在配置MySQL主从架构时,必须保证数据库的版本高度一致,统一版本为mysql-boost-5.7.30.tar.gz
传统AB复制架构(M-S):克隆两台全新数据库服务器,master和slave
环境规划:
编号 | 主机名称 | 主机IP地址 | 角色信息 |
---|---|---|---|
1 | master.mysql.cn | 10.1.1.10 | master 主服务器 |
2 | slave.mysql.cn | 10.1.1.100 | slave 从服务器 |
两台系统执行初始化:
- 修改主机名
- 修改一下IP和UUID即可
- 关闭NetworkManager 网络管理,以免影响获取静态IP
- 关闭防火墙,selinux
- 配置腾讯yum源
- 安装一下基本的扩展软件
#!/bin/bash
# desc:Operating system initialization
# Modify hostname
os_hostname ()
read -p "Please set the hostname:" hostname
hostnamectl set-hostname "$hostname"
# Modify network card information
static_nic_ip ()
if [ -f /etc/sysconfig/network-scripts/ifcfg-ens33 ];then
sed -i.bak '/^BOOTPROTO=/c\\BOOTPROTO="static"' /etc/sysconfig/network-scripts/ifcfg-ens33
sed -i '/^UUID="/c\\UUID="af42de51-8836-44d0-8b20-1ebfa7818bc6"' /etc/sysconfig/network-scripts/ifcfg-ens33
# sed -i -r '13s/bc5"$/ba2"/' /etc/sysconfig/network-scripts/ifcfg-ens33
sed -i '4a\\DNS2=114.114.114.114' /etc/sysconfig/network-scripts/ifcfg-ens33
sed -i '4a\\DNS1=8.8.8.8' /etc/sysconfig/network-scripts/ifcfg-ens33
sed -i '4a\\NETMASK=255.255.255.0' /etc/sysconfig/network-scripts/ifcfg-ens33
sed -i '4a\\GATEWAY=10.1.1.2' /etc/sysconfig/network-scripts/ifcfg-ens33
sed -i '4a\\IPADDR=10.1.1.10' /etc/sysconfig/network-scripts/ifcfg-ens33
# sed -i '4a\\IPADDR=10.1.1.100' /etc/sysconfig/network-scripts/ifcfg-ens33
systemctl stop NetworkManager
systemctl disableNetworkManager
systemctl restart network
sleep 5
fi
# Turn off the firewall and selinux
secure_firewalld ()
systemctl stop firewalld
systemctl disable firewalld
setenforce 0
sed -i.bak '/SELINUX=enforcing/c\\SELINUX=disabled' /etc/selinux/config
# Configure yum source
yum_Tencent ()
yum -y install wget 1>/dev/null
tar -zcPf /etc/yum.repos.d/repo.tar.gz /etc/yum.repos.d/*.repo
rm -f /etc/yum.repos.d/*.repo
# Install Tencent yum source
if !(wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.cloud.tencent.com/repo/centos7_base.repo 1>/dev/null);then
echo "yum installation failed"
else
yum clean all
yum makecache
fi
# 安装扩展软件(bash-completion自动补全、vim编辑器、net-tools网络工具包以及ntpdate时间同步工具)
expand_sf ()
if ! (yum install bash-completion vim net-tools ntp -y);then
echo "Failed to install extension"
fi
function main
os_hostname
secure_firewalld
static_nic_ip
yum_Tencent
expand_sf
main
初始化后,由于两台机器处于集群架构,需要互相连接。绑定主机名称与IP地址到/etc/hosts,然后同步一下时间
配置一下主机名:
# vim /etc/hosts
...
10.1.1.10 master.mysql.cn
10.1.1.100 slave.mysql.cn
同步一下时间:
# ntpdate edu.ntp.org.cn
MySQL主从复制核心思路
1. slave必须安装相同版本的mysql数据库软件
2. master端必须开启二进制日志;slave端必须开启relay log日志
3. master端和slave端的server-id号不能一致
4. slave端配置向master来同步数据
- master端必须创建一个复制用户
- 保证master和slave端初始数据一致
- 配置主从复制(slave端)
MySQL主从复制的具体实践
在Master端安装、初始化以及运行mysql软件
安装需求:
选项 | 值(自定义也可以采用默认形式) |
---|---|
安装路径 | /usr/local/mysql |
数据路径 | /usr/local/mysql/data |
端口号 | 3306 |
套接字 | /usr/local/mysql/data/mysql.sock |
第一步:使用脚本安装MySQL软件:
- 配置时安装目录和数据目录还有端口号可不写,因为默认安装在/usr/local 目录下
vim mysql.sh
#!/bin/bash
# 安装依赖
if ! (yum -y install cmake ncurses-devel openssl-devel gcc-c++ libaio-devel &>/dev/null);then
echo "Dependency installation failed"
fi
# 创建mysql用户
if ! (id mysql &>/dev/null);then
useradd -r -s /sbin/nologin mysql
fi
# 更改mariadb的配置文件
[ -f /etc/my.cnf ] && mv /etc/my.cnf /etc/my.cnf.bak
# 解压源码包,并指定解压到mysql-boost-5.7.30目录
read -p "请输入mysql版本:" mysql
mkdir ./$mysql && tar -xzf $mysql.tar.gz -C ./$mysql --strip-components 1
cd /root/$mysql
# 编译安装
cmake . \\
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql \\
-DMYSQL_DATADIR=/usr/local/mysql/data \\
-DMYSQL_TCP_PORT=3306 \\
-DMYSQL_UNIX_ADDR=/usr/local/mysql/data/mysql.sock \\
-DWITH_INNOBASE_STORAGE_ENGINE=1 \\
-DWITH_PARTITION_STORAGE_ENGINE=1 \\
-DWITH_FEDERATED_STORAGE_ENGINE=1 \\
-DWITH_BLACKHOLE_STORAGE_ENGINE=1 \\
-DWITH_MYISAM_STORAGE_ENGINE=1 \\
-DENABLED_LOCAL_INFILE=1 \\
-DEXTRA_CHARSETS=all \\
-DDEFAULT_CHARSET=utf8mb4 \\
-DDEFAULT_COLLATION=utf8mb4_general_ci \\
-DWITH_SSL=system \\
-DWITH_BOOST=boost
make && make install 1>/dev/null
# 创建mysql-files目录并修改权限
cd /usr/local/mysql
mkdir mysql-files
chown mysql.mysql mysql-files
chown mysql.mysql /usr/local/mysql
chmod 750 mysql-files
# 初始化,并将初始化产生的临时密码保存下来
bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data > /root/passwd.txt
# 拷贝mysql.server脚本到/etc/init.d目录
[ -f support-files/mysql.server ] && cp support-files/mysql.server /etc/init.d/mysql
# 将mysql的bin目录加入环境变量
echo 'export PATH=$PATH:/usr/local/mysql/bin' >> /etc/profile
source /etc/profile
- 启动脚本:
# source mysql.sh => 因为需要脚本内用了source 加载文件所以用此命令执行脚本
第二步:修改MySQL密码
# service mysql start => 需要先启动mysql服务才可以修改密码
# mysqladmin -uroot password '123' -p => 输入刚才保存到/root/passwd.txt 的临时密码
第三步:安全配置
# mysql_secure_installation =>输入密码,按两下回车,后一路Y就行
第四步:编写master配置文件(开启二进制日志)
# vim /usr/local/mysql/my.cnf
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
socket=/usr/local/mysql/data/mysql.sock
port=3306
log-error=/usr/local/mysql/data/master.err
log-bin=/usr/local/mysql/data/binlog
server-id=10
character_set_server=utf8mb4
选项说明:
log-bin:master 需要开启二进制日志
# service mysql restart => 启动MySQL
# chkconfig --add mysqld => 配置开机自启
# chkconfig mysqld on
在Slave从服务器端安装mysql软件(不需要初始化)
安装需求:
选项 | 值(自定义也可以采用默认形式) |
---|---|
安装路径 | /usr/local/mysql |
数据路径 | /usr/local/mysql/data |
端口号 | 3306 |
套接字 | /usr/local/mysql/data/mysql.sock |
- 注意:slave的套接字是可以放在data目录下,因为它不会出现重复的套接字文件,就算你raync复制master的数据目录过来,如果你slave定义的套接字文件在别的地方,复制过来的数据目录也不会出现。
- 所以slave的套接字可以直接放置在data目录下
第一步:使用脚本安装MySQL软件:
-
配置时安装目录和数据目录还有端口号可不写,因为默认安装在/usr/local 目录下
-
相对于主服务器MySQL的安装与配置,从服务器端不需要进行初始化操作,因为其数据将来都来自于主服务器。
# vim mysql.sh
#!/bin/bash
# 安装依赖
if ! (yum -y install cmake ncurses-devel openssl-devel gcc-c++ libaio-devel &>/dev/null);then
echo "Dependency installation failed"
fi
# 创建mysql用户
if ! (id mysql &>/dev/null);then
useradd -r -s /sbin/nologin mysql
fi
# 更改mariadb的配置文件
[ -f /etc/my.cnf ] && mv /etc/my.cnf /etc/my.cnf.bak
# 解压源码包,并指定解压到mysql-boost-5.7.30目录
read -p "请输入mysql版本:" mysql
mkdir ./$mysql && tar -xzf $mysql.tar.gz -C ./$mysql --strip-components 1
cd /root/$mysql
# 编译安装
cmake . \\
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql \\
-DMYSQL_DATADIR=/usr/local/mysql/data \\
-DMYSQL_TCP_PORT=3306 \\
-DMYSQL_UNIX_ADDR=/usr/local/mysql/data/mysql.sock \\
-DWITH_INNOBASE_STORAGE_ENGINE=1 \\
-DWITH_PARTITION_STORAGE_ENGINE=1 \\
-DWITH_FEDERATED_STORAGE_ENGINE=1 \\
-DWITH_BLACKHOLE_STORAGE_ENGINE=1 \\
-DWITH_MYISAM_STORAGE_ENGINE=1 \\
-DENABLED_LOCAL_INFILE=1 \\
-DEXTRA_CHARSETS=all \\
-DDEFAULT_CHARSET=utf8mb4 \\
-DDEFAULT_COLLATION=utf8mb4_general_ci \\
-DWITH_SSL=system \\
-DWITH_BOOST=boost
make && make install
# 创建mysql-files目录并修改权限
cd /usr/local/mysql
mkdir mysql-files
chown mysql.mysql mysql-files
chown mysql.mysql /usr/local/mysql
chmod 750 mysql-files
# 拷贝mysql.server脚本到/etc/init.d目录
[ -f support-files/mysql.server ] && cp support-files/mysql.server /etc/init.d/mysql
# 将mysql的bin目录加入环境变量
echo 'export PATH=$PATH:/usr/local/mysql/bin' >> /etc/profile
source /etc/profile
- 启动脚本:
# source mysql.sh => 因为需要脚本内用了source 加载文件所以用此命令执行脚本
第二步:编写slave配置文件(开启中继日志)
- slave服务器没有初始化,所以没有密码修改,自然也没有数据目录
# vim /usr/local/mysql/my.cnf
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
socket=/usr/local/mysql/data/mysql.sock
port=3306
log-error=/usr/local/mysql/data/slave.err
relay-log=/usr/local/mysql/data/relaylog
server-id=100
character_set_server=utf8mb4
选项说明:
port:端口可换可不换,只要不占用别的服务端口即可
relay-log:需要开启中继日志
把master主服务器的数据目录同步到slave从服务器
第一步:把MASTER服务器中的mysql服务停止
- 因为需要需要拷贝数据到slave服务器了,所以停止它不让它进行增删改的操作
# service mysql stop
第二步:把MASTER服务器中的/usr/local/mysql/data目录下的auto.cnf文件删除
- auto.cnf文件保存的是每一个数据库实例的UUID信息,代表数据库的唯一标识
- 每安装一个mysql软件,其data数据目录都会产生一个auto.cnf文件,里面是一个唯一性的编号,相当于我们每个人的身份证号码,重启服务后又会重新生成
- 这是为了防止两台数据库的UUID号重复发生错误,因为删除后各自重启后UUID的值会变化,不删除重启不会变化
# rm -f /usr/local/mysql/data/auto.cnf
第三步:把MASTER服务器中/usr/local/mysql中的data目录拷贝一份到SLAVE从服务器的/usr/local/mysql目录
# rsync -av /usr/local/mysql/data root@10.1.1.100:/usr/local/mysql/
第四步:同步完成后,把主服务器与从服务器中的mysqld启动
# service mysql start
常见问题解决方案
常见问题1:MySQL无法启动
# service mysqld start
Redirecting to /bin/systemctl start mysqld.service
Failed to start mysqld.service: Unit not found.
出现以上问题的主要原因在于/etc/init.d目录中没有mysqld这个文件换句话说,就是你没有cp mysql.server脚本
#l 解决方案:
# cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysql
=> 记住:/etc/init.d目录中的文件叫什么名字,我们service的时候就应该使用什么名字
# service mysqld start
常见错误2:MySQL没有安装在/usr/local/mysql目录中,service也无法启动
- 相对于glibc版本,源码没有这种情况
# service mysql start
无法启动的原因可能是你的MySQL并没有安装在/usr/local/mysql目录中,
因为/etc/init.d/mysqld脚本中的basedir与datadir默认指向的都是/usr/local/mysql
所以如果我们更换了mysql的安装位置,则必须更改/etc/init.d/mysqld脚本中basedir与datadir目录
#l 解决方案:
# vim /etc/init.d/mysqld
basedir=你的安装路径
datadir=你的安装路径/data
常见问题3:因为my.cnf配置文件导致mysql无法启动
- 相对于glibc版本,源码没有这种情况
# vim my.cnf => 假设这是你的配置
[mysqld]
basedir=/usr/local/mysql => 安装路径
datadir=/usr/local/mysql/data => 数据目录
socket=/tmp/mysql.sock => GLIBC默认就是/tmp/mysql.sock
port=3310
log-error=/usr/local/mysql/slave.err => 错误日志到底放在哪里
relay-log=/usr/local/mysql/data/relaylog
server-id=100
character_set_server=utf8mb4
#l 启动报错:
xxxxxxxxxx Starting MySQL.2020-08-31T07:17:06.554270Z mysqld_safe error: log-error set to
'/usr/local/mysql/slave.err', however file don't exists. Create writable for user 'mysql'.
ERROR! The server quit without updating PID file (/usr/local/mysql/data/slave.itcast.cn.pid).
产生以上问题的主要原因在于mysql这个用户对/usr/local/mysql文件夹没有写入权限
# ll -d /usr/local/mysql
drwxr-xr-x 11 7161 31415 174 Aug 31 15:16 /usr/local/mysql
发现文件拥有者位置与所属组位置都是两个数字,正常应该是文件拥有者的名称与文件所属组的名称。
但是由于GLIBC已经提前打包了,我们解压后,如果在我们系统中,找不到原文件对应的文件拥有者与所属组,
则以两个数字代替文件拥有者与所属组的显示。
#l 解决方案:
方案1:建议把错误日志,丢在数据目录中
# vim my.cnf
...
log-error=/usr/local/mysql/data/slave.err
方案2:直接更改/usr/local/mysql目录的权限
# chown -R mysql.mysql /usr/local/mysql
配置MASTER-SLAVE主从同步
第一步:在MASTER主服务器中创建一个账号,专门用于实现数据同步
MySQL5.7及以下版本:
# mysql> grant replication slave on *.* to 'slave'@'10.1.1.%' identified by '123';
# mysql> flush privileges;
MySQL新版本中建议:
# mysql> create user 'slave'@'10.1.1.%' identified by '123';
# mysql> grant replication slave on *.* to 'slave'@'10.1.1.%';
# mysql> flush privileges;
选项说明:
replication slave:常用于建立复制时所需要用到的用户权限
第二步: 在MASTER中锁表,然后查看二进制文件的名称及位置
# mysql> flush tables with read lock; => 锁表,不准写入数据,防止两边数据不一致
# mysql> show master status; => 查看当前数据库日志写到什么位置(只有打开二进制日志,这条命令才有结果)
mysql> show master status;
+---------------+--------------------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+--------------------+--------------+------------------+-------------------+
| binlog.000003 | 763 | | | |
+---------------+--------------------+--------------+------------------+-------------------+
二进制日志文件名称 二进制日志文件位置
第三步: 在SLAVE从服务器中,使用
change master to
指定主服务器,并实现数据同步
- 登录slave 的用户密码是管理员的
- 通过语句
change master to
指定slave
复制账号去同步master的数据
#l [root@slave mysql]# mysql -p123 => 因为它当数据目录是直接复制master的,所以管理员密码也是123
指定主服务器:
# mysql> change master to
master_host='10.1.1.10',
master_user='slave',
master_password='123',
master_port=3306,
master_log_file='binlog.000003',
master_log_pos=763;
选项说明:
master_host:主机的IP地址
master_user:主机的user账号
master_password:主机的user账号密码
master_port:主机MySQL的端口号
master_log_file:二进制日志文件名称
master_log_pos:二进制日志文件位置
主从复制的change master to语句记不住怎么办?答:求帮助,mysql> help change master to;
第四步:在SLAVE从服务器中,启动slave数据同步
# mysql> start slave; => 启动slave
# mysql> show slave status\\G => 查看是否启动成功
说明:
" \\G 和 ; " 其实是一样的,只不过一个是竖着显示,另一个是横着显示
第五步:主MASTER服务器解锁
# mysql> unlock tables;
常见问题解决方案:
在配置主从时,一般遇到错误,大部分都是change master to语句写错了(80%)
解决方案:在slave服务器上操作
# mysql> stop slave; => 停止slave
# mysql> reset slave; => 重置slave
# mysql> change master to master_host='10.1.1.10',master_user='slave',master_password='123',master_port=3306,master_log_file='binlog.000002',master_log_pos=597;
=> 再次指定主服务器,并实现数据同步
# mysql> start slave; => 启动slave数据同步
- 同步测试成功
master服务器插入:
# mysql > create database db_xjj;
# mysql > use db_xjj;
# mysql > create table tb_girl (id int not null auto_increment,name varchar(30),primary key(id));
# mysql > insert into tb_girl values (null,'迪丽热巴'),(null,'杨幂');
slave服务器查看:
# mysql> select*from db_xjj.tb_girl;
总结:
- 主从复制必须保证两台数据库实例的server-id不一致
- 主服务器必须开启二进制日志;从服务器必须开启中继日志
- 主从复制搭建必须保证初始数据一致
- 主服务器必须要给从服务器创建一个复制用户,并授予复制权限
- Master—>Slave架构,主写会同步到从;而从写不会同步到主
SLAVE从服务器不小心写入数据解决方案
正常情况下:
MASTER既可以读,也可以写。但是SLAVE从服务器,只能执行读取操作。一旦我们在SLAVE从服务器中写入数据,则主从架构会失败。
从服务器写入数据:
# mysql > use db_xjj;
# mysql > insert into tb_girl values (null,'佟丽娅');
主服务器也写入数据:
# mysql > insert into tb_girl values (null,'佟丽娅');
备注:这是主从架构就出现问题了
遇到以上问题:如果数量较少,还可以通过跳过当前语句的方式解决。但是如果从服务器写入数据过多,则以上架构必须要重新搭建了!
解决方案:
如果由于人为操作或者其他原因直接将数据更改到从服务器导致数据同步失效,可以通过变量sql_slave_skip_counter
临时跳过事务进行处理
- 注意:
- 跳过事务应该在slave上进行
- 传统的AB复制方式可以使用变量:
sql_slave_skip_counter
,基于GTIDs的方式不支持 - N :代表你从服务器插入数据的条数,如果你插入一条就写1,插入两条就写2
- 还有就是,这条命令只是跳过而已,并不是修正,如果你从服务器插入的数据和主服务器插入的不一致,那么通过
sql_slave_skip_counter
命令只是跳过这个主键冲突的事务,跳过后再次同步slave 并不会修正数据
命令格式:
# mysql > SET GLOBAL sql_slave_skip_counter = N; => N代表跳过N个事务
演示:从服务器上操作
# mysql> SET GLOBAL sql_slave_skip_counter=1; => 跳过
# mysql> stop slave;
# mysql> start slave;
# mysql> select*from db_xjj.tb_girl;
+----+--------------+
| id | name | => 此时就可以再次同步到master的数据了
+----+--------------+
| 1 | 迪丽热巴 |
| 2 | 杨幂 |
| 3 | 佟丽娅 |
| 4 | 佟丽娅 |
+----+--------------+
以上是关于MySQL数据库在线热备(主从复制之AB复制)的主要内容,如果未能解决你的问题,请参考以下文章