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















 
 
 










 
 
 
 