作為后端應用的開發(fā)者,我們經(jīng)常開發(fā)、調(diào)試、測試完我們的應用并發(fā)布到生產(chǎn)環(huán)境,用戶就可以直接訪問到我們的應用了。但對于互聯(lián)網(wǎng)應用,在你的應用和用戶之間還隔著一層低調(diào)的或厚或薄的負載均衡層軟件,它們不顯山不露水默默的發(fā)揮著重要的作用,以至于我們經(jīng)常忽略了它們的存在。因為負載均衡層通常不在一般開發(fā)人員的問題域內(nèi),而且它們一般都是現(xiàn)成且成熟的解決方案,以至于我們習慣性的忽略和認為乏善可陳。其實不然,本文就寫寫我對負載均衡層次結(jié)構(gòu)的認知和理解。
硬負載
所謂「硬負載」就是采用硬件設(shè)備來提供負載均衡。
在七、八年前那時我在做 Java 的企業(yè)軟件開發(fā),開發(fā)出來的企業(yè)級 Java 應用程序就部署在像 Weblogic 之類的應用容器中。而這類應用容器軟件又跑在 Unix 的小型機上。把硬件和軟件一體打包作為企業(yè)應用解決方案賣給客戶。這類應用部署的方案十分簡單,層級也比較淺。為了保證可靠性,使用兩套小型機上各部署一個 Weblogic Server,在應用服務前面使用像 F5 之類的硬件負載均衡器,如下圖所示。
由于小型機和前面的 F5 負載均衡硬件都比較貴,所以出于可靠性、可維護性和成本的綜合考慮,一般應用部署兩套跑在兩臺小型機上,在前面共享一個 F5 做負載均衡。而一般 F5 和小型機這類硬件設(shè)備都至少是 5 個 9 的可靠性保障,所以整體的系統(tǒng)可靠性基本有保障。
進入互聯(lián)網(wǎng)時代后,應用開發(fā)擁抱開源,部署使用更廉價的 PC Server 和免費開源的應用容器。負載均衡也逐步從硬負載向軟負載變遷,由于互聯(lián)網(wǎng)應用的海量特性和部署規(guī)模的急劇膨脹,前端負載均衡也開始變得豐富起來。
軟負載
進入互聯(lián)網(wǎng)公司后,我們剛開始開發(fā)應用時,業(yè)務規(guī)模小用戶量還不大,機器數(shù)量也少(<10)。所以一開始的負載均衡的結(jié)構(gòu)也是很簡單的,類似硬負載只是把硬件換成了免費的開源軟件并跑在可用性是有 3 個 9 的廉價 PC Server 上。
前面一個 LVS 后面跟著幾個應用服務,后來為了方便做按域名的分流和適配切流量上線,中間又加了一層 Nginx。
這樣就變成了兩層軟負載結(jié)構(gòu)了,LVS 負責 4 層,Nginx 負責 7 層。 但 Nginx 只負責了單機內(nèi)多實例的負載均衡,這里主要是因為當時 PC Server 是物理機,CPU 16/32 core,內(nèi)存 32/64G 不等,為了更充分的利用資源,一臺物理機上都部署了多個應用服務實例,而考慮到 Nginx 工作在 7 層的開銷遠高于 LVS/DR 模式,所以一般在一個 Nginx 后面掛的實例數(shù)也不會超過 10 個。
但隨著業(yè)務發(fā)展和用戶流量上升,機器規(guī)模也在不斷擴張,導致一個網(wǎng)段內(nèi)的 IP 都不夠用了,這套負載結(jié)構(gòu)又遇到了橫向擴展的瓶頸,因為 LVS/DR 模式下跨不了網(wǎng)段。所以后來又在 LVS 和 Nginx 之間加了一層 HAProxy,負載結(jié)構(gòu)就變成了下面這樣。
其實加了 HAProxy 之后,它也是工作在 7 層,這樣 Nginx 這層看起來就不是很有必要。但三層的負載結(jié)構(gòu)能支撐更大規(guī)模的集群,而原本在 Nginx 層做了一套方便研發(fā)切流量上線的運維管理系統(tǒng),所以犧牲一點性能換取現(xiàn)在的可維護性和將來擴展性,Nginx 這層就一直保留下來了。而且 Nginx 相比 HAProxy 不是純粹的負載均衡器,它還能提供 cache 功能,對于某些 HTTP 請求實際只走到 Nginx 這層就可以通過緩存命中而返回。
DNS負載
隨著業(yè)務發(fā)展,公司開始了多個 IDC 的建設(shè),考慮到 IDC 級別的容災,集群開始部署到多個 IDC。跨 IDC 的負載均衡方案可以簡單通過 DNS 輪詢來實現(xiàn),但可控性不好。所以我們沒有采用這種,而是采用一主加多子域名的方式來基于業(yè)務場景實現(xiàn)動態(tài)域名調(diào)度和負載。主域名下實際是一個動態(tài)流量調(diào)度器,跨多個 IDC 部署,對于 HTTP 請求基于重定向方式跳子域名,對于 TCP 方式每次建立長連接前請求分配實際連接的子域名,如下圖所示。
CDN負載
最后再加上互聯(lián)網(wǎng)應用必不可少的 CDN 將靜態(tài)資源請求的負載分流,那么整個負載的層次結(jié)構(gòu)就完整了。
SSL 帶來的負載結(jié)構(gòu)變化
隨著互聯(lián)網(wǎng)的普及,安全問題益發(fā)嚴重,原本早期只有銀行網(wǎng)銀等使用 HTTPS 方式訪問,現(xiàn)在電商類網(wǎng)站也開始啟用全站 HTTPS 了。引入 SSL 后對負載結(jié)構(gòu)帶來了什么影響么?SSL 屬于應用層的協(xié)議,所以只能在 7 層上來做,而 HAProxy 也是支持 SSL 協(xié)議的,所以一種方式是只需簡單的讓 HAProxy 開啟 SSL 支持完成對內(nèi)解密對外加密的處理。
但 HAProxy 的作者不太贊同這種方案,因為引入 SSL 處理是有額外的性能開銷的。那么在承擔確定流量的情況下,假設(shè)原本需要 M 臺 HAProxy,在開啟了 SSL 后可能需要 M + N 臺 HAProxy。隨著流量增長,這種方式的橫向擴展成本較高(畢竟 SSL 證書按服務器數(shù)量來收費的)。他給出的解決方案是再獨立一層 SSL 代理緩存層,像下面這樣。
L4 和 L7 之間獨立的 SSL 代理緩存層只負責 SSL 協(xié)議的處理,把 HTTPS 轉(zhuǎn)換成 HTTP,并檢查本地緩存是否命中。若未命中再轉(zhuǎn)發(fā)請求到后端的 L7 層應用負載均衡層。這樣的好處是每個層次都可以根據(jù)流量來獨立伸縮,而且 SSL 層顯然可以跨多個應用共享,更節(jié)省成本。如果按這個思路來重新調(diào)整我們前面的負載均衡結(jié)構(gòu)層次,將會演變成下面這樣。
其實,這時我覺得應用前面的那層 Nginx 可能就顯得多余了點,不是必需的。但如果現(xiàn)實這么演進下來很可能就會有這么一層冗余的東西存在很長一段時間,這就是理想和現(xiàn)實之間的差距吧。
總結(jié)
好了,本文到此為止。作為一名后臺開發(fā)我其實對上面提及的各類開源軟件如何配置、調(diào)優(yōu)和管理并不熟悉,這屬于運維開發(fā)的問題域范疇。但這并不妨礙我去了解我所開發(fā)的應用所處的整個環(huán)境是怎樣的,多了解些你工作領(lǐng)域范圍邊界外的 What 和 Why,有時也能幫助我們更好的設(shè)計和解決自身問題域內(nèi)的問題,別為自己設(shè)限而最終畫地為牢。
本來以為負載均衡這個古老的課題已經(jīng)定型了,在寫本文時又看到新聞,在近日舉辦的第十三屆網(wǎng)絡(luò)系統(tǒng)設(shè)計與實現(xiàn) USENIX 研討會上,來自 Google 的工程師又分享了其自研的 Maglev 負載均衡器。剛下了論文還沒看,回頭看了再來寫寫。
參考
[1] HAProxy Documentation. HAProxy Management Guide
[2] HAProxy Documentation. HAProxy Starter Guide
[3] Willy Tarreau. Making applications scalable with Load Balancing
[4] LVS wiki. Load balancing
[5] Wikipedia. Virtual Router Redundancy Protocol
[6] shuming. LVS 工作模式以及工作原理