企業級負載平衡簡介


  在之前的一篇文章《放好你的密碼 - 從芝麻金融被攻破說起》中,一位讀者在評論中提出了“如果整個過程速度比較慢登陸會有問題”這樣一條評論。雖然說我對文章的正確性很有把握,但也仍需要仔細思考是否自己哪里沒有說清楚。在這個思考過程中,我想起了一個非常值得一說的話題,那就是負載平衡。

  在那篇文章中我們說到,要安全地管理好密碼,計算密碼哈希所使用的迭代次數應該盡可能地大,從而使得單次哈希計算的速度變長,增加惡意人員破解密碼的難度。反過來,如果有一百個人或者一千個人同時執行登陸操作,那么這么繁瑣的哈希計算將導致登陸服務器產生“忙不過來”的情況。此時我們就需要使用負載平衡將登陸請求分散到多個登陸服務器上,以降低單個服務器的負載。

 

負載平衡簡介

  或許有些讀者仍然對負載平衡這個名詞感到陌生,那么我們就花一小段篇幅來講解一下到底什么是負載平衡。

  在一個大型網站中,在線用戶有時可能有幾千個甚至上萬個之多。如果一個用戶的請求需要服務使用0.02秒來處理,那么該服務實例每秒鍾將只能處理50個這樣的請求,每分鍾也只能處理3000個。如果該服務是一個用戶非常常用的功能,如瀏覽網站的產品列表,那么很顯然單個服務實例已經無法支持該網站的運營。在這種情況下,我們就需要對該服務進行擴容。

  擴容主要分為Scale Up和Scale Out兩種,分別對應着增強單個服務的服務能力以及增強服務數量。在某些情況下,Scale Up是一個較為簡單的操作,例如為該服務所在的服務器添加更大的內存。但是任意一個服務器所能提供的能力實際上都受到其自身物理硬件能力的限制,尤其是具有越高性能的服務器其單位服務能力的價格越為昂貴,因此我們就需要使用Scale  Out方式將工作量分攤到多個服務器之中:

  就如上圖所顯示的那樣,當服務器的負載過多而來不及處理的時候,服務器就處於一種過載的狀態。在該狀態的服務常常會出現響應速度慢甚至無響應的情況。而在執行了Scale Out之后,我們將會使用多個服務器同時處理用戶的請求。在該解決方案中,我們需要使用一台特定的設備將這些請求分發到各個服務器。該設備會根據其內部所包含的請求分發邏輯來決定如何對這些請求進行分發,以避免出現單個服務器過載的情況。這些用來對請求進行分發的設備實際上就是負載平衡服務器。

  當然,我們不會等到服務器真正過載了才去解決這個問題。在服務的日常運維中,我們在服務器的平均負載和峰值負載達到某個特定閾值時就需要考慮是否需要為相應服務進行擴容。

  一旦一個服務使用了負載平衡系統,那么它將在高可用性以及擴展性上得到極大的增強。這也是我們使用負載平衡解決方案的最重要原因。例如對於一個擁有三台服務器的負載平衡系統,如果其中一台發生了故障,那么負載平衡服務器可以通過向各個服務發送心跳等方式得知它們的異常,進而不再向這個發生了故障的服務器分發任務:

  而如果當前負載平衡系統中所負擔的服務容量已經超過了閾值,那么我們可以簡單地通過在負載平衡系統中添加服務器來解決這個問題:

  這樣,每個服務器所需要處理的任務就相對減少了,從而減輕了單個服務器的負擔。

 

