Server Load Balancing

當伺服器負載過大時,需要透過幾台伺服器分散效能~通常都採用 Cluster 的架構,由一台中心伺服器來負責監控與分散要求,Web Server 與 Database 等 Server 蠻常在遇到瓶頸後採用這種方式來解決。

如果是網頁伺服器,可以採用 Apache or nginx 的 proxy 做 reverse proxy 來做。 reverse proxy 是由一台伺服器接收 url request 再由該 proxy server 向背後的伺服器農場(server farm) 發出請求(http request),再將回傳的資料轉送至其他實際提供服務伺服器達成。所以所有要求都會經過該伺服器處理,所以雖然幫後端分散了一些負載,但是到最後負載可能會卡在 proxy server 上~

但如果是其他服務,例如 ftp , streaming , dns .. 等其他 tcp 的服務就沒辦法用以上的 reverse proxy server 處理,因為他算是 layer 7 的 load balance 不是單純再轉送封包而已,而是很 high level 的再轉送網頁內容而已,如果要處理 tcp 的 load balance 就要透過其他不單純再處理 Web Server 的 Load Blancing 軟體來處理囉。

有幾本書在討論這種軟體

平衡模式:

能夠達成負載平衡有幾種模式:

•  NAT Mode + HA

一台主伺服器負責接受要求,該伺服器再透過區網,將要求轉送給 private lan 內的其他處理伺服器,再由主伺服器轉送給 client,容易造成主伺服器過載。

•  Direct Routing Mode(DR)

主伺服器負責接受要求,再透過區網選擇出一台可以工作的伺服器,不修改也不封裝 IP 封包,而是將資料封包的 MAC 地址改為選出後端伺服器的 MAC 地址,再將修改後的資料封包在與後端伺服器組成的區域網路連結,因為資料封包的 MAC 地址是選出的後端伺服器,所以後端伺服器肯定可以收到該封包,該負責的伺服器在直接回應 client 不經過主伺服器。這樣效能比較不會卡在主伺服器上。

為什麼可以不用修改封包?因為  real server 的 ip 要設的跟 service server 一樣,並且關閉 arp,這樣 real server 再接收到封包的時候也不會覺得有奇怪,實際設定可以搜尋 lvs 的相關文章。

•  IP Tunneling Mode

連接分配和管理與 VS/NAT 中的一樣,只是它的封包轉送方法不同。 LBS 主機根據各個後端伺服器的負載情況,動態地選擇一台伺服器,將請求封包封裝在另一個 IP 封包中,再將封裝後的 IP 封包轉送給選出的後端伺服器。

後端伺服器收到封包後,先將封包解開獲得原來目標地址為 VIP 的封包,後端伺服器發現 VIP 位址被配置在本地的 IP 隧道設備上,所以就處理這個請求,然後依據路由表將回應封包直接返回給用戶端。

