MySQL数据库的主从复制与高可用

70 阅读8分钟

MYSQL

主从复制

在实际的生产环境中,对数据库的读和写都在同一个数据库服务器中,是不能满足实际需求的。无论是在安全性、高可用性还是高并发等各个方面都是完全不能满足实际需求的。因此,通过主从复制的方式来同步数据,再通过读写分离来提升数据库的并发负载能力。有点类似于rsync,但是不同的是rsync是对磁盘文件做备份,而mysql主从复制是对数据库中的数据、语句做备份。
主从复制的工作过程
Master节点将数据的改变记录成二进制日志(bin log),当Master上的数据发生改变时,则将其改变写入二进制日志中。
Slave节点会在一定时间间隔内对Master的二进制日志进行探测其是否发生改变,如果发生改变,则开始一个I/O线程请求 Master的二进制事件。
同时Master节点为每个I/O线程启动一个dump线程,用于向其发送二进制事件,并保存至Slave节点本地的中继日志(Relay log)中,Slave节点将启动SQL线程从中继日志中读取二进制日志,在本地重放,即解析成 sql 语句逐一执行,使得其数据和 Master节点的保持一致,最后I/O线程和SQL线程将进入睡眠状态,等待下一次被唤醒。
步骤
首先需要将时间与主机同步,可以使用NTP软件进行同步
需要mysql5.7以上版本的软件
yum install ntp -y
下载ntp软件进行同步时间
vim /etc/ntp.conf
修改配置文件
主机上配置
server 127.127.IP地址.0(网段)
fudge 127.127.IP地址.0 stratum 8(层级)
重启 systemctl restart ntpd
从:下载ntp后启动
/usr/sbin/ntpdate 192.168.主机IP地址.xxx
匹配主机的时间进行同步
crotab -e 配置计划任务
*/30 * * * * /usr/sbin/ntpdate 192.168.222.100 设置时间进行同步

主机对MySQL配置:
vim /etc/my.cnf
server-id = 1
log-bin=mysql-bin
binlog_format = MIXED
log-slave-updates=true
expire_logs_days = 7
max_binlog_size = 500M(根据需要选择配置的命令)

log-bin=mysql-bin #添加,主服务器开启二进制日志
binlog_format=mixed
#选配项
expire_logs_days=7 #设置二进制日志文件过期时间,默认值为0,表示logs不过期
max_binlog_size=500M #设置二进制日志限制大小,如果超出给定值,日志就会发生滚动,默认值是1GB
skip_slave_start=1 #阻止从库崩溃后自动启动复制,崩溃后再自动复制可能会导致数据不一致

image.png systemctl restart mysqld重启MySQL
mysql -u root -p密码 登入mysql
GRANT REPLICATION SLAVE ON *. * TO 'myslave'@'192.168.80.%' IDENTIFIED BY '123456'; #给从服务器授权

show master status;

image.png 从服务器的mysql配置:
vim /etc/my.cnf
server-id = 22 #修改,注意id与Master的不同,两个Slave的id也要不同
relay-log=relay-log-bin #开启中继日志,从主服务器上同步日志文件记录到本地
relay-log-index=relay-log-bin.index #定义中继日志文件的位置和名称,一般和relay-log在同一目录

#选配项
innodb_buffer_pool_size=2048M #用于缓存数据和索引的内存大小,让更多数据读写内存中完成,减少磁盘操作,可设置为服务器总可用内存的 70-80%
sync_binlog=0 #MySQL不做任何强制性的磁盘刷新指令,而是依赖操作系统来刷新数据到磁盘
innodb_flush_log_at_trx_commit=2 #每次事务log buffer会写入log file,但一秒一次刷新到磁盘
log-slave-updates=0 #slave 从 master 复制的数据会写入二进制日志文件里,从库做为其他从库的主库时设置为 1
relay_log_recovery=1 #当 slave 从库宕机后,假如 relay-log 损坏了,导致一部分中继日志没有处理,则自动放弃所有未执行的 relay-log, 并且重新从 master 上获取日志,这样就保证了 relay-log 的完整性。默认情况下该功能是关闭的,将 relay_log_recovery 的值设置为 1 时, 可在 slave 从库上开启该功能,建议开启。
systemctl restart mysqld 重启
mysql -u root -p密码
CHANGE master to master_host='192.168.IP地址.xxx',master_user='myslave',master_password='123456',master_log_file='mysql-bin.00000x',master_log_pos=xxxx;#配置同步,注意 master_log_file 和 master_log_pos 的值要与Master查询的一致
start slave; 启用主从复制
show slave status\G;
确保 IO 和 SQL 线程都是 Yes,代表同步正常。
Slave_IO_Running: Yes #负责与主机的io通信
Slave_SQL_Running: Yes #负责自己的slave mysql进程

