Rails如果運用在正式上線的服務,便是相當需要配置為Cluster(叢集)服務。不過大部分使用Rails來建立Cluster通常都是藉著Apache mod_proxy,但在一些情況之下,他只有好設定的優點而已。另一種方式是利用一些Plugin及設定去模擬Cluster的行為,不過這樣便是消耗CPU的時間。
網路上可以看見許多Cluster的文章,但多半都是介紹單方面的功能,或是許多實做的細節牽扯在一起。這篇文章用商業服務的整體規劃來看Cluster及Rails之間的種種問題與解決方法。文章後面附帶了一節是要解釋如何解讀apache menchmark的數據。而各位如果想要瞭解的是效能,數據上的差異,已經有一篇相當棒的可以參考:
http://blog.kovyrin.net/2006/08/28/ruby-performance-results/
Cluster(叢集)Cluster中文翻譯為叢集,意指利用
多台電腦完成同一工作來達到一般單台電腦不可能負擔的運算量或是穩定度。Cluster基本上分做兩種,一個是純粹作為計算的Computing Cluster目的是進行平行運算。一個是用來提供各種Internet服務的Application Cluster。其中Application Cluster有兩種實做方式,Failover 方式,又可以稱做HA(High Availability),主要目的是提供
不會中斷的服務,而另一個Load Balance方式,就是要提供
承受高度負載的服務。一般人難以理解的部分,就是會將承受高負載與不會中斷這兩件事弄混,其實這兩項工作並非有直接相關,管理者可是硬體成本考量是否都要做。
既然是Application Cluster,對於Internet上最主要的服務如HTTP,FTP,Mail等,便有相當成熟的軟體的解決方案。 這些解決方案通常是透過Windows
Server或是Unix Server來實做,而在這邊我要推薦Linux。Linux的多工排程效率較Windows好,在高負載的時候核心不會因為過於忙碌而呈現容易當機等不穩定狀態,而Linux本來在很早期就有比Windows更完善的開放原碼專案來解決這些問題,其中最著名的套件就是Linux-HA。
硬體的解決方案也不是沒有,稱做Layer 4 Switch,雖然有較親切的UI讓管理員快速設定,不過價格也昂貴許多。
一般來說HTTP Cluster的架構大概會如下圖,而這裡更加上DB的部分,來說明商業服務是怎樣運作的。在這裡特別標出一個紅色箭頭表示為Failover的架構,當然DB的部分也是可以,不過也是比較複雜所以日後再談。這樣的切割,也會影響到硬體的需求。基本上來說跑Web的東西,不管是用什麼Server的軟硬體,就是吃CPU(關連到一次request的速度)與記憶體(關連到最大負載人數)。而對資料庫而言,CPU就不見得,記憶體的要求會遠比跑Web來得高。我會建議一般的Web Server為一般幾萬塊的PC即可,使用好一點的CPU,記憶體為2G。但資料庫就不能草率,盡量購買高級的伺服器,並具有RAID5或6的硬碟儲存,及4G以上的記憶體。
在這個例子裡面,我們可以看見由四台Real Web Server及三台Real DB Server所組成的Web及DB Cluster。而Virtual Server本身不具備任何的服務資料(如程式碼或圖片...等),只有一個能力就是將連線重新導向到Real Server,而導向的方式有相當多種,之後會討論。這樣子利用重新導向來將服務負載分散給Real Server的方式就稱做Load Balance。
此外可以注意到 Virtual Server 2,除了上述的功能之外,就是可以偵測Virtual Server 1當機或是無法服務的時候,自動將自己的IP位置取代Virtual Server 1。這樣子的方式就稱做Failover。
IP配置的方式IP是一個很大的問題,由現今商業服務的環境看來,沒有實體IP根本無法進行任何服務。傳統的作法有三種,NAT,Direct Routing,Tunneling。
IP配置方式 | NAT | Direct Routing | Tunneling |
伺服器網路功能支援 | 有NAT功能即可 | 需支援arp ignore | 需支援ip tunneling(設定上較arp ignore複雜) |
IP種類 | public/private皆可(private ip 就是常說的虛擬IP) | 一定要public | 一定要public |
IP數量 | 適合少量(100以下) | 可以大量 | 可以大量 |
Virtual Server負載 | 高 | 低 | 低 |
整體分析起來商業服務比較適合使用Direct Routing,但缺點也是有多少Real Server就需要多少實體IP。如果只是單純一兩個Real Server,又不太容易弄到很多實體IP,或許較適合NAT。
本篇文章強調商業服務,所以我會使用DR(direct routing)做為例子。
實做一個簡單的Load Balance環境接下來的章節,要用一個簡單的實例跟大家說明如何安裝軟體,而這不是文章後面測試所使用的環境。
假設有這些機器,如下:
D1(Director Server 1): P4 2.0G, 768M RAM, 10.1.1.60
R1(Real Server 1): P4 2.0G, 768M RAM, 10.1.1.61
R2(Real Server 2): P4 2.0G, 768M RAM, 10.1.1.62
OS:Fedora 6
Director Server就是要用來做Load Balance的機器,目的也是為了剛剛所說進行連線重新導向。
1. Bind 9實做RRDNS
2. Linux Virtual Server(ldirectord+ipvsadm)
3. Apache mod_proxy
4. HAProxy
Bind是一套相當著名的DNS服務軟體,我想Internet上九成都是使用這個來當作DNS服務,他有一個功能就是可以利用輪替(Round Robin)的方式來讓查詢者找到不同的IP,藉此將連線導向不同的機器。你可以試著下nslookup
www.google.com指令,會注意到每次回來的3個IP順序是不太一樣的,而OS會自動以第一個IP作為你這次連線的對象。其實在這裡拿RRDNS來比有點不太適合,因為他並不是針對封包來進行負載平衡,而只是單純切換IP而已。不過這個方式確實是早期進行負載平衡的方式,就連現在都還可以在各處看見。
Linux Virtual Server計畫實行已經相當久遠,目的就是利用ipvsadm這一個以IP為主的負載平衡程式來達到讓所有使用TCP/IP的通訊協定都可以進行負載平衡。由於他是由Linux Kernel所支援,效率相當好,佔用CPU資源相當的低。不過因為ipvsadm並無法針對任何layer 4以上的封包資料進行分析,並不像接下來談到的proxy一樣具有先分析HTTP再傳送的能力,如果將這個功能都寫進去,那要做在Kernel裡就不太可能了。再者ipvsadm要手動設定也是一件難事,所以靠著ldirectord可以進行較簡單的設定。
Apache也是眾所皆知的HTTP Server,自2.0版開始對Proxy的功能大幅度地支援,儘管沒有Squid功能強大,卻整合了Apache,讓他可以進行一些意想不到的作法如Reverse Proxy。以往Proxy都是單向地,從Server到Client,而Reverse Proxy是反過來,可以處理Client HTTP Post到Server的資料。也因此加上一些改善,雙向的Proxy可以完全變成HTTP負載平衡軟體。使用Apache執行其實是有一點浪費效能的,另一個HAProxy就是純粹做負載平衡的,而本身也有簡單的快取能力。
這四種方法其實區別只在於,萬一有任何Real Server掛掉的時候,正要連線的那個人是否會斷線,換句話說就是Director是否有辦法偵測到連線對向是否斷線。結論是mod_proxy與haproxy都可以偵測到,除非機器全部掛掉,或是director自己死掉,不然使用者完全不會感受到任何的中斷。而RRDNS就完全沒有辦法,ipvsadm也是至少會有一次連線會中斷。其實這個結論也是合理的,相對的代價就是使用Proxy方式消耗的CPU會較高。
Director | CPU使用 | 封包轉送效率 | 是否會偵測連線 | 是否會遭遇斷線 |
RRDNS | 低 | 最高(直接連線) | 否 | 是 |
ipvsadm | 最低 | 高 | 是 | 是 |
mod_proxy | 高 | 低 | 是 | 否 |
haproxy | 中 | 中 | 是 | 否 |
安裝Bind 9與RRDNSBind的安裝已經有很好的文章,請參考
http://turtle.ee.ncku.edu.tw/~tung/dns/bind_conf.html
在FC6上只要yum install bind就可以安裝。
要進行的設定很簡單,首先先修改named.conf,在options區塊裡面加入一行
PLAIN TEXT
BASH:
- rrset-order {order cyclic;};
接著修改你的正查設定檔(如果你的domain是test.com就應該是test.com.hosts)。根據本例子,我改成:
PLAIN TEXT
BASH:
www IN A 10.1.1.61
- IN A 10.1.1.62
請注意測試機器的DNS Server當然就要設定成D1了,一旦使用nslookup成功地查到兩個會變動的IP,那接著測試的時候URL就可以使用
http://www.test.com。
安裝ipvsadm及ldirectord參考文章:
http://zh.linuxvirtualserver.org/files/lvs.pdf
http://zh.linuxvirtualserver.org/node/272
基本上安裝了ipvsadm後就可以下指令手動進行負載平衡,而ldirectord只是有比較好看的設定檔。
D1機器:
PLAIN TEXT
BASH:
yum install ipvsadm
#清除
ipvsadm -C
#建立Virtual Server IP 及使用演算法
ipvsadm -A -t 10.1.1.60:80 -s rr
#串接兩個Real Server IP
ipvsadm -a -t 10.1.1.60:80 -r 10.1.1.61:80 -g
- ipvsadm -a -t 10.1.1.60:80 -r 10.1.1.62:80 -g
接著在R1及R2上,你要設定好一個lo(loopback)的alias並且將IP設定為10.1.1.60,你可以建立/etc/sysconfig/network-scripts/ifcfg-lo:0或是使用xwindow的網路設定來編輯。
R1及R2機器:
PLAIN TEXT
BASH:
加入
PLAIN TEXT
BASH:
net.ipv4.ip_forward = 1
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
- net.ipv4.conf.all.arp_announce = 2
接著
PLAIN TEXT
BASH:
sysctl -p
- vi /etc/sysconfig/network-scripts/ifcfg-lo:0
內容為
PLAIN TEXT
BASH:
DEVICE=lo:0
IPADDR=10.1.1.60
NETMASK=255.255.255.255
- ONBOOT=yes
最後
service network restart
由於request封包是透過ipvsadm轉送過來,real server必須做一件事情就是不要更動封包裡的mac address,而將這個mac address當作response的mac address而送回去,如此client收到的資料才會正常。
安裝apache+mod_proxymod_proxy在2.0版後就是預設模組,而FC6上也算是內建的套件。如果你還沒安裝的話,就yum install httpd。
編輯/etc/httpd/conf/httpd.conf
加入
PLAIN TEXT
BASH:
BalancerMember http://10.1.1.61:3000
- <proxy>BalancerMember http://10.1.1.62:3000</proxy>
重新啟動之後就可以試試看了,不過要注意這樣的設定就是全部交由後端處理,事實上還可以加一些設定讓apache處理靜態資料的時候直接回傳節省時間。
安裝 haproxy到了這個小節,你會發現工作越來越簡單,就請各位參考
http://lightyror.wordpress.com/2007/06/04/%e5%9c%a8-centos-%e5%ae%89%e8%a3%9d-ruby-on-rails/
雖然透過rubyworks他會啟動一些不見得是使用者需要的服務監控程式,不過就請各位自行killall吧。
編輯/etc/haproxy.haproxy.conf
global及default區段都不用動,而注意到listen區段,語法是listen {appname} {ip:port}
修改成
PLAIN TEXT
BASH:
listen appli1-rewrite 0.0.0.0:80
stats enable
cookie SERVERID rewrite
balance roundrobin
server app1_1 10.1.1.61:3000 cookie app1inst1 check inter 2000 rise 2 fall 5
- server app1_2 10.1.1.62:3000 cookie app1inst2 check inter 2000 rise 2 fall 5
之後service haproxy start即可
AB(Apache Benchmark)數據解讀ab指令的語法是 ab -c {同時進行的request數量} -t {時間} {url} 或是 ab -c {同時進行的request數量} -n {次數} {url}
ab的測試方式有兩種:
1. -t {秒數}
2. -n {request次數}
兩種方式都可以取得可以觀察的數據,不過如果-n太少的話,就沒有意義。我通常都是使用-t 30或是-t 60。而這樣的測試有另一個好處是,在測試的其中,可以找真的人在一定時間內去實際點點看你的程式,如果時間都過去了(先別跟他講已經跑完了),他還是覺得速度沒有差,那表示效能有到使用者能夠接受的感受。而需要效能數據,其實也是為了使用經驗法則推算出應用程式最多可以容納幾個使用者註冊。
以下舉個一個例子來解讀:
[root@dsa1 ~]# ab -c 20 -t 30
http://some.machine.com/test/
#這裡是版權宣告This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0Copyright 1996 Adam Twiss, Zeus Technology Ltd,
http://www.zeustech.net/Copyright 2006 The Apache Software Foundation,
http://www.apache.org/Benchmarking xxx (be patient)
#這裡會將完成的req次數顯示出來,如果每超過5000會再次顯示Finished 1028 requests
#主機資訊Server Software: Apache/2.2.3Server Hostname: xxxServer Port: 80Document Path: /test/
#要注意,如果傳輸的資料大小超過1MB,表示使用ADSL的人多少會因為資料量感受到緩慢#,就可能不會是準確的測試結果Document Length: 8943 bytes
#這裡表示你下了 -c 20Concurrency Level: 20
#總測試時間,應該不會跟-t的時間差太遠Time taken for tests: 30.27095 secondsComplete requests: 1028
#這裡的Fail表示在TCP階段就連線失敗,如果fail太多次,出來的數據絕對不正確Failed requests: 0Write errors: 0Total transferred: 9478392 bytesHTML transferred: 9197475 bytes
#每秒鐘的Request次數,可以視為效能的指標。因為這次測試我們使用了-c 20
#表示在20個人同時連線的情況下,還可以保持每秒34個request。Requests per second: 34.24 [#/sec] (mean)
#表示這20個人裡「平均」每個人感受到的回應時間(不包括瀏覽器顯示出來的時間)
#約是584ms,也就是0.58秒。Time per request: 584.185 [ms] (mean)Time per request: 29.209 [ms] (mean, across all concurrent requests)Transfer rate: 308.25 [Kbytes/sec] receivedConnection Times (ms) min mean[+/-sd] median maxConnect: 0 49 382.7 0 3000Processing: 91 519 1287.7 262 20913Waiting: 90 518 1287.7 260 20912Total: 91 569 1542.9 262 21543
#這個曲線圖比較重要,算是ab的數據價值所在。這裡表示了這20個人所感受到的#回應速度曲線,可以從0.2秒到21秒不等。也就是說,在這裡約有20*90%=18人,
#他們感受到的速度會低於1秒,而其他人會高於1秒。這個比平均數值還要更能表達#使用者大多都是感受到什麼速度,因為在伺服器很忙碌的情況下,會有像21秒這種#數值,這是會大大地拖累平均速度及每秒request數。Percentage of the requests served within a certain time (ms) 50% 262 66% 327 75% 397 80% 449 90% 730 95% 1338 98% 5224 99% 8504 100% 21543 (longest request)曲線圖繪製出來是這樣:
結論其實這篇文章寫的滿混亂的,好幾件事情堆在一起講,而無法把每件事情講的比較詳細。不管如何要建議商業用的服務是個大工程,並不是三言兩語可以講的清楚。而我本身的經驗,使用apache真的不管在啥角度來看都是最棒的web server,但是從來也沒有人說他是最棒的director。因此好的管理者心裡總是會構思許多不同的解決方案,而更要瞭解許多方案背後架構,原理,穩定度,效能等問題,而不管哪個是否難做。但讓我覺得可惜的是,網路上大部分文章會誤導比較沒有經驗的管理者,設定簡單或是好裝不見得就是好東西。
儘管我無法一一解釋我曾經測試過了什麼,而直到現在我的綜合感受還是認為haproxy+apache+fastcgi來跑rails是最穩定且效能良好的選擇,但也是設定上稍微繁雜的。
原文引用:
http://kiwi.csie.chu.edu.tw/blog/archives/138