開源負載均衡通訊分發器(LB dispatcher) - G5

caixingyun發表於2016-06-01

from:http://bbs.csdn.net/topics/390753043

1.開發背景
今天和系統運維的老大聊天,談到一直在用的F5,行裡對其評價為價格過高、功能複雜難懂,反正印象不是很好,使用前景不明。因為以前我曾經給行裡開發過一個通訊中介軟體,附帶軟實現了負載均衡,幾年使用下來一直效果不錯,突然想自己再軟實現一個純負載均衡通訊分發器,並開源分享給大家。
說幹就幹,回到家,搜了一下網上同類軟體,整理技術需求,定義設計目標如下:
* 支援長/短TCP,後續還會支援UDP
* 與應用層協議無關,即支援HTTP,FTP,TELNET,SSH等等所有應用層協議
* 穩定高效,Linux下首選epoll(ET模式),全非同步設計,也決定了目前僅支援Linux
* 基於分發規則,支援遠端、線上管理規則和查詢狀態
* 支援多種主流負載均衡演算法
* 原始碼和可執行程式體型輕巧,概念簡單,使用快捷
定義使用場景如下:
* 通訊轉發、分發
* 與無負載均衡功能的通訊軟體配合實現本地連線對端的負載均衡分發,避免改造通訊軟體帶來的工作量和風險
* 低成本的網站前端負載均衡通訊閘道器

研發之前,取個好聽的名字,相對於硬實現F5,就取名為軟實現G5吧 ^_^
經過5個晚上的奮筆疾書,搗鼓出v1.0.0,原始碼只有一個.c(2000行)和一個.h檔案(200行),編譯連結出可執行程式約60KB大小。

2.安裝部署
從http://git.oschina.net/calvinwilliams/G5下載原始碼安裝包,在你的臨時目錄解開
$ tar xvzf G5-x.x.x.tar.gz
$ cd G5-x.x.x/src
$ make -f makefile.Linux clean
$ make -f makefile.Linux install
因為只有一對原始檔,所以編譯連結很快,也便於編譯器優化,更便於你自己手工編譯。
如果不報錯的話,可執行程式G5就安裝到/usr/bin/下了。

3.基本使用
3.1.命令列引數
不帶引數執行G5會顯示版本、命令列引數說明等資訊
$ G5
G5 - tcp LB dispatcher
v1.0.0 build Apr  6 2014 15:00:31 WITH 100:1024:4096,10:3:100,64
Copyright by calvin 2014
Email : calvinwilliams.c@gmail.com

USAGE : G5 -f config_pathfilename [ -r forward_rule_maxcount ] [ -s forward_session_maxcount ] [ -b transfer_bufsize ] [ -d ]

3.1.啟動
因為是工具型軟體,所以使用者介面設計的比較簡單,自行編寫一個分發規則配置檔案
$ cat demo.conf
admin      G        192.168.1.54:* - 192.168.1.54:8060 ;
webdog     MS       192.168.1.54:* - 192.168.1.54:8070 > 192.168.1.79:8088 ;
webdog2    RR       *.*.*.*:* - 192.168.1.54:8080 > 192.168.1.79:8089 192.168.1.79:8090 192.168.1.79:8091 ;
作為G5唯一一個必須的命令列引數-f啟動
$ G5 -f demo.conf
forward_rule_maxcount    [100]
forward_session_maxcount [1024]
transfer_bufsize         [4096]bytes
epoll_create ok #3#
admin G 192.168.1.54:* - 192.168.1.54:8060(LISTEN)#5# ;
webdog MS 192.168.1.54:* - 192.168.1.54:8070(LISTEN)#7# > 192.168.1.79:8088 ;
webdog2 RR *.*.*.*:* - 192.168.1.54:8080(LISTEN)#8# > 192.168.1.79:8089 192.168.1.79:8090 192.168.1.79:8091 ;
...
之後產生的所有普通訊息、錯誤都輸出到標準輸出、錯誤輸出上,如果啟動引數加上-d,則還會輸出所有除錯資訊,如連線、斷開、資料分發