演算法:

  1. 輪詢(Round Robin)
    SLB 通過”輪詢”演算法將外部請求按順序輪流分配到集群中的真實伺服器上,它均等地對待每一台伺服器,而不管伺服器上實際的連接數和系統負載。
  2. 加權輪詢(Weighted Round Robin)
    SLB 通過”加權輪詢”調度算法根據真實伺服器的不同處理能力來調度訪問請求。這樣可以保證處理能力強的伺服器處理更多的負載流量。SLB 可以自動詢問真實伺服器的負載情況,並動態地調整其加權值。由管理者來決定哪個機器要承受較重的負載,依此分配權重。
  3. 最少鏈接(Least Connections)
    SLB 通過”最少連接”演算法動態地將網路請求調度到已建立的鏈接數最少的伺服器上。如果 Cluster 的伺服器性能相似,採用”最小連接”演算法可以較好地均衡負載。依照當時要求的連線數分配,不考慮伺服器的差異,應該跟輪詢差不多。
  4. 加權最少鏈接(Weighted Least Connections)
    在 Cluster 中的伺服器性能差異較大的情況下,LBS 採用”加權最少鏈接”演算法負載均衡性能,具有較高權重的伺服器將承受較大比例的連接負載。LBS 可以自動詢問真實伺服器的負載情況,並動態地調整其權值。加權輪詢的輪詢改成看當時連接數最少的…應該是優先順序的差異吧!
  5. 基於局部性的最少鏈接(Locality-Based Least Connections)
    “基於局部性的最少鏈接” 演算法是針對目標 IP 地址的負載均衡,目前主要用於 Cache Cluster 。該演算法根據請求的目標 IP 地址找出該目標 IP 地址最近使用的伺服器,若該伺服器 是可用的且沒有超載,將請求發送到該伺服器;若伺服器不存在,或者該伺服器超載且有伺服器處於一半的工作負載,則用”最少鏈接”的原則選出一個可用的伺服 器,將請求發送到該伺服器。
    這邊的情境是 Catch Server Cluster, 所以 Client 的要求都是告訴你他要查哪台伺服器的資料,所以才有目標 IP 這個變數,這演算法主要想控制每個伺服器分別處理特定的要求,例如Client 要求 Yahoo 的 IP 就固定給 a 處理,Google 的 IP 就給 b 處理,這樣就可以減少每台伺服器要處理的區域,可以節省一些 Catch 儲存空間。
  1. 帶複製的基於局部性最少鏈接(Locality-Based Least Connections with Replication)
    “帶複製的基於局部性最少鏈接” 演算法也是針對目標IP地址的負載均衡,目前主要用於Cache集群系統。它與LBLC算法的不同之處是它要維護從一個 目標IP地址到一組伺服器的對應,而LBLC 演算法維護從一個目標 IP 地址到一台伺服器的對應。該算法根據請求的目標IP地址找出該目標IP地址對應的伺服器組,按”最小連接”原則從伺服器組中選出一台伺服器,若伺服器沒有超載,將請求發送到該伺服器,若伺服器超載;則按”最小連接”原則從這個集群中選出一 台伺服器,將該伺服器加入到伺服器組中,將請求發送到該伺服器。同時,當該伺服器組有一段時間沒有被修改,將最忙的伺服器從伺服器組中刪除,以降低複製的 程度。
    如同的局部性最少連接,只是這次處理的伺服器為一組為單位, a b c 一組都處理 client 對 yahoo 的要求,b c d 一組都處理 client 對 google 的要求,對於負載很大的情況一台機器處理不來,分組會在過載時的分配會有一些改善。
  2. 目地分佈(Destination Hashing)
    “目地分佈” 演算法根據請求的目標 IP 地址,作為 Hash Key 從靜態分配的 Hash Table 找出對應的伺服器,若該伺服器是可用的且未超載,將請求發送到該伺服器,否則回應無可用伺服器。
  3. 來源分佈(Source Hashing)
    “來源分佈” 演算法根據請求的來源 IP 地址,作為 Hash Key 從靜態分配的 Hash Table 找出對應的伺服器,若該伺服器是可用的且未超載,將請求發送到該伺服器,否則回應無可用伺服器。

另外介紹常用的幾款著名的 Open Source 軟體 SLB,

軟體:

  • HAProxy

支援 Session keep alive,由於 http 伺服器很多台,如果遇到像 php 內建的 session 實作將 session 實體放在該機器上,

則沒辦法跨數台伺服器共用 session ,可能造成一個使用者在 a 機器 登入重新整理過後突然轉到 b 機器 ,

b 機器沒有 session 造成伺服器不認識使用者的情況,所以如果是 LBS 原生支援這種 session 的存活,可以省去自己要解決這種問題的麻煩。

效能佳,接近硬體LBS,特色是支援 Direct Routing,DR 前提是 real server 都能連結到實體網路。

沒什麼可以調整的參數,所以配置好就不用理他就可以跑得很好了~


分層:

Layer-2 Load Balancing

就是把好幾張網卡 bonding 起來上網分流…port aggregation

Layer-4 Load Balancing

可以針對 port 進行導向,例如 80 就導到某台 Web 伺服器,21 就導到 ftp Server~

Layer-7 Load Balancing

http 層的 load balance,可以判定虛擬伺服器~依照 http 內容去做決定要導到那個伺服器。

參考資料

歷史的痕跡

當你在撰寫一隻程式的時候,你腦中會有與該程式相關的背景知識,這是你透過瞭解這隻程式的過程中獲取而來的寶貴資料。當你要讓這隻程式產生變化之時,你得要從另外一個角度來觀看,從一個陌生人的角度,觀察這隻程式產生的變化,對這個陌生人而言有什麼意義!

例如你想要依照不同的資料做不同的處理,而你深刻的理解這兩種狀態的差異性,但!對這陌生人可不然~所以你需要留下可被追尋的痕跡,因為你在創造歷史,而你得告訴後人,為何要做這樣的決策,你可以試著用各種方式給予暗示。

註解,變數名稱,函式名稱~等等,這些可以具有意義的紀錄點~在這些地方留下深刻的印記。


<form><input type="text" name="name" /></form>

//type 1

if( $name == 'apple' || $name == 'orange') {
$db->insert('fruit', array('name', $name));
}
else if( $name == 'dog' || $name == 'cat') {
$db->insert('animal', array('name', $name));
}

//type 2

if( $name == 'apple' || $name == 'orange') {
   $type = 'fruit';
}
else if( $name == 'dog' || $name == 'cat') {
   $type = 'animal'
}
$db->insert($type, array('name', $name));

