Windows NLB 倒底是什麼東西?

各位客倌您沒看錯, Windows NLB (Network Load Balance) 這篇文章居然被放在我 Linux 的分類下…

Windows NLB 架構

Windows NLB 架構

話說 NLB 的設定方法還真的很簡單, 在 Windows Server 的界面下, 只要點點 “新增叢集”, 設設 “叢集IP設定”, 選選 “叢集操作模式”, 就好了!

真的是這樣嗎?

不, Windows NLB 真的.不.好.上.手.又.難.懂, 不像 Linux Virtual Server 那麼容易搞懂運作原理與佈署方法. 在一個偶然的機會下, 我有幸觀摩到別人使用 NLB 來玩負載平衡…一種我心儀已久看起來好像很厲害又很方便的技術…

(這篇我做了一次 reader’s test, 某人看沒一半就點了視窗右上方的叉叉了… 所以客倌們非網路技術工程背景者, 建議您也不要服用本篇; 基本上沒什麼營養可言, 只是很大篇的抱怨文)

說 “觀摩” 是因為我對 Windows 真的一竅不通, 畢竟我是 Linux 基本教義派的… 好, 問題馬上就來了: What is multicast? 這個問題您問一百個資工資科的學生, 很多人都知道它叫 “多點傳送”, 但這多點傳送要怎麼運作? 其實翻翻教課書或網路上的文章很多都只有原理講解… 我想因為真正懂得 implementation 的人早就在靠此悶著頭賺大錢了, 哪還有時間把吃飯的傢伙寫出來分享?

Multicast 示意圖

Multicast 示意圖

在了解原理後 (說真的我還是不了解! 容後再述), 我對於 NLB 利用 multicast 這招真的有點嚇到. 其實這真的是一種反向的運用. 以往在書上看到的 multicast 的應用都是在 voice/video 方面的. 早期若是要線上收看 video, 相同內容的封包, 丟給N個特定的 clients (同時收看), 就得佔用N倍的骨幹流量, 這我們叫 unicast; “使用 multicast, 則可以節省網路骨幹的流量使用”, 既然內容相同, 何不只丟一份封包於骨幹上, 到某個分岐點後, 再散佈給特定的 clients 呢? 多棒的概念啊! 好吧, 這個概念打從 IPv4 有 Class D (RFC988, 1986年) 以來, 到今天 2010 年, 各位網民們您實際上網路生活中真的用到過嗎? 為什麼這樣難看到? 因為啊, multicast 在實用上, client 及一層一層的 switch/router 都要用到 IGMP (Internet Group Management Protocol, 網際網路群組管理協定) 來加入 multicast group, 問題是您上層 router 誰會相信您要加入某一群組的合法性? 且各個不同 ISP 彼此之間的 IGMP 是否可信任? 且 IGMP 據測非常耗 router 的 CPU 資源? 加上太多的商業因素 (講好聽是 “安全性考量”), 均使得這個超棒的概念一點都不切實際. 台灣少數(可能也是唯一)的應用例就是 “中華電信MOD” 這種封閉式 (單一ISP內) 的服務.

扯太遠了, 回題. NLB 用到的 multicast 完全不是基於這樣的精神; 上一段”經文”講的其實是指 IP Multicast, 而微軟用的是 Ethernet Multicast. 叢集 IP 仍屬於 unicast IP 的範圍 (因為此一 Virtual IP 會和您實際 servers 處在同一網段…; 但事實上 NLB 在使用 IGMP 時仍然會在 LAN 內宣告一個 class D 的 multicast IP 才能依 IGMP 加入 multicast group, 在此不加詳述), 所以 router 之間不用管 IGMP 的問題, 把從 Internet 來的 client 端丟來的單一封包 (通常應用上就是指 tcp connection request, 通常就是 port 80…) 不斷地丟丟丟, 最後只需在 server 所在網段的 LAN 內, (通常應該)由 switch 負責散發, 同時丟給叢集內所有的 servers. 這些 servers 再基於相同但官方語焉不詳的演算法來決定是哪台 server 要回應這個封包以回應這位特定 client 的 connection, 而其他台 server(s) 則會丟棄這個封包不理. 這種類似”對號入座”的過程, 都在每台主機的 kernel space 的 wlbs.sys (intermediate NDIS driver) 內完成, 唯有需要回應的 server 其封包才會正式上達一般的 TCP/IP 層級… 好像是這樣的原理. Orz. 好複雜的東西… 之所以說 “反向的運用”, 是說上一段”經文”是讓 client 加入 multicast group, 而微軟的 NLB 則是讓 server 加入 multicast group. 不管怎樣, 目的是達到了, 確實是做到了 “負載平衡” 這樣的需求. 但很快地, 又有問題來了.