我模擬發起一個HTTP請求
$ lynx http://192.168.1.54:8080/index.php
G5的標準輸出上產生如下資訊
forward2 [192.168.1.54:43477]#3# - [192.168.1.54:8080]#7# > [192.168.1.79:8089]#8#
transfer #3# [324]bytes to #8#
transfer #8# [257]bytes to #3#
close #8# recv 0
說明一下
192.168.1.54:43477(lynx)連線192.168.1.54:8080(G5)被轉發到網站伺服器192.168.1.79:8089(apache)
lynx傳送了HTTP請求324位元組給網站伺服器
lynx從網站伺服器接收了HTTP響應257位元組
服務端首先斷開連線

一般都使用nohup使其變為守護程式,輸出導向到檔案
$ nohup G5 demo.conf >demo.log 2>&1 &

3.2.停止
別客氣,直接kill (pid)即可。

4.配置檔案
配置檔案裡一行為一條轉發規則,每條規則由三大段組成:規則名稱、規則型別和規則實體,之間用白字元(空格、TAB)隔開。
規則名稱唯一標識該規則,便於新增、修改和刪除規則。
規則型別說明該規則是線上管理(G),還是以某種通訊分發演算法。目前實現的演算法列表如下
MS : 主備模式,即一直連線第一個目標地址,如果第一個目標地址故障了,切換到下一個目標地址
RR : 輪詢模式,把所有目標地址按次序依次迴圈使用
LC : 最少連線數模式,在目標地址集合中挑選當前最少連線的目標
RT : 最小響應時間模式,在目標地址集合中挑選歷史資料交換最快的目標
RD : 隨機模式,隨機選擇目標地址
HS : HASH模式,根據來源地址計算HASH得到一個唯一固定的目標地址
規則實體格式為"來源地址集合 - 本地轉發地址集合 > 目標地址集合 ;",其中三個地址集合內可以包含一個地址或白字元隔開的地址列表。單個地址由"IP:PORT"組成。來源單個地址中的IP和PORT可以使用'*'和'?'通配。當只有一個目標地址時,通訊分發演算法就沒有意義了。

回來解釋一下前面展示的配置檔案
$ cat demo.conf
# 只允許本機192.168.1.54連線到G5線上管理規則
admin      G        192.168.1.54:* - 192.168.1.54:8060 ;
# 本地所有TCP連線到本機8070埠時統統轉發到192.168.1.79:8088
# 用於跨網段的通訊轉發
webdog     MS       192.168.1.54:* - 192.168.1.54:8070 > 192.168.1.79:8088 ;
# 允許所有主機連線192.168.1.79:8089,並以輪詢演算法分發給三個伺服器192.168.1.79:8089 192.168.1.79:8090 192.168.1.79:8091
# 用於網站前端負載均衡通訊節點
webdog2    RR       *.*.*.*:* - 192.168.1.54:8080 > 192.168.1.79:8089 192.168.1.79:8090 192.168.1.79:8091 ;
還簡單吧

5.線上管理
G5在啟動時必須指定一個配置檔案裝載所有規則並以之工作,也支援遠端連線上管理埠線上管理規則,用telnet即可
$ telnet 192.168.1.54 8060
Trying 192.168.1.54...
Connected to rhel54 (192.168.1.54).
Escape character is '^]'.
>
'>'為輸入提示符,後面可以鍵入的命令有
ver : 顯示G5版本及編譯日期時間
quit : 斷開管理連線
list rules : 顯示當前所有轉發規則
add rule (...規則...) : 新增轉發規則
modify rule (...規則...) : 修改轉發規則
remove rule (規則名稱) : 刪除轉發規則
dump rule : 儲存所有轉發規則到啟動時指定的配置檔案中
list forwards : 顯示當前所有轉發連線資訊