基於DNS的負載平衡

  OK,在了解了負載平衡系統的大致組成及使用方式之后,我們就來看看各種負載解決方案。

  當前業界中所最常使用的負載平衡解決方案主要分為三種:基於DNS的負載平衡,L3/4負載平衡,也即是基於網絡層的負載平衡,以及L7負載平衡,即基於應用層的負載平衡。在這些解決方案中,基於DNS的負載平衡是最簡單的,也是最早出現的一種負載平衡解決方案。

  當我們通過在瀏覽器的地址欄中鍵入域名來訪問某個網站時,瀏覽器將首先查找本地的DNS緩存是否擁有該域名所對應的IP地址。如果有,那么瀏覽器將嘗試直接使用該IP地址訪問該網站的內容。如果本地DNS緩存中沒有該域名所對應的IP地址,那么它將向DNS發送一個請求,以獲得該域名所對應的IP並添加到本地DNS緩存中。

  而在DNS中,一個域名可能和多個IP地址綁定。在這種情況下,DNS響應將會按照Round Robin方式返回這些IP地址的列表。例如在多次通過nslookup或host等命令來查看特定域名所對應的IP時,其可能的返回如下(因國內網絡原因,您需要翻牆再進行試驗):

 

  $ host -t a google.com

  google.com has address 72.14.207.99

  google.com has address 64.233.167.99

  google.com has address 64.233.187.99

 

  $ host -t a google.com

  google.com has address 64.233.187.99

  google.com has address 72.14.207.99

  google.com has address 64.233.167.99

 

  可以看到,不同的DNS請求所返回的結果會按照Round Robin進行輪換,進而使得不同的用戶訪問不同的IP地址,平衡各個服務器的負載。

  雖然這種負載平衡解決方案非常容易實現,但是它有一個致命的缺點:為了減少DNS請求的次數以提高訪問效率,瀏覽器常常緩存了DNS查詢的結果。如果一個IP處的服務失效,那么瀏覽器可能仍會根據DNS緩存中所記錄的信息向該不可用的服務發送請求(不同的瀏覽器可能有不同的行為)。雖然說整個服務只有一處IP所對應的服務失效了,但是從用戶的角度看來該網站已經不可訪問。因此基於DNS的負載平衡方案並不能作為一個獨立的負載平衡解決方案來提供高可用性的保障,而是作為其它負載平衡解決方案的補充方案來使用。

 