去到主机进行列表创建,随后在从机查看是否同步

高可用

先完成主从复制的命令,在每台主机MySQL里设置进行 mysql 授权
mysql -uroot -p
grant replication slave on *. * to 'myslave'@'192.168.222.%' identified by '123123'; #从数据库同步使用
grant all privileges on *. * to 'mha'@'192.168.222.%' identified by 'manager'; #manager 使用
grant all privileges on *. * to 'mha'@'mysql1' identified by 'manager'; #防止从库通过主机名连接不上主库
grant all privileges on *. * to 'mha'@'mysql2' identified by 'manager';
grant all privileges on *. * to 'mha'@'mysql3' identified by 'manager';
flush privileges;

在 Master、Slave1、Slave2 节点上都创建两个软链接
ln -s /usr/local/mysql/bin/mysql /usr/sbin/
ln -s /usr/local/mysql/bin/mysqlbinlog /usr/sbin/

在 Slave1、Slave2 节点查看数据同步结果
show slave status\G
两个从库必须设置为只读模式:只读之后才可以验证
set global read_only=1;

image.png

image.png

image.png 主从机上装MHA软件
yum install epel-release --nogpgcheck -y

yum install -y perl-DBD-MySQL \
perl-Config-Tiny \
perl-Log-Dispatch \
perl-Parallel-ForkManager \
perl-ExtUtils-CBuilder \
perl-ExtUtils-MakeMaker \
perl-CPAN

cd到存放mha4mysql-node-0.57.tar.gz的目录进行解压
cd进解压后的文件
perl Makefile.PL
make && make install
进行编译安装

image.png
cd 到存放mha4mysql-manager-0.57.tar.gz的manager机器上进行额外的manager编译安装
perl Makefile.PL
make && make install

image.png 进行免密登录操作
manager上给三台MySQL机器 ,三台MySQL机器给另外两台

image.png image.png

image.png 在 manager 节点上配置 MHA

image.png (1)在 manager 节点上复制相关脚本到/usr/local/bin 目录
cp -rp /opt/mha4mysql-manager-0.57/samples/scripts /usr/local/bin
#拷贝后会有四个执行文件
ll /usr/local/bin/scripts/
(2)复制上述的自动切换时 VIP 的管理脚本到 /usr/local/bin 目录,这里使用master_ip_failover脚本来管理 VIP 和故障切换
cp /usr/local/bin/scripts/master_ip_failover /usr/local/bin
(3)修改内容如下:(删除原有内容,直接复制并修改vip相关参数。可在拷贝前输入 :set paste 解决vim粘贴乱序问题)
vim /usr/local/bin/master_ip_failover

#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';

use Getopt::Long;

my (
command,command, ssh_user, origmasterhost,orig_master_host, orig_master_ip,
origmasterport,orig_master_port, new_master_host, newmasterip,new_master_ip, new_master_port
); #############################添加内容部分#########################################
my vip = '192.168.IP地址'; #指定vip的地址 my brdc = '192.168.IP地址.255'; #指定vip的广播地址
my ifdev = 'ens33'; #指定vip绑定的网卡 my key = '1'; #指定vip绑定的虚拟网卡序列号
my sshstartvip="/sbin/ifconfigens33:ssh_start_vip = "/sbin/ifconfig ens33:key vip"; #代表此变量值为ifconfig ens33:1 192.168.239.100 my ssh_stop_vip = "/sbin/ifconfig ens33:key down"; #代表此变量值为ifconfig ens33:1 192.168.239.100 down my exit_code = 0; #指定退出状态码为0
#my sshstartvip="/usr/sbin/ipaddraddssh_start_vip = "/usr/sbin/ip addr add vip/24 brd brdcdevbrdc dev ifdev label ifdev:ifdev:key;/usr/sbin/arping -q -A -c 1 -I ifdevifdev vip;iptables -F;";
#my sshstopvip="/usr/sbin/ipaddrdelssh_stop_vip = "/usr/sbin/ip addr del vip/24 dev ifdevlabelifdev label ifdev:key"; ################################################################################## GetOptions( 'command=s' => \command,
'ssh_user=s' => $ssh_user,
'orig_master_host=s' => $orig_master_host,
'orig_master_ip=s' => $orig_master_ip,
'orig_master_port=i' => $orig_master_port,
'new_master_host=s' => $new_master_host,
'new_master_ip=s' => $new_master_ip,
'new_master_port=i' => $new_master_port,
);