使用示例
$ telnet 192.168.1.54 8060
Trying 192.168.1.54...
Connected to rhel54 (192.168.1.54).
Escape character is '^]'.
> ver
version v1.0.0 build Apr  3 2014 08:05:54
> list rules
    1 : admin G 192.168.1.54:* - 192.168.1.54:8060 ;
    2 : webdog MS 192.168.1.54:* - 192.168.1.54:8070 > 192.168.1.79:8088 ;
    3 : webdog2 RR *.*.*.*:* - 192.168.1.54:8080 > 192.168.1.79:8089 192.168.1.79:8090 192.168.1.79:8091 ;
> add rule webdog3 MS 192.168.1.54:* - 192.168.1.54:8070 > 192.168.1.79:8088 ;
add forward rule ok
> modify rule webdog3 HS 192.168.1.54:* - 192.168.1.54:8070 > 192.168.1.79:8088 ;
modify forward rule ok
> remove rule webdog3
remove forward rule ok
> dump rules
dump all forward rules ok
> list forwards
    1 : LISTEN [192.168.1.54:8060]#5#
    2 : LISTEN [192.168.1.54:8060]#6#
    3 : LISTEN [192.168.1.54:8070]#7#
    4 : LISTEN [192.168.1.54:8080]#8#
    5 : CLIENT [192.168.1.54:54162]#4# - MANAGE [192.168.1.54:8060]#5#
 2138 : CLIENT [192.168.1.54:39869]#11# < LISTEN [192.168.1.54:8080]#8# - SERVER [192.168.1.79:8090]#12# connected
 2139 : CLIENT [192.168.1.54:39869]#11# - LISTEN [192.168.1.54:8080]#8# > SERVER [192.168.1.79:8090]#12# connected
 2140 : CLIENT [192.168.1.54:39871]#27# < LISTEN [192.168.1.54:8080]#8# - SERVER [192.168.1.79:8091]#28# connected
 2141 : CLIENT [192.168.1.54:39871]#27# - LISTEN [192.168.1.54:8080]#8# > SERVER [192.168.1.79:8091]#28# connected
 2142 : CLIENT [192.168.1.54:39873]#17# < LISTEN [192.168.1.54:8080]#8# - SERVER [192.168.1.79:8089]#18# connected
 2143 : CLIENT [192.168.1.54:39875]#25# < LISTEN [192.168.1.54:8080]#8# - SERVER [192.168.1.79:8090]#26# connected
 2144 : CLIENT [192.168.1.54:39875]#25# - LISTEN [192.168.1.54:8080]#8# > SERVER [192.168.1.79:8090]#26# connected
 2145 : CLIENT [192.168.1.54:39873]#17# - LISTEN [192.168.1.54:8080]#8# > SERVER [192.168.1.79:8089]#18# connected
 2146 : CLIENT [192.168.1.54:39877]#21# < LISTEN [192.168.1.54:8080]#8# - SERVER [192.168.1.79:8091]#22# connected
 2147 : CLIENT [192.168.1.54:39877]#21# - LISTEN [192.168.1.54:8080]#8# > SERVER [192.168.1.79:8091]#22# connected
 2148 : CLIENT [192.168.1.54:39879]#9# < LISTEN [192.168.1.54:8080]#8# - SERVER [192.168.1.79:8089]#10# connected
 2149 : CLIENT [192.168.1.54:39879]#9# - LISTEN [192.168.1.54:8080]#8# > SERVER [192.168.1.79:8089]#10# connected
 2150 : CLIENT [192.168.1.54:39881]#15# < LISTEN [192.168.1.54:8080]#8# - SERVER [192.168.1.79:8090]#16# connected
 2151 : CLIENT [192.168.1.54:39881]#15# - LISTEN [192.168.1.54:8080]#8# > SERVER [192.168.1.79:8090]#16# connected
 2152 : CLIENT [192.168.1.54:39883]#19# < LISTEN [192.168.1.54:8080]#8# - SERVER [192.168.1.79:8091]#20# connected
 2153 : CLIENT [192.168.1.54:39884]#23# < LISTEN [192.168.1.54:8080]#8# - SERVER [192.168.1.79:8089]#24# connected
 2154 : CLIENT [192.168.1.54:39884]#23# - LISTEN [192.168.1.54:8080]#8# > SERVER [192.168.1.79:8089]#24# connected
 2155 : CLIENT [192.168.1.54:39883]#19# - LISTEN [192.168.1.54:8080]#8# > SERVER [192.168.1.79:8091]#20# connected
 2156 : CLIENT [192.168.1.54:39887]#13# < LISTEN [192.168.1.54:8080]#8# - SERVER [192.168.1.79:8090]#14# connected
 2157 : CLIENT [192.168.1.54:39887]#13# - LISTEN [192.168.1.54:8080]#8# > SERVER [192.168.1.79:8090]#14# connected