透過多命名一個稱為 $type 的變數,讓未來看見這隻程式的人,可以清楚的知道,name 有分成兩種 type ……是吧?!。。。

夢一場

今天做了一場大冒險的夢…

夢中我是一個作家,寫了很多著名的書,好像許多都跟文學有關~

有一天有壞人想要把我毀了,類似言論自由的箝制,想要把我的書全部毀掉,並且把我抓去關還是殺掉~

他就找到我家裡來,而我提早收到這個資訊,早就在家裡做好準備,把我的著作都藏起來,

夢中的家是三四樓的獨棟透天,此時我躲在頂樓的廁所裡面,而頂樓的樓上有一個密閉的小閣樓,

我將書本都藏在那裡,正常人應該不會輕易的發現,而我就躲在廁所裡面裝死…

接著我家被數十黑衣人士闖入大肆搜尋,而我躲的廁所被開關幾次,我假裝是其他人在大便也躲過了幾次搜尋~

但最後他們已經不耐煩,又找到廁所來…此時我發現紙已經包不住火…我就馬上往閣樓跑,抱著我最愛的幾本著作,

此時黑衣人已發現接衝入閣樓內,而我緊急之下,於頂樓閣樓內沿著窗戶爬出外牆,開始沿著牆壁邊緣快速的往下奔逃…

此時外面已經下起了傾盆大雨…,而我抱著書不斷的奔跑著,想著家裡的父母與姐姐…

由於雨勢之大,黑衣人也無法繼續追過來了,而我抱著已經濕透連書上的字都好像化開的紙們,

到了一個舊式的三合院,這附近的建築都是很古老的紅磚砌成的排樓,看起來也不太像有人居住,

我順勢跳入一間平房內,找到一間很擁擠看似只有一坪呈長方形廢棄的小廁所,躲藏了起來…

全身濕透了我開始把衣服拖掉晾乾,並且試著把小房間能遮蔽的窗與門都關閉好…

雖然簡陋但是有個棲身之處,那就決定在這先過夜再說吧,時間也不早了…

並看著我那濕透的著作們…不自覺哀傷了起來…

隔天起床雨已經停了,並且發現這間三合院有美麗的庭院,還種滿了許多種類的花,

正可以透過穿戶看出去,但是開始聽到有小孩嬉鬧的聲音…

翻翻乾掉的衣服與書,整理一下,並利用廁所的水清洗一下,想知道時間但是出門卻忘記帶手機…

阿…帶電話說不定會被追蹤…還是這樣安全…

突然間有個小孩探出頭來,詢問「欸,你是誰阿?」

我驚訝的想要解釋…但是他卻跑走去跟家裡大人告狀了…

我趕快將身上整理好,假裝是路人,走了出去,馬上看到一位婦人在我躲藏房間的牆外,

看起來像是坐在搖椅上,觀賞花園,我馬上主動解釋,「嗨,請問這裡是哪裡,我不小心進到這裡來,要怎麼出去呢」

此時我手上還提著鞋子…看起來就很不尋常…

最後我奔跑出三合院中…但聽到母親與姊姊討論我的事情的聲音…彷如時空錯置…

最終我被發現並且被槍射殺…或許是我捨不得的回去躲在三合院的小廁所中,享受那短暫棲身的寂寞…

reverse proxy

reverse proxy ,proxy 伺服器,可以將外部連線導入到內部網路的 web 伺服器,搭配 nat 可以隱藏內部網站,如果 load blancer 效果~
只是效能可能會卡在入口站的 網路 或 效能~

apache

<VirtualHost *:80>
     ServerName apple.tw
     ProxyRequests Off
     ProxyPreserveHost On
     ProxyPass / http://192.168.8.10/
     ProxyPassReverse / http://192.168.8.10/
 </VirtualHost>

nginx

   proxy_redirect     off;

    proxy_set_header   Host             $host;
    proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
    proxy_max_temp_file_size 0;

    proxy_connect_timeout      90;
    proxy_send_timeout         90;
    proxy_read_timeout         90;

    proxy_buffer_size          4k;
    proxy_buffers              4 32k;
    proxy_busy_buffers_size    64k;
    proxy_temp_file_write_size 64k;

    server {
        listen  80;
        server_name apple.tw;
        location / {
          proxy_pass http://192.168.8.10/;
        }
    }

用 ab 實際測試 apache 跟 nginx 的差異 ,在我的環境下都超慢的,感覺是虛擬機的設定有問題,

只是在近端網路測就比較正常了,且在 -c Number of multiple requests to make 越高的情況下, nginx 的表現竟然反而比較好,在低的情況下就都差不多。

好像是 catch 設定的問題..每次測都有點不一樣。