L3/4負載平衡

  另一種較為常見的負載平衡則是L3/4負載平衡。這里的L3/4實際上指的就是負載平衡服務器會根據OSI模型中的第三層網絡層(Network Layer)和第四層傳輸層(Transport Layer)所包含的數據來進行負載平衡操作。在這種負載平衡服務器中,這些數據主要包含數據包的IP頭和TCP、UDP等協議的協議頭:

  L3/4負載平衡服務器的工作原理非常簡單:在數據到達時,負載平衡服務器將根據自身算法以及OSI模型三四層所包含的數據決定需要處理該數據的服務實例並將其轉發。

  整個負載平衡的運行包含三方面內容:負載平衡服務器需要知道當前有效的服務實例到底有哪些,並根據自身的分派算法來決定需要處理數據的服務實例,根據分派算法的計算結果將數據發送到目標服務實例上。

  首先來看看負載平衡服務器是如何確定服務實例的有效性的。為了能夠保證從負載平衡服務器所派發的數據包能被它后面的服務器集群正常處理,負載平衡服務器需要周期性地發送狀態查詢請求以探測到底哪些服務實例正在有效地工作。這種狀態查詢請求常常會超出很多人的認知:如果服務實例崩潰但是承載它的操作系統正常工作,那么該操作系統仍然會正常響應負載平衡服務器所發出的Ping命令,只是此時TCP連接會失敗;如果服務實例並沒有崩潰,而只是掛起,那么它仍然可以接受TCP連接,只是無法接收HTTP請求。

  由於這種狀態查詢請求實際上是特定於服務實例的具體實現,因此很多負載平衡服務器都允許用戶添加自定義腳本以執行特定於服務實例的查詢。這些狀態查詢請求常常包含了很多測試,甚至會嘗試從服務實例中返回數據。

  一旦負載平衡服務器發現其所管理的某個服務實例不再有效,那么它就不會再將任何數據轉發給該服務實例,直到該服務實例回歸正常狀態。在這種情況下,其它各個服務實例就需要分擔失效服務器所原本承擔的工作。

  這里需要注意的一點是,在某個服務實例失效以后,整個系統仍應該具有足夠的總容量以處理負載。舉例來說,假如一個負載平衡服務器管理了三個具有相同能力的服務實例,而且這三個服務實例各自的負載都在80%左右。如果其中一個服務實例失效,那么所有的負載都需要由其它兩個服務實例來完成。每個服務實例就需要承擔120%的負載,遠超過了它所具有的負載能力。這種情況的直接后果就是,服務顯得非常不穩定,並常常有系統超時,應用無法正常工作的情況出現。

  OK。 現在假設我們的負載平衡服務器有一個設計良好的狀態查詢請求,那么它就會根據其所使用的負載平衡算法來為工作的服務實例分配負載。對於初次接觸到負載平衡功能的人來說,最常見的誤區就是認為負載平衡服務器會根據各個服務實例的響應速度或負載狀況來決定請求需要到達的服務實例。

  通常情況下,Round Robin算法是最常用也是表現最好的負載平衡算法。如果各個服務實例的容量並不相同,那么負載平衡服務器會使用Weighted Round Robin算法,即根據各個服務實例的實際能力來安比例地分配負載。在某些商業負載平衡服務器中,其的確會根據當前服務實例的負載以及響應時間等因素對這些分配比例自動進行微小地調整,但是它們並不是決定性的因素。

  如果單純地使用Round Robin算法,那么具有關聯關系的各個請求將可能被分配到不同的服務實例上。因此很多負載平衡服務器允許根據數據的特定特征對這些負載進行分配,如使用一種哈希算法來對用戶所在的IP進行計算,並以計算結果決定需要分配到的服務實例。

  同樣地,我們也需要考慮某個服務器實例失效的情況。如果負載平衡系統中的某個服務器實例失效,那么哈希算法中的哈希值空間將發生變化,進而導致原本的服務實例分配結果將不再有效。在這種情況下,所有的請求將重新分配服務器實例。另外,在某些情況下,用戶的IP也可能在各個請求之間發生變化,進而導致它所對應的服務實例發生更改。當然,不用擔心,后面對L7負載平衡服務器的講解會給您一個解決方案。

  在確定了數據包的目標地址后,負載平衡服務器所需要做的事情就是將它們轉發到目標實例了。負載平衡服務器所使用的轉發方式主要分為三種:Direct routing,Tunnelling以及IP address translation。

  在使用Direct routing方式的時候,負載平衡服務器以及各個服務實例必須在同一個網段上並使用同一個IP。在接收到數據的時候,負載平衡服務器將直接對這些數據包進行轉發。而各個服務實例在處理完數據包之后可以將響應返回給負載平衡服務器,也可以選擇將響應直接發送給用戶,而不需要再經過負載平衡服務器。后一種返回方式被稱為Direct Server Return。其運行方式如下所示:

  在該過程中,負載平衡服務器和各個服務實例都不需要對IP(Internet Protocol)層數據進行任何更改就可以對其進行轉發。使用這種轉發方式的負載平衡服務器的吞吐量非常高。反過來,這種組織方式也要求集群的搭建人員對TCP/IP等協議擁有足夠多的理解。

  另一種轉發方式Tunnelling實際上與Direct routing類似。唯一的一點不同則是在負載平衡服務器和各個服務之間建立了一系列通道。軟件開發人員仍然可以選擇使用Direct Server Return來減輕負載平衡服務器的負載。

  IP Address Translation則與前兩種方式非常不同。用戶所連接的目標地址實際上是一個虛擬地址(VIP,Virtual IP)。而負載平衡服務器在接到該請求的時候將會將其目標地址轉化為服務實例所在的實際地址(RIP,Real IP),並將源地址更改為Load Balancer所在的地址。這樣在對請求處理完畢后,服務實例將會把響應發送到負載平衡服務器。此時負載平衡服務器再將響應的地址更改為VIP,並將該響應返回給用戶。在這種轉發方式下,其運行流程則如下所示:

  有些細心的讀者會問:在消息傳遞的過程中,用戶所在的User IP已經不在消息中存在了,那負載平衡服務器在傳回響應的時候應該如何恢復用戶的IP地址呢?實際上在這種轉發方式中,負載平衡服務器會維持一系列會話,以記錄每個經由負載平衡服務器的正在處理的各個請求的相關信息。但是這些會話非常危險。如果將會話持續的時間設置得比較長,那么在一個高並發的負載平衡服務器上就需要維護過多的會話。反之如果將會話持續的時間設置得過短,那么就有可能導致ACK Storm發生。

  先看會話持續時間較長的情況。假設當前負載平衡服務器每秒鍾會接收到50000個請求,而且該負載平衡服務器的會話過期時間為2分鍾,那么其就需要保持6000000個會話。這些會話會占用負載平衡服務器的很大部分資源。而且在負載高峰期,其所消耗的資源可能會成倍地增長,會向服務器施加更多的壓力。

  但是將會話持續時間設置得比較短則更為麻煩。這會導致用戶和負載平衡服務器之間產生ACK Storm,占用用戶和負載平衡服務器的大量帶寬。在一個TCP連接中,客戶端和服務端需要通過各自的Sequence Number來進行溝通。如果負載平衡服務器上的會話快速地失效,那么其它TCP連接就有可能重用該會話。被重用的會話中客戶端和服務端的Sequence Number都會被重新生成。如果此時原有的用戶再次發送消息,那么負載平衡服務器將通過一個ACK消息通知客戶端其擁有的Sequence Number出錯。而在客戶端接受到該ACK消息之后,其將向負載平衡服務器發送另一個ACK消息通知服務端所擁有的Sequence Number出錯。服務端接受到該ACK消息后,將再次發送ACK消息到客戶端通知其所擁有的Sequence Number出錯……這樣客戶端和服務端之間就將持續地發送這種無意義的ACK消息,直到某個ACK消息在網絡傳輸過程中丟失為止。

  因此乍一看來,使用IP Address Translation的方案是最容易的,但是相較於其它兩種方案,它卻是最危險也是維護成本最高的一種方案。

 

