淺談mysql-MHA
一、MHA簡介
MHA(Master High Availability)目前在MySQL高可用方面是一個相對成熟的解決方案,它由日本人youshimaton開發,是一套優秀的作爲MySQL高可用性環境下故障切換和主從提升的高可用軟件。在MySQL故障切換過程中,MHA能做到0~30秒之內自動完成數據庫的故障切換操作,並且在進行故障切換的過程中,MHA能最大程度上保證數據庫的一致性,以達到真正意義上的高可用。
MHA由兩部分組成:MHA Manager(管理節點)和MHA Node(數據節點)。MHA Manager可以獨立部署在一臺獨立的機器上管理多個Master-Slave集羣,也可以部署在一臺Slave上。當Master出現故障時,它可以自動將最新數據的Slave提升爲新的Master,然後將所有其他的Slave重新指向新的Master。整個故障轉移過程對應用程序是完全透明的。
【基本原理】:
從宕機崩潰的master保存二進制日誌事件(binlog events);
識別含有最新更新的slave;
應用差異的中繼日誌(relay log)到其他的slave;
應用從master保存的二進制日誌事件(binlog events);
提升一個slave爲新的master;
使其他的slave連接新的master進行復制;
MHA軟件由兩部分組成,Manager工具包和Node工具包,具體的說明如下:
Manager工具包主要包括以下幾個工具:
masterha_check_ssh 檢查MHA的SSH配置狀況
masterha_check_repl 檢查MySQL複製狀況
masterha_manger 啓動MHA
masterha_check_status 檢測當前MHA運行狀態
masterha_master_monitor 檢測master是否宕機
masterha_master_switch 控制故障轉移(自動或者手動)
masterha_conf_host 添加或刪除配置的server信息
Node工具包主要包括以下幾個工具:
save_binary_logs 保存和複製master的二進制日誌
apply_diff_relay_logs 識別差異的中繼日誌事件
filter_mysqlbinlog 去除不必要的ROLLBACK事件
purge_relay_logs 清除中繼日誌
二、公司需求
不影響mysql性能(不開啓半同步)
不增加mysql服務器(按原有集羣,一主三從)
不使用keepalived(多臺切換)
不影響讀寫分離功能
1.mysql架構
圖1.1
【測試MHA】:
角色 | IP地址 | 主機名 |
MHA manger | 172.16.1.53 | mha03 |
MySQL master | 172.16.1.51 | mha01 |
MySQL slave1 | 172.16.1.52 | mha02 |
MySQL slave2 | 172.16.1.53 | mha03 |
Atlas | 51、52、53 | 三臺都裝 |
2.安裝mysql
所需安裝包:
mysql-5.5.32-linux2.6-x86_64.tar.gz
[root@db01 ~]# cd /usr/local/src/
[root@db01 src]# rz -y #將安裝包上傳至/usr/local/src目錄下
[root@db01src]# tar xf mysql-5.5.32-linux2.6-x86_64.tar.gz #解壓二進制包
[root@db01 src]# mv mysql-5.5.32-linux2.6-x86_64/application/mysql-5.5.32 #移動並改名
[root@db01 src]# ln -s /application/mysql-5.5.32//application/mysql #做軟連接
[root@db01 scripts]# useradd mysql -s/sbin/nologin -M #創建mysql用戶
[root@db01 src]# cd/application/mysql/scripts/ #進入mysql初始化目錄
[root@db01 scripts]# ./mysql_install_db--user=mysql --datadir=/application/mysql/data/--basedir=/application/mysql/ #初始化mysql
[root@db01 scripts]# cd ../support-files/ #進入mysql功能文件目錄
[root@db01 support-files]# cp my-small.cnf/etc/my.cnf #將mysql的配置文件拷貝到/etc下
[root@db01 support-files]# cp mysql.server/etc/init.d/mysqld #將mysql啓動文件拷貝到/etc下
[root@db01support-files]# sed -i 's#/usr/local#/application#g'/etc/init.d/mysqld /application/mysql/bin/mysqld_safe #修改啓動文件
[root@db01 support-files]# exportPATH="/application/mysql/bin/:$PATH" #將mysql的命令放置系統中
[root@db01support-files]# echo "exportPATH="/application/mysql/bin/:$PATH"" >> /etc/profile #將以上命令寫入環境變量
[root@db01support-files]# source /etc/profile #刷新環境變量
[root@db01support-files]# /etc/init.d/mysqld start #啓動mysql
StartingMySQL.... SUCCESS #mysql啓動成功
[root@db01support-files]# mysql -uroot password faxuan #給mysql設置密碼
[root@db01support-files]# netstat -anltup|grep 3306 #檢查mysql端口
[root@db01support-files]# ps -ef|grep mysql #檢查mysql進程
至此,mysql就搭建完畢,其它幾臺也同樣
3.設置主從複製
主庫和從庫都要開啓bin-log日誌
所有的mysql的server-id不同
創建從庫複製權限的用戶
【主庫操作】:
[root@db01 tools]# vim /etc/my.cnf #修改配置文件
server-id = 1 #主庫爲1 從庫必須大於1
[root@db02tools]# /etc/init.d/mysqld restart #重啓mysql
[root@db01 support-files]# mysql -uroot-pfaxuan #登錄數據庫
mysql> grant replication slave on *.* to slave@'172.16.1.%' identified by '123456'; #授權用戶
mysql> show master status; #查看主庫bin-log值
+---------------------------+-----------+---------------------+-------------------------+
| File | Position | Binlog_Do_DB |Binlog_Ignore_DB |
+---------------------------+------------+---------------------+------------------------+
| mysql-bin.000004 | 257 | | | #記住標顏色的兩個值
+----------------------------+-----------+--------------------+-------------------------+
【從庫操作】:
[root@db01 tools]# vim /etc/my.cnf #修改配置文件
server-id = 1 ==》 1改爲2 #主庫爲1 從庫必須大於1
[root@db02 tools]# /etc/init.d/mysqld restart #重啓mysql
[root@db02 tools]# mysql -uroot -pfaxuan #登錄數據庫
mysql> change master to #在從庫上設置主庫信息
->master_host='172.16.1.51', #主庫IP
->master_user='slave', #授權用戶(在主庫上操作授權的用戶)
->master_password='123456', #授權用戶的密碼
->master_log_file='mysql-bin.000004', #剛纔主庫記錄的File值
-> master_log_pos=257; #剛纔主庫記錄的Position值
mysql> start slave; #開啓複製
mysql> show slave status\G #查看複製狀態
Slave_IO_Running: Yes
Slave_SQL_Running:Yes #主從複製成功
至此,主從複製完畢,其它幾臺也同樣
【從庫設置】:
[root@db02 tools]# mysql -uroot -pfaxuan #登錄mysql
mysql> set global relay_log_purge = 0; #禁用自動刪除功能
mysql> set global read_only=1; #從庫不可寫
[root@db02 tools]# vim /etc/my.cnf #編輯配置文件
relay_log_purge = 0 #不自動刪除relay log
[root@db02 tools]# /etc/init.d/mysqld restart #重啓mysql
4、安裝mysql MHA
所需安裝包:
mha4mysql-node-0.56-0.el6.noarch.rpm
mha4mysql-manager-0.56-0.el6.noarch.rpm
【所有節點】:
[root@db01 ~]# yum install perl-DBD-MySQL -y #安裝依賴包
將mha4mysql-node-0.56-0.el6.noarch.rpm上傳到/usr/local/src下
[root@db01 src]# rpm -ivhmha4mysql-node-0.56-0.el6.noarch.rpm #安裝
[root@db01 src]# mysql -uroot -pfaxuan #登錄mysql
mysql> grant all privileges on *.* tomha@'172.16.1.%' identified by 'mha'; #添加管理賬號
[root@db01 src]# ln -s/application/mysql/bin/mysqlbinlog /usr/bin/mysqlbinlog #創建軟連接
[root@db01 src]# ln -s/application/mysql/bin/mysql /usr/bin/mysql #創建軟連接
【管理節點】:
[root@mha03tools]# wget -O/etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo #使用epel源
[root@db03 src]# yum install -y perl-Config-Tinyepel-release perl-Log-Dispatch perl-Parallel-ForkManager perl-Time-HiRes #安裝依賴包
將mha4mysql-manager-0.56-0.el6.noarch.rpm 包上傳到/usr/local/src下
[root@db03 src]# rpm -ivhmha4mysql-manager-0.56-0.el6.noarch.rpm #安裝
[root@db03 src]# mkdir -p /etc/mha #在/etc下創建mha目錄
[root@db03 src]# mkdir -p /var/log/mha/app1 #創建日誌目錄
[root@db03 src]# vim /etc/mha/app1.cnf #編輯配置文件
[server default]
manager_log=/var/log/mha/app1/manager #管理日誌目錄
manager_workdir=/var/log/mha/app1 #管理工作目錄
master_binlog_dir=/application/mysql/data #主庫bin-log日誌
user=mha #上一步授權的用戶
password=mha #上一步授權的密碼
ping_interval=2
repl_password=123456 #複製密碼(主從)
repl_user=slave #複製用戶(主從)
ssh_user=root #ssh遠程連接用戶
[server1] #第一個主機
hostname=172.16.1.51 #IP
port=3306 #端口
[server2]
candidate_master=1 #優先的新主人(切換主庫優先)
check_repl_delay=0 #忽略複製延遲
hostname=172.16.1.52
port=3306
[server3]
hostname=172.16.1.53
port=3306
【配置文件詳解】:
[server default]
manager_workdir=/var/log/masterha/app1.log ##設置manager的工作目錄
manager_log=/var/log/masterha/app1/manager.log ##設置manager的日誌
master_binlog_dir=/data/mysql ##設置master 保存binlog的位置,以便MHA可以找到master的日誌,我這裏的也就是mysql的數據目錄
master_ip_failover_script=/usr/local/bin/master_ip_failover ##設置自動failover時候的切換腳本
master_ip_online_change_script=/usr/local/bin/master_ip_online_change ##設置手動切換時候的切換腳本
password=123456 ##設置mysql中root用戶的密碼,這個密碼是前文中創建監控用戶的那個密碼
user=root 設置監控用戶root
ping_interval=1 ##設置監控主庫,發送ping包的時間間隔,默認是3秒,嘗試三次沒有迴應的時候自動進行railover
remote_workdir=/tmp ##設置遠端mysql在發生切換時binlog的保存位置
repl_password=123456 ##設置複製用戶的密碼
repl_user=repl ##設置複製環境中的複製用戶名
report_script=/usr/local/send_report ##設置發生切換後發送的報警的腳本
secondary_check_script=/usr/local/bin/masterha_secondary_check -s server03 -s server02 --user=root--master_host=server02 --master_ip=192.168.0.50 --master_port=3306 ##一旦MHA到server02的監控之間出現問題,MHA Manager將會嘗試從server03登錄到server02
shutdown_script="" ##設置故障發生後關閉故障主機腳本(該腳本的主要作用是關閉主機放在發生腦裂,這裏沒有使用)
ssh_user=root ##設置ssh的登錄用戶名
[server1]
hostname=172.16.1.51
port=3306
[server2]
hostname=172.16.1.52
port=3306
candidate_master=1 ##設置爲候選master,如果設置該參數以後,發生主從切換以後將會將此從庫提升爲主庫,即使這個主庫不是集羣中事件最新的slave
check_repl_delay=0 ##默認情況下如果一個slave落後master 100M的relay logs的話,MHA將不會選擇該slave作爲一個新的master,因爲對於這個slave的恢復需要花費很長時間,通過設置check_repl_delay=0,MHA觸發切換在選擇一個新的master的時候將會忽略複製延時,這個參數對於設置了candidate_master=1的主機非常有用,因爲這個候選主在切換的過程中一定是新的master
[server3]
hostname=172.16.1.53
port=3306
【配置ssh祕鑰登錄】:
[root@db01 src]# ssh-keygen -t rsa #創建祕鑰對
[root@db01 src]# ssh-copy-id -i/root/.ssh/id_rsa.pub [email protected] #分發公鑰,包括自己
[root@db01 src]# ssh-copy-id -i/root/.ssh/id_rsa.pub [email protected]
[root@db01 src]# ssh-copy-id -i/root/.ssh/id_rsa.pub [email protected]
其它兩臺也同樣配置
【測試】:
在管理機上操作
[root@db03 src]# masterha_check_ssh--conf=/etc/mha/app1.cnf #測試ssh
Tue Aug 2 14:37:44 2016 - [info] All SSHconnection tests passed successfully. #說明ssh配置成功
[root@db03 src]# masterha_check_repl--conf=/etc/mha/app1.cnf #測試複製
MySQL Replication Health is OK. #說明覆制配置成功
【啓動MHA】:
[root@db03 src]# nohup masterha_manager--conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover </dev/null > /var/log/mha/app1/manager.log 2>&1 &
【測試】:
[root@db02 src]# mysql -uroot -pfaxuan #登錄從庫的mysql
mysql> show slave status\G #查看複製狀態
主庫是172.16.1.51
[root@db01 src]# /etc/init.d/mysqld stop #在主庫上執行,停掉主庫
mysql> show slave status\G #再在從庫查看複製狀態
可以看到,主庫自動切換成了,mha配置文件中設置的172.16.1.53
再次啓動172.16.1.51主的mysql後,不會自動加入集羣。
需要手動修改配置文件,將172.16.1.51更改爲數據從庫。
本次MHA架構搭建成功。
三、測試VIP漂移
1.vip配置可以採用兩種方式:
通過keepalived的方式管理虛擬ip的漂移。
通過MHA自帶腳本方式啓動虛擬ip的方式(即不需要keepalived或者heartbeat類似的軟件)。
因爲公司的需求,這裏給大家介紹第二種方式:
2.修改配置文件:
[root@db03 bin]# vim /etc/mha/app1.cnf
[server default]
manager_log=/var/log/mha/app1/manager.log
manager_workdir=/var/log/mha/app1.log
master_binlog_dir=/application/mysql/data
master_ip_failover_script=/usr/local/bin/master_ip_failover #MHA自帶腳本
password=mha
ping_interval=1
remote_workdir=/tmp
repl_password=123456
repl_user=slave
shutdown_script=""
ssh_user=root
user=mha
[server1]
hostname=172.16.1.51
port=3306
[server2]
hostname=172.16.1.52
port=3306
[server3]
hostname=172.16.1.53
port=3306
在這裏不配置之前介紹的以下兩個參數:
andidate_master=1 #優先的新主人
heck_repl_delay=0 #忽略複製延遲
因爲我們需要實現,多臺主機之間互相切換,不使用keepalived
這個配置比較適合兩臺服務器做半同步,然後再加上keepalived
3.編寫腳本:
#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';
use Getopt::Long;
my (
$command, $ssh_user, $orig_master_host, $orig_master_ip,
$orig_master_port, $new_master_host, $new_master_ip, $new_master_port
);
my $vip = '172.16.1.55/24'; #虛擬IP
my $key = '1';
my $ssh_start_vip = "/sbin/ifconfig eth1:$key$vip";
my $ssh_stop_vip = "/sbin/ifconfig eth1:$keydown";
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====$ssh_stop_vip==$ssh_start_vip===\n\n";
if ( $commandeq "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$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 \"`;
}
sub stop_vip() {
return0 unless ($ssh_user);
`ssh$ssh_user\@$orig_master_host \" $ssh_stop_vip \"`;
}
sub usage {
"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";
}
[root@db01 ~]# ifconfig eth1:1 172.16.1.55 #手動給master上添加VIP
[root@db01 ~]#ip a|grep eth1
3: eth1:<BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen1000
inet 172.16.1.51/24 brd 172.16.1.255 scopeglobal eth1
inet 172.16.1.55/16 brd172.16.255.255 scope global eth1:1
#查看手動配置的VIP
4.測試:
[root@db01 ~]# sysbench --test=oltp--oltp-table-size=1000000 --oltp-read-only=off --init-rng=on --num-threads=16--max-requests=0 --oltp-dist-type=uniform --max-time=1800 --mysql-user=root--mysql-socket=/tmp/mysql.sock --mysql-password=faxuan --db-driver=mysql--mysql-table-engine=innodb --oltp-test-mode=complex prepare
sysbench 0.4.12: multi-threaded system evaluation benchmark
Creating table 'sbtest'...
Creating 1000000 records in table 'sbtest'... #插入100000萬條數據
mysql> stopslave; #在從庫52上執行,停止複製
[root@db01 ~]#/etc/init.d/mysqld stop #寫完數據後,將主庫進程停掉
#VIP已經不在51上了