在具體的分析程序源代碼之前,我準(zhǔn)備先看一下Haproxy的doc目錄下的architecture.txt文件。
作者在此文件中說,由于涉及到解釋性的腳本語言,一個(gè)網(wǎng)絡(luò)應(yīng)用程序的前端服務(wù)器SERVER往往都會(huì)承受非常大的壓力;當(dāng)然這也可能依賴于相對壓力不是很大的后端的數(shù)據(jù)庫服務(wù)器DB。(對于后者,我的理解是當(dāng)DB慢一點(diǎn)的話,SERVER對于請求的響應(yīng)就沒那么快,新的請求又來到,又要分配新的資源,造成累積,自然也就會(huì)使SERVER的壓力變大。)
對于網(wǎng)絡(luò)服務(wù)器來說,用戶的上下文也是存儲(chǔ)在SERVER中,而不是存儲(chǔ)在DB中,因此如果為了解決上述問題而通過簡單的IP/TCP負(fù)載均衡來增加另一個(gè)SERVER的話是不能正常工作的。(因?yàn)橛脩粝嚓P(guān)的上下文是在SERVER中,如果后續(xù)連接通過負(fù)載均衡分配到其他機(jī)器上的話,那么將會(huì)找不到相應(yīng)信息)
而將SERVER換成大型機(jī)系統(tǒng)的花費(fèi)比增加幾臺(tái)便宜點(diǎn)的機(jī)器要高得多。對此,作者說可以買幾臺(tái)便宜的機(jī)器,在原來的老機(jī)器上安裝Haproxy,將系統(tǒng)壓力分散到多個(gè)機(jī)器中。也就是將架構(gòu)從圖(1)改成圖(2)
+-------+
|clients| clients and/or reverse-proxy
+---+---+
|
-+-----+--------+----
| _|_db
+--+--+ (___)
| web | (___)
+-----+ (___)
192.168.1.1 192.168.1.2
圖(1)
192.168.1.1 192.168.1.11-192.168.1.14 192.168.1.2
-------+-----------+-----+-----+-----+--------+----
| | | | | _|_db
+--+--+ +-+-+ +-+-+ +-+-+ +-+-+ (___)
| LB1 | | A | | B | | C | | D | (___)
+-----+ +---+ +---+ +---+ +---+ (___)
haproxy 4 cheap web servers
圖(2)
Haproxy數(shù)據(jù)流處理流程如下:
(client) (haproxy) (server A)
>-- GET /URI1 HTTP/1.0 ------------> |
( no cookie, haproxy forwards in load-balancing mode. )
| >-- GET /URI1 HTTP/1.0 ---------->
| <-- HTTP/1.0 200 OK -------------<
( the proxy now adds the server cookie in return )
<-- HTTP/1.0 200 OK ---------------< |
Set-Cookie: SERVERID=A |
>-- GET /URI2 HTTP/1.0 ------------> |
Cookie: SERVERID=A |
( the proxy sees the cookie. it forwards to server A and deletes it )
| >-- GET /URI2 HTTP/1.0 ---------->
| <-- HTTP/1.0 200 OK -------------<
( the proxy does not add the cookie in return because the client knows it )
<-- HTTP/1.0 200 OK ---------------< |
>-- GET /URI3 HTTP/1.0 ------------> |
Cookie: SERVERID=A |
( ... )
這就是Haproxy對于http會(huì)話的保持方式。首先客戶端發(fā)出第一個(gè)請求時(shí),通過負(fù)載均衡算法找出一個(gè)SERVER對其進(jìn)行處理,SERVER在處理完返回信息的時(shí)候?qū)?huì)在HTTP的頭中增加一個(gè)Cookie,SERVERID=A。在客戶端的后續(xù)請求中將會(huì)使用此Cookie來確定其對應(yīng)的SERVER。由于客戶端已經(jīng)知道了Cookie,因此對于以后的響應(yīng)數(shù)據(jù),Haproxy不會(huì)在插入此Cookie。
對于屬于KEEP-ALIVE的連接,Haproxy對Cookie不敏感,因?yàn)橹灰堰B接之后,后續(xù)的請求肯定都是在此session上進(jìn)行處理。
對于那些由于某種原因客戶端只支持一個(gè)Cookie的情況下,并且應(yīng)用程序返回的響應(yīng)中已經(jīng)設(shè)置了一個(gè)Cookie,那么可以使用前置Cookie來進(jìn)行標(biāo)記,也就是在響應(yīng)信息返回時(shí)在Haproxy中修改Cookie增加前置信息,在接收到后續(xù)的請求時(shí)將Cookie中的前置部分清除掉在發(fā)送到SERVER。
從這兒可以看出Haproxy主要是使用Cookie來解決session的問題,那么對于不支持Cookie的瀏覽器怎么辦?可以使用適當(dāng)?shù)呢?fù)載均衡算法來解決,比如用對源IPHASH來進(jìn)行負(fù)載均衡,那么可以保持同一IP總是在同一機(jī)器上。對于多IP的客戶端怎么辦?那就要求它使用單一IP,或則支持Cookie。
對architecture.txt就看到這兒,因?yàn)檫@主要是為了知道Haproxy的工作原理。
那么為什么architecture.txt只講了HTTP層次的SESSION保持,而不講TCP層次SESSION保持呢?從我的感覺來說,TCP層次沒有所謂SESSION概念。假設(shè)某TCP層次程序的某兩筆業(yè)務(wù)A和B的關(guān)系是B的處理需要A的處理結(jié)果,那么A的處理結(jié)果一般都會(huì)保存于DB中。