NLB stack

NLB stack

2010/11/21註: 有台灣 NLB 大師 (同時也是獲微軟MVP獎項之高人) 來訊指出, 我寫 wlbs.sys 是錯字, 應為 nlb.sys 才對. 不過我把之前在 微軟 TechNet 找的資料翻出來看後 (請先看一下右圖)… 我想我文內 “intermediate NDIS driver”, 指的正是 NLB driver 那一層, 而依該資料內的某張表中的說法即是指 Wlbs.sys… 所以應該是微軟 TechNet 此份資料太舊, 或是有留一手, 試圖誤導我這種門外漢 :p

(OK, 如果再往下走, 您必須了解 layer-3 即 IP 層的 routing 方式, 不然恐怕會一知半解, 看不到問題在哪)

什麼樣的問題呢?

第一, 雖然微軟這招是用了 unicast IP 來玩 multicast: “叢集 IP” 仍屬於 class A~C 的範圍, 看來在各 router 間不會有什麼狀況嘛… 非也非也. 其實 ethernet multicast 用到的 mac address 是有個特徵可資辨識的: “第一個位元組的最後一個位元” (在寫繞口令嗎? 其實就是第一個Byte為奇數咩) 如果是 1 的話, 則這個 mac address 即屬於 multicast 封包. 事實上我們看到叢集 IP 產生的 multicast mac address 會是 01:00:5E 開頭的 (for IGMP), 好回應人家的 ARP query, 作法完全合乎規範, 但壞就壞在這裏了. 雖然各個 router 間在處理 unicast IP 是不會有問題的, 即使兩顆 router 間有用到 arp, 但也是以 router 他們自己的 mac address 來回應, 絕非叢集產生的那個 multicast mac address (01:00:5E開頭的). 很不幸, 問題就出在 “last router” 上. 依照 RFC1812, “A router MUST not believe any ARP reply that claims that the Link Layer address of another host or router is a broadcast or multicast address”, 所以從 Internet 來的封包, 到了最後一顆 router 上時, router 用了 arp 問說 LAN 內是這 IP 是誰在用呀? 叢集回應了, 但就因為它不能相信叢集回應的 multicast mac address, 也就不會註冊在動態的 arp table 中, 接下來它根本不知道要把這個 dest IP 丟到 Ethernet LAN 裏的哪個 mac address? 自然就在 router 內 “往生” 了… 結論就是您得說服您的 ISP/IDC 管這顆 router 的負責人, 新增一筆靜態對應 (IP 對應 mac address), 或是為您打開 “他們認為政策上很不安全的” IGMP, 這樣這個封包才會通到您的 LAN 內. 至此才打通第一道難關.

2010/10/18註: 之前在 CISCO 網站上不小心又看到這一段.
Note: Ensure that you use the multicast mode on the NLB cluster. Cisco recommends that you DO NOT use multicast MAC addresses that begin with 01 because they are known to have a conflict with the IGMP setup.
似乎微軟那邊也開始改用 03:BF:(Your IPv4 address, 剛好四碼) 當成你 NLB 的 multicast mac address, 不再是用 01:00:5E 開頭了… 此資訊供 NLB 使用者參考. 不過若 mac address 改來改去的, 我想管上層 router 的人可能會被煩死 囧rz

Microsoft NLB from CISCO

Microsoft NLB from CISCO

