搭建mysql負(fù)載均衡及高可用環(huán)境
目標(biāo):使用兩臺主機(jī)實(shí)現(xiàn) Mysql 的負(fù)載均衡及冗余,并做到雙主互備;
環(huán)境:rhel5.8,mysql-5.0.77,keepalived-1.2.7,haproxy-1.4.20;
說明:
keepalived 實(shí)現(xiàn)通過 vrrp協(xié)議,通過使一個虛擬IP地址(或稱浮動IP)在主備設(shè)備間的切換來達(dá)到主機(jī)冗余;
而客戶機(jī)通過訪問這個虛擬IP 來獲取服務(wù);
haproxy 是一款負(fù)載均衡軟件,用于將請求按策略轉(zhuǎn)發(fā)給不同主機(jī),達(dá)到負(fù)載均衡的效果;
可以實(shí)現(xiàn)網(wǎng)絡(luò)層或應(yīng)用層上的判斷分配;
mysql 開啟二進(jìn)制日志,做到數(shù)據(jù)庫之間的雙向復(fù)制,保持?jǐn)?shù)據(jù)一致性;
#提醒一下,實(shí)際生產(chǎn)環(huán)境沒人會這樣搭建的,僅通過這個實(shí)驗(yàn)來理解這些概念,希望閱者能有所獲;
server1_ip=192.168.5.11
server2_ip=192.168.5.12
server_vip=192.168.5.111
================================================
#此處關(guān)閉了防火墻,開啟則另配置相應(yīng)規(guī)則
service iptables stop
chkconfig iptables off
ls /opt/soft/ #提取準(zhǔn)備軟件到此處
haproxy-1.4.20.tar.gz keepalived-1.2.7.tar.gz
mkdir /opt/keepalived
mkdir /opt/scripts/ #此實(shí)驗(yàn)用到腳本目錄
mkdir /opt/log/ #此實(shí)驗(yàn)日志文件夾
=================================================
[install_mysql]
#在兩臺主機(jī)上安裝 mysql ,此處使用 rpm 包安裝,yum環(huán)境可以搭本地源;
yum install -y mysql-server
service mysqld start
=======================================================
[create_mysql_test_table]
#分別創(chuàng)建一張相同名稱和字段的表,插入不同的值,方便中途測試 ha 和輪詢是否成功;
#還有分別創(chuàng)建一個相同的用戶
#server1
mysql
>use test;
>create table mywait(name char(9),phone char(14));
>insert into mywait(name,phone) values('wait',15000000000);
#server2
>use test;
>create table mywait(name char(9),phone char(14));
>insert into mywait(name,phone) values('chen',15611111111);
[new_mysql_test_user]
>mysql
>grant all on test.* to diaosi@'%' identified by '123456';
>flush privileges;
=======================================================
#從客戶機(jī)上測試一下;
mysql -udiaosi -p123456 -h 192.168.5.11 -e "select * from test.mywait;"
mysql -udiaosi -p123456 -h 192.168.5.12 -e "select * from test.mywait;"
#至此,mysql 基礎(chǔ)環(huán)境搭建完成;
=======================================================
[install_keepalived]
yum install -y libnl-devel #解決依賴關(guān)系
tar xf /opt/soft/keepalived-1.2.7.tar.gz -C /opt/soft
cd /opt/soft/keepalived-1.2.7/
#with-kernel 指定內(nèi)核版本時,根據(jù)本機(jī)情況使用TAB鍵補(bǔ)全
./configure --prefix=/opt/keepalived --with-kernel-dir=/usr/src/kernels/2.6.18-308.el5-i686/
make && make install
[keepalived_config]
#因?yàn)闆]有安裝在 / 目錄下,所以這些啟動和配置文件都需要再 copy 一下;
cp /opt/keepalived/sbin/keepalived /usr/sbin/
cp /opt/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/
cp /opt/keepalived/etc/sysconfig/keepalived /etc/sysconfig/
mkdir /etc/keepalived
cp /opt/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/
chkconfig keepalived on #設(shè)置開機(jī)啟動
=======================================================
vim /etc/keepalived/keepalived.conf #keepalived 主配文件
#以下的配置適合 keepalived 本身便是服務(wù)提供者的情況;
- ! Configuration File for keepalived
- #簡單的頭部,這里主要可以做郵件通知報警等的設(shè)置,此處就暫不配置了;
- global_defs {
- notificationd LVS_DEVEL
- }
- #預(yù)先定義一個腳本,方便后面調(diào)用,也可以定義多個,方便選擇;
- vrrp_script mysql_chk {
- script "/opt/scripts/mysql_chke.sh"
- interval 2 #腳本循環(huán)運(yùn)行間隔
- weight 2 #腳本的結(jié)果導(dǎo)致優(yōu)先級變更,成功+2
- }
- #VRRP虛擬路由冗余協(xié)議配置
- vrrp_instance VI_1 { #VI_1 是自定義的名稱;
- state MASTER #表明這是一臺主設(shè)備,備用設(shè)備為 BACKUP
- interface eth0 #指定VIP需要綁定的物理網(wǎng)卡
- virtual_router_id 11 #VRID虛擬路由標(biāo)識,也叫做分組名稱,該組內(nèi)的設(shè)備需要相同
- priority 150 #定義這臺設(shè)備的優(yōu)先級 1-254;
- advert_int 1 #生存檢測時的組播信息發(fā)送間隔,組內(nèi)一致
- authentication { #設(shè)置驗(yàn)證信息,組內(nèi)一致
- auth_type PASS #有PASS 和 AH 兩種,常用 PASS
- auth_pass 111 #密碼
- }
- virtual_ipaddress { #指定VIP地址,組內(nèi)一致,可以設(shè)置多個IP
- 192.168.5.111/24
- }
- track_script { #使用在這個域中使用預(yù)先定義的腳本
- mysql_chk
- }
- #此部分所載入的腳本為外部腳本,不需要預(yù)先定義;
- #也可不添加,此實(shí)驗(yàn)在后半部分安裝haproxy后,才有添加;
- notify_master /opt/scripts/start_haproxy.sh #表示當(dāng)切換到master狀態(tài)時,要執(zhí)行的腳本
- notify_fault /opt/scripts/stop_keepalived.sh #故障時執(zhí)行的腳本
- notify_stop /opt/scripts/stop_haproxy.sh #keepalived停止運(yùn)行前運(yùn)行的腳本
- }
#keepalived 主和備的配置文件基本相同;只需要修改:
state BACKUP #修改為備份設(shè)備
priority 100 #優(yōu)先級要比主低
#其它地方根據(jù)實(shí)際情況也可以做調(diào)整;
#p#
=======================================================
#新建剛才配置keepalived 時所定義的腳本,用于在mysql 死亡后結(jié)束 keepalived
- #!/bin/bash
- #mysql_chke.sh
- #
- a=`ps -C mysqld --no-header | wc -l`
- if [ $a -eq 0 ];then
- sleep 3
- /sbin/service keepalived stop
- echo "`date +%c` stop keepalived" >> /opt/log/stop_keepalived.log
- fi
- fi
service keepalived start #在兩臺設(shè)備上面啟動
#開始測試
ip address
#查看主設(shè)備 11 上是否有生成 vip 地址;
#注意事項(xiàng),keepalived 生成的 VIP 對 ifconfig 命令不可見,所以需要使用 ip 命令;
mysql -udiaosi -p123456 -h 192.168.5.111 -e "select * from test.mywait;"
#正常情況是只能查詢到 MASTER 的數(shù)據(jù)庫的數(shù)據(jù);
1、嘗試將 MASTER 的keepalived 停掉
2、down 掉 MASTER 的網(wǎng)卡
3、讓mysql 啟動不了,比如先注釋掉mysql這個用戶,后killall mysqld ,
查看mysql_chke 腳本是否會把 keepalived 結(jié)束掉;
#這個時后 vip 地址會移動到 Slave 主機(jī)上; HA 搭建的是否成功體現(xiàn)于查詢所獲取值的變化;
#當(dāng)將 MASTER 恢復(fù)后,VIP 又會回到 11 的設(shè)備上;
#至此 keepalived 為 mysql 做HA 模式成功;
========================================================================
[install_haproxy]
#用于將請求分別輪詢到 192.168.5.11 192.168.5.12
tar xf /opt/soft/haproxy-1.4.20.tar.gz -C /opt/soft/
cd /opt/soft/haproxy-1.4.20/
make TARGET=linux26 PREFIX=/opt/haproxy install
mkdir /opt/haproxy/conf
mkdir /opt/haproxy/logs
touch /opt/haproxy/conf/haproxy.cfg
========================================================================
[mysql_config]
#修改 mysql 監(jiān)聽,使 mysql 避開 192.168.5.111,因?yàn)?haproxy 也要監(jiān)聽 111:3306 這個IP地址和端口;
vim /etc/my.cnf
#server1
[mysqld]
bind-address=192.168.5.11 #mysql 的監(jiān)聽,添加這一句就好了
#server2
[mysqld]
bind-address=192.168.5.12
#重啟mysql
service mysqld restart
#到現(xiàn)在已經(jīng)不能通過 192.168.5.111 訪問數(shù)據(jù)庫了,接下來配置 haproxy
========================================================================
[config_haproxy]
#主備服務(wù)器的主配文件一致;
vim /opt/haproxy/conf/haproxy.cfg
- global #全局系統(tǒng)配置
- log 127.0.0.1 local0 info #定義日志級別[err warning info debug]
- #local0 是日志設(shè)備,必須為24種標(biāo)準(zhǔn)syslog設(shè)備之一;
- maxconn 4096 #最大鏈接數(shù)
- uid 0 #運(yùn)行該程序的用戶,此處沒有其它用戶了,就用的 root
- gid 0
- daemon #以后臺形式運(yùn)行
- nbproc 1 #進(jìn)程數(shù)量
- defaults #默認(rèn)配置
- mode tcp #所處理的類別 http | tcp | health
- option redispatch #serverId對應(yīng)的服務(wù)器掛掉后,強(qiáng)制定向到其他健康的服務(wù)器
- retries 3 #三次連接失敗則服務(wù)器不用
- timeout connect 5000 #連接超時
- timeout client 50000 #客戶端超時
- timeout server 50000 #服務(wù)器超時
- timeout check 2000 #心跳檢測超時
- listen proxy
- bind 192.168.5.111:3306 #監(jiān)聽地址
- mode tcp
- balance roundrobin #定義負(fù)載方式,此處為輪詢
- log 127.0.0.1 local0 info #定義日志類型
- #rise 3三次正確表示服務(wù)器可用,fall 3表示3次失敗表示服務(wù)器不可用
- server db1 192.168.5.11:3306 check inter 1200 rise 2 fall 3 weight 1
- server db2 192.168.5.12:3306 check inter 1200 rise 2 fall 3 weight 1
- #服務(wù)器狀態(tài)監(jiān)控配置,可以通過定義的地址查看集群狀態(tài);
- listen haproxy_stats
- log 127.0.0.1 local0 info
- mode http
- bind 192.168.5.111:8888
- option httplog
- stats uri /status
- stats realm Haproxy Manager
- stats auth admin:admin #設(shè)置監(jiān)控地址的帳號與密碼
#在keepalived 主配文件中添加剛才在其末端說明的外部定義腳本
#啟動服務(wù)
/opt/haproxy/sbin/haproxy -f /opt/haproxy/conf/haproxy.cfg
#說明事項(xiàng),keepalived 的服務(wù)主備設(shè)備上都可以同時運(yùn)行,實(shí)則只有獲得VIP的服務(wù)器才有效;
#但是 haproxy 啟動的時候需要監(jiān)聽 VIP 地址,所以第一次備用設(shè)備是手動起不了服務(wù)的;
#需要在 keepalived 的notify_master配置項(xiàng)中設(shè)定腳本,當(dāng)此設(shè)備獲得VIP地址后才啟動 haproxy;
#有個問題在這里,我們只設(shè)定了當(dāng)keepalived 停止服務(wù)時,才結(jié)束 haproxy ,沒有設(shè)定移交VIP時是否結(jié)束;
#其實(shí)這也不用擔(dān)心,因?yàn)橹鳈C(jī)上已經(jīng)沒有VIP地址了,即便是監(jiān)聽也無效果,并無干擾;
#p#
========================================================================
##開始測試
#檢測監(jiān)聽
netstat -tunlp | grep ha
netstat -tunlp | grep 3306
# master 設(shè)備上才會有兩個程序監(jiān)聽不同地址的 3306;
#暫未配置 mysql 互為主備就是為了方便這一階段的排錯,這樣能更準(zhǔn)確的測試;
mysql -udiaosi -p123456 -h 192.168.5.111 -e "select * from test.mywait;"
#返回值應(yīng)該是在 server1 server2 之間徘徊;
sed -i 's/^mysql.*$/#&/' /etc/passwd #注釋掉mysql的用戶
service mysqld stop
#這個時候 mysql 服務(wù)已經(jīng)啟動不起了,mysql_chke.sh 腳本會把 keepalived 停止掉;
keepalived 停止前,又會把 haproxy 殺死;當(dāng)備份的設(shè)備獲得 vip 后,則會通過start_haproxy.sh 腳本將 haproxy 啟動起來;
于是并不會因?yàn)榉?wù)器當(dāng)機(jī)或mysql故障,影響我們客戶端對 111 的查詢操作,實(shí)驗(yàn)完成一半了;
#但是測試時,在VIP地址切換過程中,客戶端會有那么2-3秒不能訪問到數(shù)據(jù)庫,這個暫時忽略不計;
sed 's/^#//' /etc/passwd #測試完后,記得恢復(fù)mysql用戶哦;
#恢復(fù)mysql 后,啟動主設(shè)備的 mysqld keepalived ,然后使用 ip a 查看VIP 地址是否有返回來;
#在其中一臺設(shè)備上 killall haproxy ,之后查看集群狀態(tài);
http://192.168.5.111:8888/status
#查看后再將 haproxy 啟動
#至此,已經(jīng)完成 負(fù)載均衡 + 高可用 兩部分,負(fù)載方式為輪詢
========================================================================
##三個腳本,很簡單,就不再介紹了哈;主要是做日志和結(jié)束服務(wù);
- #!bin/bash
- #start_haproxy.sh
- sleep 5
- get=`ip addr |grep 192.168.5.111 |wc -l`
- echo $get >> /opt/log/start_haproxy.log
- if [ $get -eq 1 ]
- then
- echo "`date +%c` success to get vip" >> /opt/log/start_haproxy.log
- /opt/haproxy/sbin/haproxy -f /opt/haproxy/conf/haproxy.cfg
- else
- echo "`date +%c` can not get vip" >> /opt/log/start_haproxy.log
- fi
- #!bin/bash
- #stop_haproxy.sh
- pid=`pidof haproxy`
- echo "`date +%c` stop haproxy" >> /opt/log/stop_haproxy.log
- kill -9 $pid
- #!bin/bash
- #stop_keepalived.sh
- pid=`pidof keepalived`
- if [ $pid == "" ]
- then
- echo "`date +%c` no keepalived process id" >> /opt/log/stop_keepalived.log
- else
- echo "`date +%c` will stop keepalived " >> /opt/log/stop_keepalived.log
- /etc/init.d/keepalived stop
- fi
=======================================================
[mysql Manager Slave]
#mysql 主備配置;兩臺設(shè)備上添加用戶哦;
root#mysql
create database db1;
GRANT REPLICATION SLAVE ON *.* TO 'diaosi1'@'%' IDENTIFIED BY '123456';
#此處注意哦,Slave 權(quán)限必須的,我最初使用 all 權(quán)限,結(jié)果主備始終不同步,改成 Slave 就OK了;
flush privileges;
show grants for diaosi1@'%';
==================================================================
#server1 的 mysql 配置
server_id=1 #服務(wù)器標(biāo)識,唯一
log_bin=mysqlbinlog #啟用二進(jìn)制日志
log_bin_index=mysqlbinlog-index #日志索引文件
log_slave_updates=1 #讓從服務(wù)器把自身復(fù)制的事件和記錄都寫到自己的二進(jìn)制日志里
relay_log=relay-log #中繼日志位置;存放slave端獲取到master端的二進(jìn)制文件信息
replicate_do_db=db1 ##指定需要同步的數(shù)據(jù)庫
#server2 的 mysql 配置
server_id=2
log_bin=mysqlbinlog
log_bin_index=mysqlbinlog-index
log_slave_updates=1
relay_log=relay-log
replicate_do_db=db1
#分別重啟兩服務(wù)
service mysqld restart
mysql> show master status; #查看mysql 的當(dāng)前二進(jìn)制日志文件
+--------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+--------------------+----------+--------------+------------------+
| mysqlbinlog.000001 | 98 | | |
+--------------------+----------+--------------+------------------+
1 row in set (0.28 sec)
#分別連接對方 mysql 日志,開始備份;記得替換 Master_Host 和日志名及MASTER_LOG_POS;
>CHANGE MASTER TO MASTER_HOST='192.168.5.12',master_port=3306,MASTER_USER='diaosi1',MASTER_PASSWORD='123456',MASTER_LOG_FILE='mysqlbinlog.000001',MASTER_LOG_POS=98;
>START SLAVE; #開始同步
mysql> SHOW SLAVE STATUS\G #查看mysql同步狀態(tài)
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.5.11
Master_User: mywait
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysqlbinlog.000001
Read_Master_Log_Pos: 98
Relay_Log_File: relay-log.000002
Relay_Log_Pos: 237
Relay_Master_Log_File: mysqlbinlog.000001
Slave_IO_Running: Yes #表明獲取對方日志文件的連接成功;
Slave_SQL_Running: Yes #將獲取到的日志轉(zhuǎn)成sql語句回寫本地數(shù)據(jù)庫成功;
Replicate_Do_DB: db1
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: 98
Relay_Log_Space: 237
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
1 row in set (0.00 sec)
#主要就是看 Slave_IO_Running,Slave_SQL_Running
#這里錯誤的話,多數(shù)情況是 Slave_IO_Running 的問題,防火墻,用戶權(quán)限,日志是否有啟用等都需要判斷;
=====================================================================
#p#
=====================================================================
#至此 mysql 雙主互備搭建完成,我們的全部實(shí)驗(yàn)規(guī)劃也全部完成;
#進(jìn)入全面測試階段;
#在 server1 的DB1里新建一張表,并賦值
>use db1;
>create table mywait(name char(9),phone char(14));
>insert into mywait(name,phone) values('wait',15888888888);
#新建一個具有 db1 權(quán)限的用戶
grant all on db1.* to diaosi2@'%' identified by '123456';
>flush privileges;
#切換到 test 庫,在mywait 表中插入一條數(shù)據(jù);
use test;
insert into mywait(name,phone) values ('diaosi',15002839961);
#在 server2做驗(yàn)證;
>use db1;
>show tables;
>select * from mywait;
#此時數(shù)據(jù)與 server1 的會數(shù)據(jù)一致,表示mysql同步成功;
select user,host,password from mysql.user;
#在 server1 創(chuàng)建的用戶也會被 server2 所同步;
#select * from test.mywait
#可以看到 server1上的 test 庫并沒有被同步;
#客戶機(jī)上測試
mysql -udiaosi2 -p123456 -h 192.168.5.111 -e "select * from db1.mywait;"
#完畢;
=======================================================
#存在的問題;
在做mysql_chke 腳本時,本打算使用檢查進(jìn)程的形式判斷服務(wù)是否啟動;
`ps -C mysqld --no-header | wc -l`
當(dāng)檢查mysql 進(jìn)程不存在的時候,先試著啟動一次mysqld ,然后再檢測,如果還是啟動不了服務(wù),再結(jié)束 keepalived ;
但是在使用 /etc/rc.d/init.d/mysqld start 啟動后,出現(xiàn)一些問題;
比如mysql 配置文件錯誤或是注銷用戶等,mysql服務(wù)已然起不來了,雖然手動起不來服務(wù);
但使用 ps -C mysqld 還是可以檢查出一條mysqld 的進(jìn)程來,這是什么情況沒弄明白,希望能得到指點(diǎn);
可優(yōu)化項(xiàng),haproxy 的功能很多,可以做成基于權(quán)重的分配方式,或是根據(jù)訪問地址的,甚至可以使用 cookie 做判斷;
大家都可以多測試一下;
有些地方是需要在兩臺服務(wù)器上同時配置的,大家看的時候多留意一下,測試過程中多看日志是最好的排錯方式;
#ip a | ip addr | ip address 效果是一樣的;
這篇博客是我第一次寫,有些粗糙,可能有些地方注釋得還有錯誤,歡迎留言;
這社區(qū)里還有很多比較好的類似文章,大家可以參考著學(xué)習(xí),這樣效率更好,謝謝;