L7負載平衡

  另一種較為常用的負載平衡解決方案則是L7負載平衡。顧名思義,其主要通過OSI模型中的第七層應用層中的數據決定如何分發負載。

  在運行時,L7負載平衡服務器上的操作系統會將接收到的各個數據包組織成為用戶請求,並根據在該請求中所包含的的數據來決定由哪個服務實例來對該請求進行處理。其運行流程圖大致如下所示:

  相較於L3/4負載平衡服務所使用的數據,L7負載平衡服務所使用的應用層數據更貼近服務本身,因此其具有更精確的負載平衡行為。

  在前面對L3/4負載平衡的講解中我們已經介紹過,對於某些具有關聯關系的各個請求,L3/4負載平衡服務器會根據某些算法(如計算IP的哈希值)來決定處理該請求的服務實例。但是這種方法並不是很穩定。當一個服務實例失效或用戶的IP發生變化的時候,用戶與服務實例之間的對應關系就將發生改變。此時用戶原有的會話數據在新的服務實例上並不存在,進而導致一系列問題。

  其實產生這個問題的最根本原因就是用戶與服務實例之間的關聯關系是通過某些外部環境創建的,而並非由用戶/服務實例本身來管理。因此它不能抵御外部環境變化的沖擊。如果要在用戶和服務實例之間建立穩定的關聯關系,那么就需要一種穩定的在用戶和服務實例之間傳遞的數據。在Web服務中,這種數據就是Cookie。

  簡單地說,基於Cookie的負載平衡服務實際上就是分析用戶請求中的某個特定Cookie並根據其值決定需要分發到的目標地址。其主要分為兩種方式:Cookie  Learning以及Cookie Insertion。

  Cookie Learning是不具有侵入性的一種解決方案。其通過分析用戶與服務實例通訊過程中所傳遞的Cookie來決定如何分派負載:在用戶與服務第一次通訊時,負載平衡服務將找不到相應的Cookie,因此其將會把該請求根據負載平衡算法分配到某個服務實例上。而在服務實例返回的時候,負載平衡服務器將會把對應的Cookie以及服務實例的地址記錄在負載平衡服務器中。當用戶再次與服務通訊時,負載平衡服務器就會根據Cookie中所記錄的數據找到前一次服務該用戶的服務實例,並將請求轉發到該服務實例上。

  這么做的最大缺點就是對高可用性的支持很差。如果一旦負載平衡服務器失效,那么在該負載平衡服務器上所維護的Cookie和服務實例之間的匹配關系將全部丟失。這樣當備份負載平衡服務器啟動之后,所有的用戶請求都將被定向到隨機的服務實例。

  而另一個問題就是會話維護功能對內存的消耗。與L3/4服務器上的會話維護不同,一個Cookie的失效時間可能非常長,至少在一次用戶使用中可能會持續幾個小時。對於一個訪問量達到每秒上萬次的系統而言,負載平衡服務器需要維護非常多的會話,甚至可能會將服務器的內存消耗殆盡。反過來,如果將負載平衡服務器中的Cookie過期時間設置得太短,那么當用戶重新訪問負載平衡服務器的時候,其將被導向到一個錯誤的服務實例。

  除了Cookie Learning 之外,另一種常用的方法就是Cookie Insertion。其通過向響應中添加Cookie以記錄被分派到的服務實例,並在下一次處理請求時根據該Cookie所保存的值來決定分發到的服務實例。在用戶與服務器進行第一次通訊的時候,負載平衡服務器將找不到分派記錄所對應的Cookie,因此其會根據負載平衡算法為該請求分配一個服務實例。在接收到服務實例所返回的數據之后,負載平衡服務器將會向響應中插入一個Cookie,以記錄該服務實例的ID。當用戶再次發送請求到負載平衡服務器時,其將根據該Cookie里所記錄的服務實例的ID派發該請求。

  相較於Cookie Learning,Cookie Insertion不需要在內存中維護Cookie與各個服務實例的對應關系,而且在當前負載平衡服務器失效的時候,備用負載平衡服務器也可以根據Cookie中所記錄的信息正確地派發各個請求。

  當然,Cookie Insertion也有缺陷。最常見的問題就是瀏覽器以及用戶自身對Cookie的限制。在Cookie Insertion中,我們需要插入一個額外的Cookie 來記錄分配給當前用戶的服務實例。但是在某些瀏覽器中,特別是移動瀏覽器中,常常會限制Cookie的個數,甚至只允許出現一個 Cookie。為了解決這個問題,負載平衡服務器也會使用一些其它方法。如Cookie Modification,即修改一個已有的Cookie使其包含服務實例的ID。

  而在用戶禁用了Cookie的時候,Cookie Insertion將是完全失效的。此時負載平衡服務所能利用的將僅僅是JSESSIONID等信息。因此在一個L7負載平衡服務器中,Cookie Learning和Cookie Insertion常常同時使用:Cookie Learning會在用戶啟用Cookie的時候起主要作用,而在Cookie被用戶禁用的情況下則使用Cookie Learning來根據JSESSIONID來保持用戶與服務實例之間的關聯關系。

  或許您會想:L3/4負載平衡服務器在處理各個關聯請求的時候是通過IP的哈希值來決定處理該請求的服務實例的。既然這些基於Cookie的解決方案能達到100%的准確,為什么我們不在L3/4負載平衡服務器中使用它們呢?答案是:由於L3/4負載平衡服務器主要關注於數據包級別的轉發,而Cookie信息則藏匿於數據包之中,因此L3/4負載平衡服務器很難決定單一的數據包該如何轉發。

  例如在執行Cookie Insertion操作的時候,原有數據包中的所有數據都將被后移。此時需要負載平衡服務器接收到所有數據包之后才能完成:

  試想一下接收所有數據包所可能發生的事情吧。在網絡的一端發送多個數據包的時候,網絡的另一端所接收到的數據包的順序可能與原有的發送順序並不一致。甚至在網絡擁堵的時候,某些數據包可能會丟失,進而再次加長接收到所有數據包所需要的時間。

  因此相較於將數據包直接轉發的方法,等待所有的數據包到齊然后再插入Cookie的性能非常差。在后面對於解決方案的講解中您會看到,L3/4負載平衡服務器對於性能的要求一般來說是很高的,而L7負載平衡服務器則可以通過一個集群來解決自身的性能問題。基於DNS的負載平衡,L3/4負載平衡服務器以及L7負載平衡服務器常常協同工作,以組成一個具有高可用性以及高可擴展性的系統。

 