(OK, 如果再往下走, 您必須了解 ethernet 的 switching 方式, 不然恐怕也會一知半解, 看不到問題在哪)

第二, multicast mac address 在 LAN 很容易造成 flooding. 什麼? 問題又來了? 沒錯, 正因為 switch 的特性! 回想 switch 的工作原理, 它是在每個 port 上面記錄 “會出現在這個 port 的 mac address”, 記在所謂的 mac address table, 這樣 switch backplane 電路才會知道 switching path, 把 ethernet 封包準確地轉丟到某一個 port 去. 這是 “一對一” 的 table, 每個不同的 mac address 都只能對應到一個 port 上面. 而這是指面對 unicast mac address (00或其他偶數開頭的) 來講的. 各廠牌的 switch 對於 multicast mac address 的處理方式, 似乎都是以 broadcast 的方式來實作, 除非有 IGMP snooping 的功能 (例如一些帶有網管功能的中階 switch), 或是能直接寫死 mac-address table (一個 multicast mac address 能同時對到兩個以上的 ports 的高階 switch, 例如 CISCO 2950 系列似乎還不能直接這樣寫, 不管自動或寫死的都一定要用 IGMP 的方式…), 例如像上上圖裏 cisco switch 把某一 multicast mac-address 寫死對應到 fa2/3 與 fa2/4, 才會真正做到 “多點轉送” 而非 “塞死人不償命的廣播” 方式. 幸好若以 web server 的 traffic pattern 而言是極不對稱的流量: inbound(流入) 比 outbound(流出) 我的經驗大約是 1 比 10 左右; Flooding 是發生在 inbound, 雖然無形中增加了非叢集內其他 server(s) 的 garbage packet loading, 但還不致於造成太大的負擔. 但, 即使 flooding 的問題有解決或問題不大, 在此您可能已經又看到一個問題了: 對於叢集內的 servers 而言, 這仍然是 flooding! 這樣的 multicast 應用, 站在單一主機的角度來看, 當您叢集內的主機愈多, 真正該它服務的 connection request 比例會愈來愈低, 其他不需要它服務的封包收了都是垃圾要丟掉! 叢集愈大, 每一台 server 的 overhead 也跟著變大. 那, 如果 NLB 裏有10台的 web servers 呢? 這時若從 switch 的角度來看, 這些 server 的 inbound 與 outbound 流量已經差不多高了.

NLB Switch Setup

NLB Switch Setup

不只是我在抱怨, 隨便像國外的網路廠商也在幹樵: “看…這就是微軟的搞法…把一台好好的 switch 搞成 hub 了!”

(PS: 以上看不懂的話, 要嘛就是我寫得太爛, 要嘛就是您得先上上 CCNA 之類的課… 其他疑問的話不妨按 “上一頁” 或直接關掉 browser 最快, 因為您可能不是吃這行飯的…)

寫到這裏, 我真的愈來愈糊塗了! 為什麼要弄得這麼複雜, 這麼麻煩, 製造這麼多新奇古怪的問題? 以我近年來最常使用且最 low-tech 的 吃飯傢伙要保密吃飯傢伙要保密 而言, 單台古董級 DELL PowerEdge 1850 (Dual P4 Xeon 2.4GHz) 拿來做 load balance 前導機 (透露一下: 使用 NAT 架構, 這樣我可以順便拿它當防火牆; 現在不妨給它起個綽號叫”小玩意兒”好了), 可以達到 250 418 Mbps (2010年11月的記錄) 的流量; 且這還只是未開 jumbo frame 的效能ㄛ (因為我是個很懶得調校效能的人 XD), concurrent connection 數高達好幾萬, 可以記超過 10 萬筆 connection status, 完全沒用到什麼 multicast, heartbeat, IGMP…blahblah 的艱澀技術, 群內各 web server 不必只是為了叢集問題而刻意多加網卡, 不必多加 driver, 不必多吃 mac address 不必多加 IP, 更不會造成 router/switch 或其他 server 的額外負擔, 更不用去找您的上層 router 求管理者加 static arp entry (通常這已經有點違反他們的安全政策了); 而分配 loading 的演算法也多達八九種, 完全透明公開任君挑選. 重點是也不用管屁股後面的 server 用的是什麼 OS 什麼 AP, 您愛用 WS2008 或 RHEL5 或 IIS7 或 Apache 都隨便您啦…有本事您可以養兩個 team 寫兩套平台: URL schema 一模一樣但一套是 IIS/ASP 另一套是 Apache/PHP 的 heterogeneous/hybrid/whatever architecture 出來, 我照樣給您搞出 load balance! 而我這些 “小玩意兒” 之間更可以做到雙機間 failover (一台上線搭一台備用), 甚至多機間 failover (例如兩台上線搭一台備用, 甚至兩台以上上線同時也互為彼此間的備用).

