HAProxy提供高可用性(體如今能夠對後端RS的健康檢查)、負載均衡以及基於TCP和HTTP應用的代理,支持虛擬主機,它是免費、快速而且可靠的一種解決方案。HAProxy特別適用於那些負載特大的web站點,這些站點一般又須要會話保持或七層處理。HAProxy運行在時下的硬件上,徹底能夠支持數以萬計的併發鏈接。而且它的運行模式使得它能夠很簡單安全的整合進您當前的架構中, 同時能夠保護你的web服務器不被暴露到網絡上。
前端
HAProxy實現了一種事件驅動、單一進程模型,此模型支持很是大的併發鏈接數。多進程或多線程模型受內存限制 、系統調度器限制以及無處不在的鎖限制,不多能處理數千併發鏈接。事件驅動模型由於在有更好的資源和時間管理的用戶端(User-Space) 實現全部這些任務,因此沒有這些問題。此模型的弊端是,在多核系統上,這些程序一般擴展性較差。這就是爲何他們必須進行優化以 使每一個CPU時間片(Cycle)作更多的工做。node
HAProxy是免費、極速且可靠的用於爲TCP和基於HTTP應用程序提供高可用、負載均衡和代理服務的解決方案,尤爲適用於高負載且須要持久鏈接或7層處理機制的web站點。
mysql
HAProxy是基於事件驅動機制的,爲默認單一進程響應多個請求的工做模式(並且官方建議也不讓改),而Nginx則是生成多個worker進程,每一個worker進程響應多個請求;在此模式下HAProxy支持很是大的併發鏈接數,而多進程或多線程模型受內存限制,系統調度器限制級鎖限制,但此模式在多核OS上,程序的擴展性較差web
HAProxy的單進程,事件驅動機制顯著下降了CPU在上下文切換上的開銷及對內存的佔用redis
HAProxy的O(1)事件檢查器容許其在高併發的鏈接中對任何鏈接的任何事件實現即時探測算法
HAProxy在任何可用的狀況下,其單緩衝(single buffering)機制能以不復制任何數據的方式完成讀寫操做,相似於內存映射,將數據單緩衝在隔模塊之間的實現共享因此不用複製任何數據,這會節約大量的CPU時鐘週期及內存帶寬;sql
HAProxy藉助於Linux 2.6 (>= 2.6.27.19)上的splice()系統調用,能夠實現零複製轉發(Zero-copy forwarding)相似於send-file,在Linux 3.5及以上的OS中還能夠實現零複製啓動(zero-starting);vim
HAProxyMRU內存分配器在固定大小的內存池中可實現即時內存分配,這可以顯著減小建立一個會話的時長;後端
HAProxy樹型存儲:側重於使用做者多年前開發的彈性二叉樹,實現了以O(log(N))(僅次於0(1)機制)的低開銷來保持計時器命令、保持運行隊列命令及管理輪詢及最少鏈接隊列;數組
HAProxy優化的HTTP首部分析:優化的首部分析功能避免了在HTTP首部分析過程當中重讀任何內存區域;
HAProxy精心地下降了昂貴的系統調用,大部分工做都在用戶空間完成,如時間讀取、緩衝聚合及文件描述符的啓用和禁用等;
HAProxy在進行client請求調度時,能夠根據請求的URL進行調度,將相同URL的請求轉發到同一臺後端RS上,這種調度方法在反向代理用戶請求到緩存server上很是適用,由於通常的數據緩存就是其根據URL進行的,這能夠大大提升緩存的命中率;而Nginx則能夠依賴url_hash實現根據URL進行調度,但Nginx自己不支持url_hash,若是須要這種調度算法,則必須安裝Nginx的hash軟件包。
所謂send-file。就是數據返回給client時原本要通過如下步驟
硬盤—>內核buf—>用戶buf—>socket相關緩衝區—>協議引擎
但send-file機制爲
硬盤—>內核buf->socket相關緩衝區—>協議引擎
能夠看到數據沒必要從內核空間複製帶用戶空間,而是直接經過端口進行傳輸,send-file機制提升了數據的傳輸的性能,纖細請看下面的鏈接
http://calmness.iteye.com/blog/378463
HAProxy還能夠從web界面進行登陸鏈接,進行對後端RS的狀態監控
能夠從如下三個因素評估負載均衡的性能
1:會話率 單位時間內完成的會話數
2:會話的併發能力 單位時間內持有的會話數
3:數據率 單位時間內實現數據交換的能力
HAProxy的配置處理3類來主要參數來源:
——最優先處理的命令行參數,
——「global」配置段,用於設定全局配置參數;
——proxy相關配置段,如「defaults」、「listen」、「frontend」和「backend」;
HAProxy有許多時間參數,如超時時長。這些值通常以毫秒爲單位,但也可使用其它的時間單位後綴。
us: 微秒(microseconds),即1/1000000秒;
ms: 毫秒(milliseconds),即1/1000秒;
s: 秒(seconds);
m: 分鐘(minutes);
h:小時(hours);
d: 天(days);
定義負載均衡算法,可用於「defaults」、「listen」和「backend」
支持的算法有:
roundrobin:基於權重進行輪叫,在服務器的處理時間保持均勻分佈時,這是最平衡、最公平的算法。此算法是動態的,這表示其權重能夠在運行時進行調整,不過,在設計上,每一個後端服務器僅能最多接受4128個鏈接;
static-rr:基於權重進行輪叫,與roundrobin相似,可是爲靜態方法,在運行時調整其服務器權重不會生效;不過,其在後端服務器鏈接數上沒有限制;
leastconn:新的鏈接請求被派發至具備最少鏈接數目的後端服務器;在有着較長時間會話的場景中推薦使用此算法,如LDAP、SQL等,其並不太適用於較短會話的應用層協議,如HTTP;此算法是動態的,能夠在運行時調整其權重;
source:將請求的源地址進行hash運算,並由後端服務器的權重總數相除後派發至某匹配的服務器;這可使得同一個客戶端IP的請求始終被派發至某特定的服務器;不過,當服務器權重總數發生變化時,如某服務器宕機或添加了新的服務器,許多客戶端的請求可能會被派發至與此前請求不一樣的服務器;經常使用於負載均衡無cookie功能的基於TCP的協議;其默認爲靜態,不過也可使用hash-type修改此特性;
uri:對URI的左半部分(「問題」標記以前的部分)或整個URI進行hash運算,並由服務器的總權重相除後派發至某匹配的服務器;這可使得對同一個URI的請求老是被派發至某特定的服務器,除非服務器的權重總數發生了變化;此算法經常使用於代理緩存或反病毒代理以提升緩存的命中率;須要注意的是,此算法僅應用於HTTP後端服務器場景;其默認爲靜態算法,不過也可使用hash-type修改此特性;
url_param:經過<argument>爲URL指定的參數在每一個HTTP GET請求中將會被檢索;若是找到了指定的參數且其經過等於號「=」被賦予了一個值,那麼此值將被執行hash運算並被服務器的總權重相除後派發至某匹配的服務器;此算法能夠經過追蹤請求中的用戶標識進而確保同一個用戶ID的請求將被送往同一個特定的服務器,除非服務器的總權重發生了變化;若是某請求中沒有出現指定的參數或其沒有有效值,則使用輪叫算法對相應請求進行調度;此算法默認爲靜態的,不過其也可使用hash-type修改此特性;
hdr(<name>):對於每一個HTTP請求,經過<name>指定的HTTP首部將會被檢索;若是相應的首部沒有出現或其沒有有效值,則使用輪叫算法對相應請求進行調度;其有一個可選選項「use_domain_only」,可在指定檢索相似Host類的首部時僅計算域名部分(好比經過www.zxl.com來講,僅計算zxl字符串的hash值)以下降hash算法的運算量;此算法默認爲靜態的,不過其也可使用hash-type修改此特性;
rdp-cookie 基於cookie的調度算法
hash-type <method>:定義用於將hash碼映射至後端服務器的方法;其不能用於frontend區段;可用方法有map-based和consistent,在大多數場景下推薦使用默認的map-based方法。
map-based:hash表是一個包含了全部在線服務器的靜態數組。其hash值將會很是平滑,會將權重考慮在列,但其爲靜態方法,對在線服務器的權重進行調整將不會生效,這意味着其不支持慢速啓動。此外,挑選服務器是根據其在數組中的位置進行的,所以,當一臺服務器宕機或添加了一臺新的服務器時,大多數鏈接將會被從新派發至一個與此前不一樣的服務器上,對於緩存服務器的工做場景來講,此方法不甚適用。
consistent:hash表是一個由各服務器填充而成的樹狀結構;基於hash鍵在hash樹中查找相應的服務器時,最近的服務器將被選中。此方法是動態的,支持在運行時修改服務器權重,所以兼容慢速啓動的特性。添加一個新的服務器時,僅會對一小部分請求產生影響,所以,尤爲適用於後端服務器爲cache的場景。不過,此算法不甚平滑,派發至各服務器的請求未必能達到理想的均衡效果,所以,可能須要不時的調整服務器的權重以得到更好的均衡性。
實驗環境
node1: eth0 192.168.139.2(可訪問公網)
eth1 192.168.10.7
node4: 192.168.10.8 網關:192.168.10.7
node5: 192.168.10.9 網關:192.168.10.7
其中在node1上裝有HAProxy,用做負載均衡調度器
node4|node5裝有httpd,用來做爲後端的RS_Server
爲了讓後端RS不暴露在外網環境下(安全考慮),本次實驗採用node4|node5的IP與node1(調度器)的eth0再也不一個網段的方法,因此先爲node1添加一個網卡,做爲node4|nde5的網關
開啓node1|node4|node5
[root@node1 ~]# ifconfig -a
eth0 Link encap:Ethernet HWaddr 00:0C:29:1C:13:12
inet addr:192.168.139.2 Bcast:192.168.139.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe1c:1312/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:6137 errors:0 dropped:0 overruns:0 frame:0
TX packets:3743 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:403125 (393.6 KiB) TX bytes:239297 (233.6 KiB)
eth1 Link encap:Ethernet HWaddr 00:0C:29:1C:13:1C
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
爲新添的網卡eth1配置IP
[root@node1 ~]# ifconfig eth1 192.168.10.7/24 up
[root@node1 ~]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:1C:13:12
inet addr:192.168.139.2 Bcast:192.168.139.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe1c:1312/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:6707 errors:0 dropped:0 overruns:0 frame:0
TX packets:4103 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:449123 (438.5 KiB) TX bytes:272859 (266.4 KiB)
eth1 Link encap:Ethernet HWaddr 00:0C:29:1C:13:1C
inet addr:192.168.10.7 Bcast:192.168.10.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe1c:131c/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:208 errors:0 dropped:0 overruns:0 frame:0
TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:13954 (13.6 KiB) TX bytes:328 (328.0 b)
配置node4|node5的網關和IP並啓動httpd
[root@node4 ~]# ifconfig eth0 192.168.10.8/24 up
[root@node4 ~]#route add default gw 192.168.139.7
[root@node4 ~]#service httpd start
[root@node5 ~]# ifconfig eth0 192.168.10.8/24 up
[root@node5 ~]# route add default gw 192.168.139.7
[root@node4 ~]#service httpd start
[root@node1 ~]# curl http://192.168.10.8
<h1>node4.zxl.com</h1>
[root@node1 ~]# curl http://192.168.10.9
<h1>node5.zxl.com</h1>
在node1上安裝HAProxy
[root@node1 ~]# yum install -y haproxy
[root@node1 ~]# cd /etc/haproxy/
[root@node1 haproxy]# cp haproxy.cfg haproxy.cfg.bak
要啓用本機的日誌功能local2要作如下配置
[root@node1 haproxy]# vim /etc/sysconfig/rsyslog
SYSLOGD_OPTIONS="-c 2 -r"
[root@node1 haproxy]# vim /etc/rsyslog.conf
local2.* /var/log/haproxy.log
[root@node1 haproxy]# service rsyslog restart
Shutting down system logger: [ OK ]
Starting system logger: [ OK ]
[root@node1 haproxy]# vim haproxy.cfg
global #全局端配置
log 127.0.0.1 local2 #啓用本機的日誌功能local2
chroot /var/lib/haproxy #chroot限制根目錄 /var/lib/haproxy 安全
pidfile /var/run/haproxy.pid #pid文件
maxconn 4000 #設定一個前端的最大併發鏈接數爲4000,所以其不能用於backend區段
user haproxy #以HAProxy用戶身份運行
group haproxy #以HAProxy組身份運行
daemon #讓haproxy以守護進程的方式工做於後臺
# turn on stats unix socket
stats socket /var/lib/haproxy/stats
defaults #爲全部其它配置段提供默認參數
mode http #設定實例的運行模式或協議,若調度mysql則爲tcp
log global #當前實例的日誌系統參數同"global"段中的定義
option httplog #啓用記錄HTTP請求、會話狀態和計時器的功能。
#默認狀況下,日誌輸入格式很是簡陋,由於其僅包括源 #地址、目標地址和實例名稱,而「option httplog」參 #數將會使得日誌格式變得豐富許多,其一般包括但不限 #於HTTP請求、鏈接計時器、會話狀態、鏈接數、捕獲的 #首部及cookie、「frontend」、「backend」及服務器 #名稱,固然也包括源地址和端口號等。
option dontlognull #不要記錄空日誌
option http-server-close
option forwardfor except 127.0.0.0/8 #除了來自本機的請求(本機自己爲DR),在發往服務器的請求首部中插入「X-Forwarded-For」首部。通Nginx的X-Real-IP,能夠記錄真實的client IP
option redispatch
retries 3 #重試次數3
timeout http-request 10s #下面則是一些關於時間的定義,通常默認就行
timeout queue 1m
timeout connect 0s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
listen stats #「listen」段經過關聯「前端」和「後端」定義了一個完整的代理,一般只對 #TCP流量有用。
mode http #值能夠爲http|tcp|health
bind 0.0.0.0:1080 #定義一個或幾個監聽的套接字,監聽在全部地址的1080端口,進行狀態監控
stats enable #啓用基於程序編譯時默認設置的統計報告(監控),不能用於「frontend」區段
stats hide-version #隱藏HAProxy的版本號(防止有人知道版本號後查到相應的系統漏洞)
stats uri /haproxyadmin?stats #根據這個URI進行監控頁面的訪問
stats realm Haproxy\ Statistics #認證時的提示信息,\爲脫義符後面有空格
stats auth admin:zxl #用戶名和密碼
stats admin if TRUE #若是認證成功則打開web監控管理界面
frontend http-in #http-in隨便給的名稱,「frontend」段用於定義一系列監聽的套接字,這些套接 #字可接受客戶端請求並與之創建鏈接。
bind *:80 #經過80端口向外提供服務(web)
mode http
log global #啓用提早將HTTP請求記入日誌,不能用於「backend」區段。
option httpclose
option logasap
option dontlognull #不要記錄空日誌
capture request header Host len 20 捕獲並記錄指定的請求首部最近一次出現時的第一個值爲HOST(主機)的請求報文的前20個字節並保留下來
capture request header Referer len 60#捕獲並記錄指定的請求首部最近一次出現時的第一個值爲Referer的請求報文的前20個字節並保留下來
default_backend servers #在沒有匹配的"use_backend"規則時爲實例指定使用的默認後 #端,所以,其不可應用於backend區段。
frontend healthcheck #定義一個健康檢查段
bind :1099 #用1099端口進行健康狀態檢查
mode http
option httpclose #爲每個請求都附加此首部「X-Forwarded-For」
option forwardfor #容許在發往服務器的請求首部中插入「X-Forwarded-For」首部。
default_backend servers
backend servers #「backend」段用於定義一系列「後端」服務器,代理將會將對應客 #戶端的請求轉發至這些服務器。
balance roundrobin #使用roundrobin調度算法
server websrv1 192.168.10.8:80 check port 80 inter 2 rise 1 fall 2 maxconn 2000
server websrv2 192.168.10.9:80 check port 80 inter 2 rise 1 fall 2 maxconn 2000
#check:啓動對此server執行健康狀態檢查,檢查端口80
#inter:設定健康狀態檢查的時間間隔,單位爲毫秒,默認爲2000;也可使用fastinter和 downinter 來根據服務器端狀態優化此時間延遲;
#rise:某離線的server從離線狀態轉換至正常狀態須要成功檢查的次數;
#fall:確認server從正常狀態轉換爲不可用狀態須要檢查的次數;
[root@node1 haproxy]# service haproxy start
Starting haproxy: [ OK ]
[root@node1 haproxy]# netstat -tnlp |grep haproxy
tcp 0 0.0.0.0:1099 0.0.0.0:* LISTEN 2007/haproxy
tcp 0 0.0.0.0:80 0.0.0.0:* LISTEN 2007/haproxy
tcp 0 0.0.0.0:1080 0.0.0.0:* LISTEN 2007/haproxy
能夠看到啓動時執行的是如下命令
[root@node1 haproxy]# ps aux |grep haproxy
haproxy /usr/sbin/haproxy -D -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid
瀏覽器測試
刷新
登陸監控web界面
登入監控界面
負載均衡MySQL服務的配置以下
[root@node1 haproxy]# vim haproxy.cfg
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
defaults
mode tcp
log global
option httplog
option dontlognull
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 600
listen stats
mode http
bind 0.0.0.0:1080
stats enable
stats hide-version
stats uri /haproxyadmin?stats
stats realm Haproxy\ Statistics
stats auth admin:admin
stats admin if TRUE
frontend mysql
bind *:3306
mode tcp #mysql爲tcp模式
log global
default_backend mysqlservers
backend mysqlservers
balance leastconn
server dbsrv1 192.168.10.8:3306 check port 3306 intval 2 rise 1 fall 2 maxconn 300
server dbsrv2 192.168.10.9:3306 check port 3306 intval 2 rise 1 fall 2 maxconn 300
本次實驗完畢!