前言
經過一段時間的積累,數據庫的架構就需要根據項目不斷的進行變化。
從單台數據庫,到了兩台數據庫的主從,再到讀寫分離,再到雙主,現在進一步需要更多的數據庫服務器去支撐更加可怕的訪問量。
那么經過那么多的學習,也了解到,進一步的架構還有很多,負載均衡,集群,等等。接下來作一一說明。
負載均衡的意義
可能有很多人一開始聽見這個名詞的時候,都覺得很厲害的樣子。然后也不知道它是干嘛的,總覺得聽起來很厲害。
舉個例子,把10件事原本要求一個人完成,現在分給10個人去做。這就是負載均衡。
負載:壓力很大的事,均衡:按照一定的規則分給不同的人去完成。
這樣理解,你就能很清楚為什么要用負載均衡了,因為一個人忙不過來了。
負載均衡各種實現方式的比較
查閱相關資料發現,mysql負載均衡的實現方式真的有很多,如常見的nginx,LVS,HAProxy等等。還有一些不開源的實現方式這邊就不列舉了,下面對這些常見的方式進行比較。
一、nginx
1、首先nginx具有功能有:反向代理、負載均衡、HTTP服務器、正向代理。在反向代理上面很出眾。
2、工作在網絡的第七層也就是應用層,對於網絡的穩定性依賴比較小,只要能ping通就能進行負載均衡。
3、某個節點出現問題,能在過程中就切換,比如上傳文件,用戶上傳到一半,服務器突然宕機,nginx會把上傳切到另一台服務器上面重新處理,而LVS如果沒有任何第三方的檢測軟件等普通情況下直接就中斷了和用戶的請求。
4、配置簡單,nginx畢竟面向的是應用,相對於別的來說配置簡單,而且網上資料畢竟充足,基本上需要的配置都能查到資料。
5、動靜分離,讓動態網站里面的不變的資源和經常變動的資源分開,nginx能提供靜態資源的訪問,從而減輕tomcat等應用容器的壓力。
6、反向代理,這里不進行細說,因為我們重點是負載均衡,但是nginx確實在這方面很出眾。也是你選擇的理由。
7、但是nginx僅僅支持的是http、https、email協議,適用的范圍較小,對於服務器的檢測只是通過端口檢測,而不支持通過url檢測。
8、在速度上面,畢竟nginx是工作在應用層的,和LVS相比,LVS是工作在網絡層,所以性能上面自然沒有LVS來的強大。
二、LVS
1、工作在網絡層,抗負載均衡能力強大,沒有流量產生,所以性能出眾,對內存和cup消耗較低。
2、經常使用LVS+keepalived進行雙機熱備,所以相對來說穩定可靠。
3、無流量,LVS只分發請求,而流量並不從它本身出去,這點保證了負載均衡服務器的IO性能不會受到大流量的影響。因為作為負載均衡服務器來說,當用戶訪問量大的時候,其實第一個訪問的就是他自己,所以它自己的性能影響就變得重要。
4、工作范圍廣,幾乎可以應對各種負載均衡的要求,沒有很強的限制。
5、但是相對來說,配置相對復雜一些,不支持動靜分離,一些健康檢測需要自行編寫腳本完成。
三、HAProxy
1、與nginx類似,但是支持session的保持,cookie的引導,支持通過獲取指定的url來檢測后端服務器的狀態。
2、在並發處理的效率上面,比nginx來的高。
3、支持TCP協議的負載均衡轉發。
4、負載均衡的策略比較多,可供選擇的比較多。
5、速度和影響上面,沒有LVS來的好。
那么你們一定會有問題,那么到底該如何選擇呢?
其實網上比較多的方案都是使用Nginx/HAProxy+keepalived作為前端的負載均衡;而后端采用LVS+keepalived對一主多從的mysql數據庫進行負載均衡。但是這也只是比較多的方案。
在我看來方案都是需要結合實際情況來考慮的。如果你的訪問量並不是很大,其實nginx就完全夠用了,配置簡單,而且能實現反向代理和動靜分離,而且出現問題也比較容易解決。而且當前的性能完全足夠滿足用戶需求即可。而當你的訪問量特別大的時候,比如PV超百萬或者更大,那么就需要考慮使用LVS了,如果作為負載均衡的服務器掛了,那么你后面服務器再多也沒用了,LVS首先能保證的就是你的負載均衡服務器不會掛。
所以可能你還是需要從實際的角度考慮,是否這樣的架構滿足你當前的性能支持。
LVS+keepalived實現mysql負載均衡
因為之前使用nginx做過反向代理和負載均衡,所以這次使用LVS+keepalived實現mysql負載均衡,看看區別到底在哪里。
首先我先實現的是LVS+keepalived對於Apache服務器的負載均衡,因為對於mysql,負載均衡是實現應該是和Apache一樣的,而最不同的就是檢測的方式,網站的訪問一般采用80端口,而且只需要進行tcp的檢測就知道是否能訪問這個網站,keepalived默認就提供了這樣的健康檢測方式,這樣我們就不需要過多的配置。而對於mysql狀態來說,簡單的tcp請求是不能檢測出mysql服務是否正常啟動或者mysql是否為可以被訪問的狀態。所以我們先從簡單的着手。
下面是過程:
1、准備工作:確定各個機器的ip,關閉防火牆等等
2、配置lvs(這里的配置是在服務器,也就是安裝apach的服務器上面,而不是負載均衡服務器上!!!!)
cd /etc/init.d/
vi realserver
SNS_VIP=192.168.75.100 /etc/rc.d/init.d/functions case "$1" in start) ifconfig lo:0 $SNS_VIP netmask 255.255.255.255 broadcast $SNS_VIP /sbin/route add -host $SNS_VIP dev lo:0 echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce sysctl -p >/dev/null 2>&1 echo "RealServer Start OK" ;; stop) ifconfig lo:0 down route del $SNS_VIP >/dev/null 2>&1 echo "0" >/proc/sys/net/ipv4/conf/lo/arp_ignore echo "0" >/proc/sys/net/ipv4/conf/lo/arp_announce echo "0" >/proc/sys/net/ipv4/conf/all/arp_ignore echo "0" >/proc/sys/net/ipv4/conf/all/arp_announce echo "RealServer Stoped" ;; *) echo "Usage: $0 {start|stop}" exit 1 esac exit 0
注意SNS_VIP需要根據你當前的幾台機器的ip來設置
我的兩台服務器ip為192.168.75.128和192.168.75.130
負載均衡服務器的ip為192.168.75.129
所以我設置VIP為192.168.75.100
這里的VIP就是我們最終需要進行訪問的IP地址,而並非訪問真實的IP地址
保存腳本文件后更改該文件權限:chmod 777 realserver
開啟realserver服務:service realserver start
兩台都一樣這樣配置完成之后
3、配置負載均衡服務器
yum install -y keepalived
cd /etc/keepalived
> keepalived.conf
vi keepalived.conf
global_defs { router_id LVS_DEVEL # 設置lvs的id,在一個網絡內應該是唯一的 } vrrp_instance VI_1 { state MASTER #指定Keepalived的角色,MASTER為主,BACKUP為備 interface eth1 #你的網卡號碼 virtual_router_id 51 #虛擬路由編號,主備要一致 priority 100 #定義優先級,數字越大,優先級越高,主DR必須大於備用DR advert_int 1 #檢查間隔,默認為1s authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 192.168.75.100 #定義虛擬IP(VIP)為192.168.75.101,可多設,每行一個 } } # 定義對外提供服務的LVS的VIP以及port virtual_server 192.168.75.100 80 { delay_loop 6 # 設置健康檢查時間,單位是秒 lb_algo wrr # 設置負載調度的算法為wlc lb_kind DR # 設置LVS實現負載的機制,有NAT、TUN、DR三個模式 nat_mask 255.255.255.0 persistence_timeout 0 protocol TCP real_server 192.168.75.130 80 { # 指定real server1的IP地址 weight 3 # 配置節點權值,數字越大權重越高 TCP_CHECK { connect_timeout 10 nb_get_retry 3 delay_before_retry 3 connect_port 80 } } real_server 192.168.75.128 80 { # 指定real server2的IP地址 weight 3 # 配置節點權值,數字越大權重越高 TCP_CHECK { connect_timeout 10 nb_get_retry 3 delay_before_retry 3 connect_port 80 } } }
其中需要修改的就是三個ip地址和
網卡號碼
interface eth1這是個坑,很多人最后不成功就敗在這里,並不是每個人的系統網卡都是eth1的,你需要百度一下查詢本機網卡的命令,然后修改為你自己網卡的名字。
啟動服務之后就行了:service keepalived start
這時你就已經實現了負載均衡的基本功能了,訪問時注意打開兩台服務器上的apach。還要注意的是訪問的是你的虛擬IP,我這里是192.168.75.100,不要訪問真實的IP。
如果沒有成功:service keepalived status,查看情況,把出現的報錯在網上搜索一下進行解決。這里就不一一列舉錯誤了。或者使用ipvsadm命令查看連接情況。
那么這時肯定就會有人說,難道mysql的負載均衡就只要把端口改成3306就可以了嗎?
講道理呢,如果你只要實現的是負載均衡的話,那確實,改成3306,就可以了,只要裝好mysql然后把兩台mysql的密碼一樣,模擬兩台主從就可以嘗試着訪問了。
也就是修改配置如下:
global_defs { router_id LVS_DEVEL # 設置lvs的id,在一個網絡內應該是唯一的 } vrrp_instance VI_1 { state MASTER #指定Keepalived的角色,MASTER為主,BACKUP為備 interface eth1 #你的網卡號碼 virtual_router_id 51 #虛擬路由編號,主備要一致 priority 100 #定義優先級,數字越大,優先級越高,主DR必須大於備用DR advert_int 1 #檢查間隔,默認為1s authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 192.168.75.100 #定義虛擬IP(VIP)為192.168.75.101,可多設,每行一個 } } # 定義對外提供服務的LVS的VIP以及port virtual_server 192.168.75.100 3006 { delay_loop 6 # 設置健康檢查時間,單位是秒 lb_algo wrr # 設置負載調度的算法為wlc lb_kind DR # 設置LVS實現負載的機制,有NAT、TUN、DR三個模式 nat_mask 255.255.255.0 protocol TCP real_server 192.168.75.130 3306 { # 指定real server1的IP地址 weight 3 # 配置節點權值,數字越大權重越高 TCP_CHECK { connect_timeout 10 nb_get_retry 3 delay_before_retry 3 connect_port 3306 } } real_server 192.168.75.128 3306 { # 指定real server2的IP地址 weight 3 # 配置節點權值,數字越大權重越高 TCP_CHECK { connect_timeout 10 nb_get_retry 3 delay_before_retry 3 connect_port 3306 } } }
而且很多我也看到有博客寫的也是這樣的我也這樣試過確實實現了:如下圖,我用本地圖形化界面進行訪問嘗試
我在128和130的mysql上面都建了一個數據庫進行區別,訪問同一個192.168.75.100就能訪問到兩個不同的數據庫了,實現了負載均衡。
但是很多人到了這步之后就萬事大吉了,都覺得實現了,就好了,作為程序員應該有邊界情況的考慮習慣。如果你把某一台數據庫的服務停止之后就會發現,不對了。
比如這里我把128的數據庫服務停止之后,再次進行訪問,130照常能訪問,但是第二次訪問到128的時候,出現了
很多人不以為然,但是這就出現問題了,負載均衡服務器一個重要的點就是,當有一台服務器無法訪問的時候,應該把這個請求轉移到其他的服務器上面去,這里128的服務器掛了,其實我們應該一直訪問到130,而並非收到這樣一個訪問不到的請求。如果這樣出現在現實之中,就會造成,sql執行失敗,而並不會均衡到另一台上面去,這也就是我之前說的,mysql的檢測問題了,也就是數據庫負載均衡和普通的負載均衡的區別。
keepalived本身提供的檢測方式有:
keepalived對后端realserver的健康檢查方式主要有以下幾種
-
TCP_CHECK:工作在第4層,keepalived向后端服務器發起一個tcp連接請求,如果后端服務器沒有響應或超時,那么這個后端將從服務器池中移除。
-
HTTP_GET:工作在第5層,向指定的URL執行http請求,將得到的結果用md5加密並與指定的md5值比較看是否匹配,不匹配則從服務器池中移除;此外還可以指定http返回碼來判斷檢測是否成功。HTTP_GET可以指定多個URL用於檢測,這個一台服務器有多個虛擬主機的情況下比較好用。
-
SSL_GET:跟上面的HTTP_GET相似,不同的只是用SSL連接
-
MISC_CHECK:用腳本來檢測,腳本如果帶有參數,需將腳本和參數放入雙引號內。腳本的返回值需為:
0) 檢測成功
1) 檢測失敗,將從服務器池中移除
2-255)檢測成功;如果有設置misc_dynamic,權重自動調整為 退出碼-2,如退出碼為200,權重自動調整為198=200-2。
-
SMTP_CHECK:用來檢測郵件服務的smtp的
這幾種方式能滿足我們需求的只有MISC_CHECK方式
簡單的說,我們需要寫一個腳本去檢測Msql的狀態,如果mysql不能被訪問,則從負載均衡服務器中把這個服務器的ip移除。
下面是修改keepalived的配置文件
! Configuration File for keepalived global_defs { #全局標識模塊 router_id LVS_DEVEL } vrrp_instance VI_1 { state MASTER #本實例啟動狀態:MASTER/BACKUP interface eno1 #監控的網絡接口 virtual_router_id 51 #vrrp實例(同一個組主備服務器設置一樣) priority 100 #優先級高的為master,不能超過255。(BACKUP可設置為50) advert_int 1 #均衡器檢測間隔1秒(服務器設置都一樣) authentication { #驗證類型及密碼(服務器設置都一樣) auth_type PASS #認證方式,PASS或AH auth_pass 123456 #認證密碼 } virtual_ipaddress { #虛擬ip地址virtual_ipaddress,可以定義多個 192.168.75.100 } } virtual_server 192.168.75.100 3306 { #定義虛擬服務器,與上面的virtual_server一樣 delay_loop 6 #健康檢查時間間隔,6秒 lb_algo wrr #負載均衡調度算法:rr|wrr|lc|wlc|sh|dh|lblc lb_kind DR #負載均衡轉發規則:NAT|DR|TUN nat_mask 255.255.255.0 persistence_timeout 0 #回話保持時間50秒,動態服務建議開啟 protocol TCP #轉發協議protocol,一般有tcp和udp兩種 #后端真實服務器,有幾台就設置幾個 real_server 192.168.75.128 3306 { weight 1 #權重越大負載分越大,0表示失效 MISC_CHECK { #健康檢查方式:HTTP_GET|SSL_GET|TCP_CHECK|SMTP_CHECK|MISC_CHECK connect_timeout 60 nb_get_retry 3 delay_before_retry 3 connect_port 3306 misc_path "/etc/keepalived/mysql_check.sh 192.168.75.128" misc_timeout 60 misc_dynamic } } real_server 192.168.75.130 3306 { weight 1 MISC_CHECK { connect_timeout 60 nb_get_retry 3 delay_before_retry 3 connect_port 3306 misc_path "/etc/keepalived/mysql_check.sh 192.168.75.130" misc_timeout 60 misc_dynamic } } }
misc_path "/etc/keepalived/mysql_check.sh 192.168.75.128" 這個參數是你的腳本所在的位置,空格后面的ip為輸入的參數
misc_timeout 這個是超時的時間,建議配置的時間長一點,有時候mysql狀態返回的很慢。
然后是腳本的編寫,這里是我從網上找的,然后修改了一下的腳本,只是簡單的用ping命令檢測了一下,但是實際檢測應該需要比這個更加細致。比如檢測數據庫連接數等等。需要注意的是,因為檢測使用了mysql的ping命令所以在負載均衡服務器上面需要安裝一個mysql。能提供mysql命令運行即可。
下面是腳本:
#!/bin/bash MYSQL_PING=`/usr/local/mysql/bin/mysqladmin -u root -h $1 ping` MYSQL_OK="mysqld is alive" if [[ ${MYSQL_PING} == ${MYSQL_OK} ]]; then echo "yes" exit 0 else echo "no" exit 1 fi
其中我把mysql的密碼配置在了/etc/my.cnf文件下面,如下所示,因為在命令中寫密碼會有警告
[mysqladmin]
password=******
需要注意的是,你需要在啟動keepalived之前測試你的腳本是否真的正常,是否顯示yes和no當數據庫服務啟動和關閉的時候(記得給腳本足夠的權限,否則無法運行)
./mysql_check.sh 192.168.75.128
顯示:yes
如果當數據庫服務處於打開狀態依舊無法訪問則需要查看mysql是不是禁止了外部的訪問等限制問題。
最后重啟keepalived即可
service keepalived restart
總結和思考
1、根據實際情況去選擇相應的架構實現相應的功能。
2、keepalived還有備份,各種不同的負載均衡策略,等等配置,需要進一步深入學習。
3、對於mysql的檢測,有一些第三方的軟件可以實現精細化的檢測,從而更好的進行負載均衡的選擇。
4、對於一主多從的情況,對於多態從服務器可以使用負載均衡,但是當寫的能力也不夠用的時候需要進一步升級架構,為數據庫集群。可以使用mysql cluster等,然后再進行負載均衡。
5、總之這里做的只是實驗,具體到實際情況之下可能有很多配置都需要進行改動,沒有經過實際的項目測試,所以很多問題可能還沒有遇到,需要經過實際項目的經驗才能有更好的提升。
參考網站:
借助LVS+Keepalived實現負載均衡http://www.cnblogs.com/edisonchou/p/4281978.html(apach是安裝這個流程走的)
LVS+Keepalived實現mysql的負載均衡http://www.cnblogs.com/tangyanbo/p/4305589.html(大致流程都是依照這個來做的,寫的很棒)
Nginx/LVS/HAProxy負載均衡軟件的優缺點詳解http://www.ha97.com/5646.html(解釋了各個優缺點,很詳細)
Lvs之NAT、DR、TUN三種模式的應用配置案例 http://www.sxt.cn/info-3188-u-324.html
keepalived的健康檢查方式 http://blog.chinaunix.net/uid-10480699-id-5179873.html
改良版本的使用keepalived構建高可用mysql-HAhttp://kongchen.github.io/keepalived-mysql-ha/(這個是把keepalived和mysql安裝在同一台服務器上,利用keepalived本身去對mysql做健康檢測)
國外的一個上述的配置實踐https://www.atlantic.net/community/howto/multi-master-mysql-percona-keepalived/(這個腳本與我寫的不同,可以做參考進行修改)