可能唯一的缺點就是這 “小玩意兒” 因為是 NAT 架構, 本身會變成是 bottleneck? 不過, 看, 這種規格的”小玩意兒”賣到市場上每台單價少說也是上百萬等級的, 您試試看拿一台 DELL 1850 的錢去買不管買到什麼鬼東西, 保證流量或session數不到一半甚至只要十分之一有的就馬上變趴趴熊了! 如果真的想提高流量瓶頸限制, 方法實在是很多, 不管是買台更暴力的機器, 或是分散成好幾台…都是很容易的; 我腦袋裏已經存有很多種 configurations 都可以辦到, 只是要看實際整體網站的大架構來加以運用. 我在海峽兩岸不同的機房都有佈置這”小玩意兒”, 其中一地的”小玩意兒”背後放了三四十台 servers (至少2/3都是對外的 web servers), 另一地的”小玩意兒”更特別的是接了五條 uplinks 走不同的路由, 以服務來自不同ISP的上網使用者 (感謝 Cisco C3750G 的加持, 完全不用多加網卡), 當然背後也是有超過 20 台的 servers 在支撐兩三百M的流量… 各位要不要想像一下同時20台30台 web servers 加入 Microsoft NLB 同一叢集的”盛況”呢? 就一顆 24 port 的 switch 而言, 不管有沒有開 IGMP snooping, 都等同於當 hub 在用了 (multicast 等於 broadcast 了!) 而且因為20台30台的關係, 你會在 switch 上看到各埠的流出流量 (即 web server 的 inbound) 比流入流量 (即 web server 的 outbound) 高出許多!

(拷, 我若一年賣一台這個”小玩意兒”的話…我也能年薪百萬ㄟ…一年賣兩台就年薪兩百萬了… 無奈老闆們沒看到牌子沒人會信, 要掛上 CISCO 或 Microsoft 才有說服力 orz)

其他例如 Piranha 或 Ultra Monkey 相信也都是 Linux 界人仕耳熟能詳的叢集工具. 當然, 您也可以土法鍊鋼直接玩 LVS: Linux Virtual Server NAT/TUN/DR 模式等等, 但不免需要親自做一些比較繁雜的設定, 甚至還要自己在每台 server 上把什麼 arp reply 的功能關掉等等… 但以上可能都比 Microsoft NLB 簡單多了 (不過在我來看 UltraMonkey 也差不多是天書了)

至於 Windows NLB 倒底是什麼東西? 工作原理是什麼? 一開始我真的很想了解, 而且我真的開始了解了, 但在了解之後我又不太想花時間再深入了解了… 我是個很討厭不求甚解的人, 我花了很多時間 google 關於 NLB 的東西, 得到的幾乎都是文宣等級或教科書似的文章. 微軟陣營的論壇或民間討論區, 沒找到有誰或哪篇文章主動把問題點出來, 更別提分享解法的了. 最後還是在 CISCO 陣營, 不管是官方文件, 或是討論區裏, 都有點出 NLB 的問題與 “workaround”, 多可愛啊.

後記: 後來我又找了一堆資料, 加上實地的觀摩與嚐試, 上述一些觀念多少有些需要修正與進一步細述的地方, 尤其是問題處理方面, 我已經得到十足正確的解答了; 總之, 我的結論還是, stay on Linux :p