SSL Farm

  在上面的講解中,我們忽略了一個事情,那就是L7負載平衡服務器對於SSL的支持。在L7負載平衡服務器中,我們常常需要讀寫請求及響應中的Cookie。但是如果通訊使用的是SSL連接,那么L7負載平衡服務器將無法對請求及響應的內容進行讀寫操作。

  解決該問題所曾經使用的一個解決方案就是:將負載平衡服務器以反向代理的方式使用。在這種方案中,負載平衡服務器將擁有服務的證書,並可以通過證書中的密鑰對請求進行解密。解密完成后,負載平衡服務器就可以開始嘗試讀取Cookie中的內容並根據其所記錄的信息決定該請求所需要派發到的服務實例。在對該請求進行派發的時候,負載平衡服務器可以不再使用SSL連接,進而使得各個服務實例不再需要再次解密請求,提高服務實例的運行效率。

  在請求處理完畢之后,服務實例將通過服務實例與負載平衡服務器的非SSL連接返回一個響應。在負載平衡服務器接收到該響應之后,其將會把該響應加密並通過SSL連接發出:

  但是這樣做的問題在於,如果所有對SSL的處理都集中在L7負載平衡服務器上,那么它將會變成系統的瓶頸。繞過該問題的方法就是在L7負載平衡服務器之前使用一系列反向代理來負責SSL的編解碼操作。

  此時整個系統的架構將呈現如下的層次結構:

  從上圖中可以看到,整個解決方案分為了四層。在用戶的請求到達了第一層的負載平衡服務器時,其將會把該請求根據自身的負載平衡算法轉發給處於第二層的專門負責SSL編解碼工作的反向代理。該代理會將傳入的由SSL連接所傳輸的請求由非SSL連接傳出。在請求到達第三層時,L7負載平衡服務器可以直接訪問這些請求所包含的Cookie,並根據Cookie中的內容決定需要處理該請求的服務實例。

  這么做的好處有很多。首先就是這些反向代理非常便宜,甚至只有常見負載平衡服務器的1/20左右的價格,卻在處理SSL連接上擁有幾乎相同的效率。除此之外,這些反向代理還提供了非常良好的擴展性和高可用性。一旦負載平衡系統在處理SSL連接的能力上顯得有些吃力,我們就隨時可以向系統中添加新的反向代理。而一旦其中一個反向代理失效,那么其它反向代理可以通過多承擔一些負載來保證系統的安全運行。

 

