HAproxy 技術分享
簡介
HAProxy是一款提供高可用性、負載均衡以及基於TCP(第四層)和HTTP(第七層)應用的代理軟件
Features
1.免費
2.能夠做到4層以上代理
3.高性能
4.高穩定性
使用案例
淘寶CDN(HTTP反向代理)
測試:
HTTP代理 ab -i -c 500 -n 100000
| --- node 8910 URL = /
HAproxy| --- node 8911 URL = /
| --- node 8912 URL = /
| --- node 8913 /test/ (reqisetbe ^[^\ ]*\ /(test|uri)/ server_uri_route) #按照規則轉發
####### haproxy : (單獨由haproxy進行均衡負載)
Concurrency Level: 500
Time taken for tests: 32.562 seconds
Complete requests: 100000
Failed requests: 0
Write errors: 0
Total transferred: 36606588 bytes
HTML transferred: 0 bytes
Requests per second: 3071.02 [#/sec] (mean)
Time per request: 162.812 [ms] (mean)
Time per request: 0.326 [ms] (mean, across all concurrent requests)
Transfer rate: 1097.85 [Kbytes/sec] received
####### nginx : (單獨由nginx進行均衡負載)
Concurrency Level: 500
Time taken for tests: 36.539 seconds
Complete requests: 100000
Failed requests: 0
Write errors: 0
Total transferred: 38600000 bytes
HTML transferred: 0 bytes
Requests per second: 2736.82 [#/sec] (mean)
Time per request: 182.694 [ms] (mean)
Time per request: 0.365 [ms] (mean, across all concurrent requests)
Transfer rate: 1031.65 [Kbytes/sec] received
對比Nginx
Name | Nginx | HAproxy |
---|---|---|
HTTP代理性能 | 9 | 10 |
TCP 代理性能 | 0 | 10 |
穩定性 | 10 | 10 |
轉發規則 | 10 | 7 |
HTTP代理性能 | 9 | 10 |
平滑升級 | 10 | 8 |
原理 epoll 轉發
驗證 轉發方式為如下
通過TCP代理請求 www.baidu.com
client HAProxy Backend
curl |----------------->|
accept(client)
recvfrom(client)
sendto(Backent)
|-------->|
dowith(HAProxy)
|<--------|
recvfrom(Backend)
sendto(Client)
|<-----------------|
strace 查看系統調用
zhangbo3@vm-222:/etc/haproxy$ sudo strace -p 7876
epoll_wait(0, {{EPOLLIN, {u32=5, u64=5}}}, 7, 1000) = 1
*** (事件循環,監聽連接事件)
accept(5, {
sa_family=AF_INET,
sin_port=htons(56479),
sin_addr=inet_addr("127.0.0.1")
}, [16]) = 1
*** (來自客戶端[127.0.0.1]的請求, 端口56479[隨機端口])
fcntl(1, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
*** (設置連接socket為非阻塞)
setsockopt(1, SOL_TCP, TCP_NODELAY, [1], 4) = 0
*** (設置TCP連接為 NODELAY, 禁止Nagle算法)
accept(5, 0x7fff8da2d7a0, [128]) = -1 EAGAIN
(Resource temporarily unavailable)
*** (再次去accept連接失敗,因為accept被循環包裹,需要返回 EAGAIN才break)
recvfrom(1, "GET HTTP://www.baidu.com HTTP/1."..., 8192) = 212
*** (收到來自客戶端的請求 curl -x 127.0.0.1:1180 www.baidu.com)
recvfrom(1, 0x2560ac4, 7980, 0, 0, 0) = -1 EAGAIN
(Resource temporarily unavailable)
*** (返回EAGAIN后break,表示收到完整的TCP數據, 開始處理請求數據)
epoll_ctl(0, EPOLL_CTL_ADD, 1, {EPOLLIN, {u32=1, u64=1}}) = 0
*** (將來自客戶端的socket加入epoll監聽隊列)
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 2
fcntl(2, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
setsockopt(2, SOL_TCP, TCP_NODELAY, [1], 4) = 0
connect(2, {
sa_family=AF_INET,
sin_port=htons(8912),
sin_addr=inet_addr("127.0.0.1")
}, 16) = -1 EINPROGRESS (Operation now in progress)
*** (創建到backend的socket連接,這里backend配置為8912)
*** (server server3 127.0.0.1:8912)
sendto(2, "GET HTTP://www.baidu.com HTTP/1."...,
212, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 212
*** (發送數據到backend)
epoll_wait(0, {}, 7, 0) = 0
*** (繼續進入epoll_wait,等待來自backend的數據返回)
gettimeofday({1413020002, 322710}, NULL) = 0
recvfrom(2, 0x255c960, 16384, 0, 0, 0) = -1 EAGAIN
(Resource temporarily unavailable)
*** (Backend數據來了)
epoll_ctl(0, EPOLL_CTL_ADD, 2, {EPOLLIN, {u32=2, u64=2}}) = 0
epoll_wait(0, {{EPOLLIN, {u32=2, u64=2}}}, 7, 1000) = 1
gettimeofday({1413020003, 308930}, NULL) = 0
recvfrom(2, "HTTP/1.1 200 OK\r\nDate: Sat, 11 O"...,16384) = 2896
*** (backend 返回 HTTP 200, 這是標准HTTP協議頭)
recvfrom(2, 0x255d4b0, 13488, 0, 0, 0) = -1 EAGAIN
(Resource temporarily unavailable)
sendto(1, "HTTP/1.1 200 OK\r\nDate: Sat, 11 O"...) = 2896
*** (將backend返回的數據發送到front end)
epoll_wait(0, {{EPOLLIN, {u32=2, u64=2}}}, 7, 1000) = 1
*** (繼續進入epoll_wait)
gettimeofday({1413020003, 309695}, NULL) = 0
*** (客戶端連接超時,關閉連接)
shutdown(2, 1 /* send */) = 0
close(2) = 0
shutdown(1, 1 /* send */) = 0
close(1) = 0
驗證單進程模型 -> 查看線程數
cat /proc/7878/status
Name: haproxy
State: S (sleeping)
...
Threads: 1
SigQ: 0/15594
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
...