exit &main();

sub main {

print "\n\nIN SCRIPT TEST====sshstopvip==ssh_stop_vip==ssh_start_vip===\n\n";

if ( commandeq"stop"command eq "stop" || command eq "stopssh" ) {

my exit_code = 1; eval { print "Disabling the VIP on old master: orig_master_host \n";
&stop_vip();
exit_code = 0; }; if (@) {
warn "Got Error: @\n";exit@\n"; exit exit_code;
}
exit exit_code; } elsif ( command eq "start" ) {

my exit_code = 10; eval { print "Enabling the VIP - vip on the new master - new_master_host \n"; &start_vip(); exit_code = 0;
};
if (@) { warn @;
exit exit_code; } exit exit_code;
}
elsif ( command eq "status" ) { print "Checking the Status of the script.. OK \n"; exit 0; } else { &usage(); exit 1; } } sub start_vip() { `ssh ssh_user@new_master_host \" ssh_start_vip "`;
}

#A simple system call that disable the VIP on the old_master

sub stop_vip() {
ssh sshuser\@ssh_user\@orig_master_host " $ssh_stop_vip " ;
}

sub usage {
print
"Usage: master_ip_failover --command=start|stop|stopssh|status --orig_master_host=host --orig_master_ip=ip --orig_master_port=port --new_master_host=host --new_master_ip=ip --new_master_port=port\n";
}

在 manager 节点上启动 MHA
nohup masterha_manager \
--conf=/opt/mysql-mha/mysql_mha.cnf \
--remove_dead_master_conf \
--ignore_last_failover < /dev/null > /var/log/mha_manager.log 2>&1 &

--remove_dead_master_conf:该参数代表当发生主从切换后,老的主库的 ip 将会从配置文件中移除。
--ignore_last_failover:在缺省情况下,如果 MHA 检测到连续发生宕机,且两次宕机间隔不足 8 小时的话,则不会进行 Failover, 之所以这样限制是为了避免 ping-pong 效应。该参数代表忽略上次 MHA 触发切换产生的文件,默认情况下,MHA 发生切换后会在 app1.failover.complete 日志文件中记录,下次再次切换的时候如果发现该目录下存在该文件将不允许触发切换, 除非在第一次切换后删除该文件,为了方便,这里设置为--ignore_last_failover。

●使用&后台运行程序:结果会输出到终端;使用Ctrl+C发送SIGINT信号,程序免疫;关闭session发送SIGHUP信号,程序关闭。
●使用nohup运行程序:结果默认会输出到nohup.out;使用Ctrl+C发送SIGINT信号,程序关闭;关闭session发送SIGHUP信号,程序免疫。
●使用nohup和&配合来启动程序nohup ./test &:同时免疫SIGINT和SIGHUP信号。

查看 MHA 状态,可以看到当前的 master 是 mysql1 节点。
masterha_check_status --conf=/opt/mysql-mha/mysql_mha.cnf

查看 MHA 日志,也以看到当前的 master 是 192.168.30.200,如下所示。
cat /opt/mysql-mha/manager.log | grep "current master"

查看 mysql1 的 VIP 地址 192.168.30.240 是否存在,这个 VIP 地址不会因为 manager 节点停止 MHA 服务而消失。
ifconfig

//若要关闭 manager 服务,可以使用如下命令。
masterha_stop --conf=/opt/mysql-mha/mysql_mha.cnf
或者可以直接采用 kill 进程 ID 的方式关闭。