> quit
Connection closed by foreign host.
$


6.效能測試
因為是簡單的通訊轉發、分發器,內部使用epoll(ET)+全非同步實現,達到高併發和充分負載均衡,幾乎可以榨乾單核硬體資源。
由於我沒有完整靠譜的壓測環境,只能在我的老爺機上做直連和通過G5轉連的效能比較差異。

壓測硬體(2007年買的老爺機)
CPU  : Intel Dual E2160 1.8GHz 1.81GHz
記憶體 : 2GB
硬碟 : 希捷 250GB 7200轉
壓測軟體
Windows XP SP3 ( VMware 6.0 ( RedHat Enterprise Linux 5.4 分了256MB記憶體 ) )
壓測場景
ab直連apache 和 ab通過G5轉發給apache
併發數100,總請求數10000次

首先是192.168.1.54:*(apache ab)直連192.168.1.79:8090(apache 2.2.13 for win32),

Server Software:        Apache/2.2.13
Server Hostname:        192.168.1.79
Server Port:            8090

Document Path:          /index.html
Document Length:        44 bytes

Concurrency Level:      100
Time taken for tests:   12.503706 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      3160000 bytes
HTML transferred:       440000 bytes
Requests per second:    799.76 [#/sec] (mean)
Time per request:       125.037 [ms] (mean)
Time per request:       1.250 [ms] (mean, across all concurrent requests)
Transfer rate:          246.73 [Kbytes/sec] received

Connection Times (ms)
             min  mean[+/-sd] median   max
Connect:        0    0   4.4      0      86
Processing:    11  123  31.7    113     283
Waiting:        8  122  31.6    112     281
Total:         28  123  31.9    113     284

Percentage of the requests served within a certain time (ms)
 50%    113
 66%    115
 75%    117
 80%    120
 90%    163
 95%    187
 98%    249
 99%    256
100%    284 (longest request)

然後是192.168.1.54:*(apache ab)發往192.168.1.54:8080(G5)(主備模式MS)分發給192.168.1.79:8089,8090,8091(apache 2.2.13 for win32),

Server Software:        Apache/2.2.13
Server Hostname:        192.168.1.54
Server Port:            8080

Document Path:          /index.html
Document Length:        44 bytes

Concurrency Level:      100
Time taken for tests:   14.235889 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      3160000 bytes
HTML transferred:       440000 bytes
Requests per second:    702.45 [#/sec] (mean)
Time per request:       142.359 [ms] (mean)
Time per request:       1.424 [ms] (mean, across all concurrent requests)
Transfer rate:          216.71 [Kbytes/sec] received

Connection Times (ms)
             min  mean[+/-sd] median   max
Connect:        0    0   8.3      0     154
Processing:    25  140  31.3    132     335
Waiting:       22  139  31.2    131     334
Total:         70  140  32.3    132     338

Percentage of the requests served within a certain time (ms)
 50%    132
 66%    134
 75%    137
 80%    140
 90%    175
 95%    190
 98%    275
 99%    295
100%    338 (longest request)

然後是192.168.1.54:*(apache ab)發往192.168.1.54:8080(G5)(輪詢模式RR)分發給192.168.1.79:8089,8090,8091(apache 2.2.13 for win32),

Server Software:        Apache/2.2.13
Server Hostname:        192.168.1.54
Server Port:            8080

Document Path:          /index.html
Document Length:        44 bytes

Concurrency Level:      100
Time taken for tests:   14.15712 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      3160316 bytes
HTML transferred:       440044 bytes
Requests per second:    713.48 [#/sec] (mean)
Time per request:       140.157 [ms] (mean)
Time per request:       1.402 [ms] (mean, across all concurrent requests)
Transfer rate:          220.18 [Kbytes/sec] received

Connection Times (ms)
             min  mean[+/-sd] median   max
Connect:        0    0   7.5      0     140
Processing:    26  137  67.8     91     342
Waiting:       25  137  67.8     90     340
Total:         49  138  68.1     91     347

Percentage of the requests served within a certain time (ms)
 50%     91
 66%    178
 75%    219
 80%    222
 90%    229
 95%    259
 98%    273
 99%    279
100%    347 (longest request)

然後是192.168.1.54:*(apache ab)發往192.168.1.54:8080(G5)(最小響應時間模式RT)分發給192.168.1.79:8089,8090,8091(apache 2.2.13 for win32),

Server Software:        Apache/2.2.13
Server Hostname:        192.168.1.54
Server Port:            8080

Document Path:          /index.html
Document Length:        44 bytes

Concurrency Level:      100
Time taken for tests:   14.260485 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      3160000 bytes
HTML transferred:       440000 bytes
Requests per second:    701.24 [#/sec] (mean)
Time per request:       142.605 [ms] (mean)
Time per request:       1.426 [ms] (mean, across all concurrent requests)
Transfer rate:          216.33 [Kbytes/sec] received

Connection Times (ms)
             min  mean[+/-sd] median   max
Connect:        0    0   7.7      0     148
Processing:    29  140  27.3    133     346
Waiting:       26  139  27.2    132     346
Total:         65  141  28.4    133     346

Percentage of the requests served within a certain time (ms)
 50%    133
 66%    136
 75%    138
 80%    140
 90%    181
 95%    190
 98%    241
 99%    287
100%    346 (longest request)

然後是192.168.1.54:*(apache ab)發往192.168.1.54:8080(G5)(隨機模式RD)分發給192.168.1.79:8089,8090,8091(apache 2.2.13 for win32),

Server Software:        Apache/2.2.13
Server Hostname:        192.168.1.54
Server Port:            8080

Document Path:          /index.html
Document Length:        44 bytes

Concurrency Level:      100
Time taken for tests:   14.114779 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      3160632 bytes
HTML transferred:       440088 bytes
Requests per second:    708.48 [#/sec] (mean)
Time per request:       141.148 [ms] (mean)
Time per request:       1.411 [ms] (mean, across all concurrent requests)
Transfer rate:          218.64 [Kbytes/sec] received

Connection Times (ms)
             min  mean[+/-sd] median   max
Connect:        0    0   7.3      0     139
Processing:    22  138  67.3     92     354
Waiting:       21  138  67.3     92     353
Total:         48  139  67.6     92     356

Percentage of the requests served within a certain time (ms)
 50%     92
 66%    184
 75%    212
 80%    221
 90%    239
 95%    255
 98%    279
 99%    292
100%    356 (longest request)

可以看出,轉發的總耗時比直連多了10%左右,大體還是可以接受的,如果G5和WebServer分開部署在不同機器裡,G5就能發揮出負載均衡的優勢,效能也會大幅提升。
以後若有更好的環境,我將會做更全面更深入的壓測。

7.待開發內容
* 轉發時,如果接收速度比傳送快,暫禁接收sock的EPOLLIN,啟用傳送sock的EPOLLOUT非同步等待準備好再傳送
* 最大連線數控制
* 連線超時控制

8.最後
作為一個通訊分發(負載均衡)網路工具,G5基本實現設計目標,併發布第一版出來分享給開源世界,歡迎試用。
G5原始碼作為epoll(ET)+全非同步綜合使用示例也供大家學習參考,歡迎批評指正。
如有問題或建議請及時聯絡我,讓我們共同把她搞大!
開源專案首頁 : http://git.oschina.net/calvinwilliams/G5

相關文章