需要考慮的問題

  在提出具體的負載平衡解決方案之前,我們需要首先講解一下在設計負載平衡系統時我們所需要考慮的一些事情。

  首先要說的就是要在負載平衡系統設計時留意它的高可用性及擴展性。在一開始的講解中,我們就已經提到過通過使用負載平衡,由眾多服務器實例所組成的服務具有很高的可用性及擴展性。當其中一個服務實例失效的時候,其它服務實例可以幫助它分擔一部分工作。而在總服務容量顯得有些緊張的時候,我們可以向服務中添加新的服務實例以擴展服務的總容量。

  但是由於所有的數據傳輸都需要經過負載平衡服務器,因此負載平衡服務器一旦失效,那么整個系統就將無法使用。也就是說,負載平衡服務器的可用性影響着整個系統的高可用性。

  解決這個問題的方法要根據負載平衡服務器的類型來討論。對於L3/4負載平衡服務器而言,為了能夠讓整個系統不失效,業界中的常用方法是在系統中使用一對負載平衡服務器。當其中一個負載平衡服務器失效的時候,另一個還能夠為整個系統提供負載平衡服務。這一對負載平衡服務器可以按照Active-Passive模式使用,也可以按照Active-Active模式使用。

  在Active-Passive模式中,一個負載平衡服務器處於半休眠狀態。其將會通過向另外一個負載平衡服務器發送心跳消息來探測對方的可用性。當正在工作的負載平衡服務器不再響應心跳的時候,那么心跳應用將會把負載平衡服務器從半休眠狀態喚醒,接管負載平衡服務器的IP並開始執行負載平衡功能。

  而在Active-Active模式中,兩台負載平衡服務器會同時工作。如果其中一台服務器發生了故障,那么另一台服務器將會承擔所有的工作:

  可以說,兩者各有千秋。相較而言,Active-Active模式具有較好的抵抗訪問量大幅波動的情況。例如在通常情況下,兩個服務器的負載都在30%左右,但是在服務使用的高峰時間,訪問量可能是平時的兩倍,因此兩個服務器的負載就將達到60%左右,仍處於系統可以處理的范圍內。如果我們使用的是Active-Passive模式,那么平時的負載就將達到60%,而在高峰時間的負載將達到負載平衡服務器容量的120%,進而使得服務無法處理所有的用戶請求。

  反過來,Active-Active模式也有不好的地方,那就是容易導致管理上的疏忽。例如在一個使用了Active-Active模式的系統中,兩個負載平衡服務器的負載常年都在60%左右。那么一旦其中的一個負載平衡服務器失效了,那么剩下的唯一一個服務器同樣將無法處理所有的用戶請求。

  或許您會問:L3/4負載平衡服務器一定要有兩個么?其實主要由各負載平衡服務器產品自身來決定的。在前面我們已經講過,實際上探測負載平衡服務器的可用性實際上需要很復雜的測試邏輯。因此如果一旦我們在一個負載平衡系統中使用了過多的L3/4負載平衡服務器,那么這些負載平衡服務器之間所發送的各種心跳測試將消耗非常多的資源。同時由於很多L3/4負載平衡服務器本身是基於硬件的,因此它能夠非常快速地工作,甚至可以達到與其所支持的網絡帶寬所匹配的處理能力。因此在一般情況下,L3/4負載平衡服務器是成對使用的。

  如果L3/4負載平衡服務器真的接近其負載極限,那么我們還可以通過DNS負載平衡來分散請求:

  這種方法不僅僅可以解決擴展性的問題,更可以利用DNS的一個特性來提高用戶體驗:DNS可以根據用戶所在的區域選擇距離用戶最近的服務器。這在一個全球性的服務中尤為有效。畢竟一個中國用戶訪問在中國架設的服務實例要比訪問在美國架設的服務實例快得多。

  反過來由於L7負載平衡服務器主要是基於軟件的,因此很多L7負載平衡服務器允許用戶創建較為復雜的負載平衡服務器系統。例如定義一個具有兩個啟用而有一個備用的一組L7負載平衡服務器。

  講解完了高可用性,我們就來介紹一下負載平衡服務器的擴展性。其實在上面我們剛剛介紹過,L3/4負載平衡服務器擁有很高的性能,因此一般的服務所使用的負載平衡系統不會遇到需要擴展性的問題。但是一旦出現了需要擴展的情況,那么使用DNS負載平衡就可以達到較好的擴展性。而L7負載平衡則更為靈活,因此擴展性更不是問題。

  但是一個負載平衡系統不可能都是由L3/4負載平衡服務器組成的,也不可能只由L7負載平衡服務器組成的。這是因為兩者在性能和價格上都具有非常大的差異。一個L3/4負載平衡服務器實際上價格非常昂貴,常常達到上萬美元。而L7負載平衡服務器則可以使用廉價服務器搭建。L3/4負載平衡服務器常常具有非常高的性能,而L7負載平衡服務器則常常通過組成一個集群來達到較高的整體性能。

  在設計負載平衡系統時,還有一點需要考慮的那就是服務的動靜分離。我們知道,一個服務常常由動態請求和靜態請求共同組成。這兩種請求具有非常不同的特點:一個動態請求常常需要大量的計算而傳輸的數據常常不是很多,而一個靜態的請求常常需要傳輸大量的數據而不需要太多的計算。不同的服務容器對這些請求的表現差異很大。因此很多服務常常將其所包含的服務實例分為兩部分,分別用來處理靜態請求和動態請求,並使用適合的服務容器提供服務。在這種情況下,靜態請求常常被置於特定的路徑下,如“/static”。這樣負載平衡服務器就可以根據請求所發送到的路徑而將動態請求和靜態請求進行適當地轉發。

  最后要提到的就是L3/4負載平衡服務器的一個軟件實現LVS(Linux Virtual Server)。相較於硬件實現,軟件實現需要做很多額外的工作,例如對數據包的解碼,為處理數據包分配內存等等呢個。因此其性能常常只是具有相同硬件能力的L3/4負載平衡服務器的1/5到1/10。鑒於其只具有有限的性能但是搭建起來成本很低,如利用已有的在Lab里閑置的機器等,因此其常常在服務規模不是很大的時候作為臨時替代方案使用。

 

負載平衡解決方案

  在文章的最后,我們將給出一系列常見的負載平衡解決方案,以供大家參考。

  在一般情況下,一個服務的負載常常是通過某些方式逐漸增長的。相應地,這些服務所擁有的負載平衡系統常常是從小到大逐漸演化的。因此我們也將會按照從小到大的方式逐次介紹這些負載平衡系統。

  首先是最簡單的包含一對L7負載平衡服務器的系統:

  如果服務的負載逐漸增大,那么該系統中唯一的L7負載平衡服務器很容易變成瓶頸。此時我們可以通過添加一個SSL Farm以及運行LVS的服務器來解決問題:

  如果我們還要應對增長的負載,那么就需要使用真正的基於硬件的L3/4負載平衡服務器來替代LVS,並增加各層的容量:

  由於該解決方案的下面三層基本都有理論上無限的擴展性,因此最容易出現過載的就是最上面的L3/4負載平衡服務器。在這種情況下,我們就需要使用DNS來分配負載了:

 

轉載請注明原文地址並標明轉載:http://www.cnblogs.com/loveis715/p/4547968.html

商業轉載請事先與我聯系:silverfox715@sina.com


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM