做了「負載均衡」就可以隨便加機器了嗎?這三招來幫你!

来源:https://www.cnblogs.com/Zachary-Fan/archive/2018/11/06/LoadBalance2.html
-Advertisement-
Play Games

本文長度為3056字,預計讀完需1.1MB流量,建議閱讀8分鐘。 閱讀目錄 什麼是Session丟失? nginx是如何來解決這個問題的? Session保持的其它方案 結語 什麼是Session丟失? nginx是如何來解決這個問題的? Session保持的其它方案 結語 什麼是Session丟失 ...


本文長度為3056字,預計讀完需1.1MB流量,建議閱讀8分鐘。

 

閱讀目錄

 

        這篇是《分散式關註點系列》中「負載均衡」相關的內容最後一發了,後續也會繼續講「高可用」相關的其它主題,主要是限流、降級、熔斷之類的吧,具體還沒定。文末先附上之前發過的高可用相關文章,供你再溫故一下。

 

        下麵這個場景不知是否在你面前出現過。

 

開發Z哥對運維Y弟喊:“Y弟,現在系統好卡,剛上了一波活動,趕緊幫我加幾台機器上去頂一下。”

 

Y弟回覆說:“沒問題,分分鐘搞定”。

 

然後就發現資料庫的壓力迅速上升,DBA就吼了:“Z哥,你丫的搞什麼呢?資料庫要被你弄垮了”。

 

然後客服那邊接框也爆炸了,越來越多的用戶說剛登陸後沒多久,操作著就退出了,接著登陸,又退出了,到底還做不做生意了。

 

        這些問題背後都是由於一個「Session丟失」問題導致的。

 

 

一、什麼是Session丟失

 

        相信Session對大部分Coder來說應該都知道。它是為了將同一個用戶的多次訪問在系統中被識別為“同一個用戶”而產生的概念。除此之外,還可以基於它來減少重覆往DB或者遠程服務處獲取與該用戶相關的信息,以起到提升性能的作用。

 

        在我們做了負載均衡的場景中,如果選擇的負載策略是hash策略,那麼會使得Session產生一個副作用,這個副作用就如上面舉的案例那樣,用戶一旦由於某種原因從原先訪問伺服器A變成訪問伺服器B,就會出現“登陸狀態丟失”、“緩存穿透”等問題

 

        為什麼hash策略會出現這個問題呢?首先有必要先瞭解一下hash是如何進行的。hash策略就是下圖這樣的一個散列函數。在函數不變的情況下,A永遠對應01,B對應04,C對應08。

 

▲圖片來源於網路,版權歸原作者所有

 

        以nginx中的ip_hash策略來舉個例子。因為我們認為正常情況下用戶的ip不會在短時間內發生變化,所以當我們選擇使用ip_hash策略進行負載均衡時,意味著期望同一個用戶能夠一直訪問到同一臺伺服器上,就像下圖這樣。

 

▲圖中的hash函數是最簡單的隨意舉例

 

        如此一來,我們只需要在這一臺伺服器上將這個用戶相關的信息緩存在進程內,就能起到非常高性價比的提升性能的效果。

 

        這時,客戶端與服務端之間的相當於建立了一個信任,相互認識。這個信任就是「Session」。

 

        但是,當我們加了一臺伺服器之後,事情就發生變化了。

 

▲圖中的hash函數是最簡單的隨意舉例

 

        這個時候我們原先的預期就被破壞了。因為用戶與序號0節點的鏈接變成了與序號3的鏈接,所以產生了前面提到的「Session丟失」問題。與此同時,在序號0節點上做的進程內緩存都無效了,而在序號3節點上又沒有用戶相關的任何緩存,導致大量數據需要從下游的DB或者遠程服務處獲取。你要知道,一旦涉及到網路通信,性能必然明顯下降,I/O、序列化都是耗時的工作。更重要的是,一旦同時有大量用戶產生這個情況,由於後端的DB和遠程服務瞬時無法承載激增的高密度請求,可能會導致它掛起。這還沒完,如果當前程式沒有一些故障隔離或者降級策略,還會進一步產生蝴蝶效應,導致整個大系統響應緩慢。可謂“一顆老鼠屎壞了一鍋粥”。

 

 

二、nginx是如何來解決這個問題的

        既然以nginx舉例,還是從nginx開始聊。通過在nginx中引入nginx-sticky-module模塊可以來解決這個問題。解決的整個過程如下。

 

▲圖片來源於網路,版本歸原作者所有

 

        可以看到,當client第一次進入到nginx匹配節點的時候,在給它分配一個節點的同時,會將這個節點的唯一標識進行md5後寫入到cookie中一併返回,如果下次再發起請求的時候發現帶有這個cookie值,就直接轉發到該值所對應的節點上去。這個機制被專業的稱之為「Session保持」。

 

        雖然可以利用cookie來解決這個問題,但是cookie也有一個潛在的問題,如果客戶端未開啟cookie功能,這個機制就失效了。不過好在目前主流瀏覽器都是預設打開cookie的。

 

題外話:nginx是2004年發佈的,在nginx-sticky-module出現之前的7年間也是nginx相比競品HAProxy最大的一個短板,因為HAProxy支持Session保持。

 

 

三、Session保持的其它方案

        除了cookie之外,還有2種方式也可以最終達到類似的效果。分別被稱為「Session複製」、「Session共用」。

 

01  Session複製

        這是最簡單粗暴的方式。根據第一節的案例來看,導致問題的原因是節點3沒有用戶的Session。那麼很容易想到,在節點3運行之前把Session相關的Cache數據複製過去唄。並且在多個節點之間持續保證數據的同步,也就是說,每一臺節點上都存在每個用戶的Session數據。

 

 

        實現的方案有很多,特別是不同的宿主程式都或多或少提供了一些切入點,甚至是拿來即用的方案,如Tomcat的Delta Manager和Backup Manager、Tomcat和IIS的Filter機制等等,這裡就不展開了。

 

        此類方案的特點是

  • 優點:天然高可用,一部分節點宕機沒事。因為每一個節點上存放著所有已連接用戶的會話信息。

  • 缺點:因為每台電腦的記憶體是有上限的,僅適用於會話相關的數據大小較小的場景。並且,由於多個節點之間需要同步數據,需要額外解決數據一致性問題。與此同時,隨著節點越多,損耗越大(延遲、帶寬等),有廣播風暴風險。

 

02  Session共用

        我們還可以通過將session信息存放到全局共用的存儲介質中來達到一樣的效果,如資料庫、遠程緩存等,這是一種中心化思想的解決方案。

 

        此類方案的特點是

  • 優點:不管節點怎麼增加和減少,100%不會產生會話丟失。

  • 缺點:每次讀寫請求都需要增加額外共用儲存調用,增加了網路I/O、序列化等操作,性能明顯下降。另外,用作共用的存儲介質除了增加了額外的維護成本外,還需要解決單點問題,以免產生系統性風險。

 

        同之前「Session保持」方案一起對比下各自的優缺點和適用場景。

 

        分別用一句話概括一下這3個方案:

  • Session 保持。原來在哪還是去哪。

  • Session 複製。不管在哪都有一樣的數據。

  • Session 共用。所有節點共用一份數據。

 

 

        越大型的系統,最終都會往「Session共用」這個方案上走,因為只要再對這個共用存儲做橫向擴展,理論上就可以支撐無窮大的用戶了。如Redis、一系列的NOSQL以及NEWSQL等。就像下麵這樣,集「規模大」、「高可用」、「效果好」於一身。

 

 

 

四、結語

        現在你應該清楚了Session丟失問題,也知道瞭如何去應對他。但是,我們還需要明白一個事實:嚴格來說「Session保持」本質上是破壞了做「負載均衡」的初衷。舉個極端點的場景:一共有10個會話連在了節點A上,並且都是活動中狀態。那麼這個時候哪怕增加一個節點B上線,只要沒有新的會話進來,節點B上的活動連接數永遠是0,並沒有起到分擔壓力的作用。

        但是,在系統的起步時期,其實用這樣簡單的方案也是極好的。

 

 

 

相關文章:

 

作者:Zachary(個人微信號:Zachary-ZF)

微信公眾號(首發):跨界架構師<-- 點擊後閱讀熱門文章,或右側掃碼關註 -->

定期發表原創內容:架構設計丨分散式系統丨產品丨運營丨一些深度思考

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 主要是通過定位找到需要指引的目標元素,然後再在蒙版上畫一個div,設置為白色,定位到目標元素位置。思路大概就是這樣。 圖一: 圖二: 圖三: 代碼如下: 實現效果如圖二、圖三所示。 ...
  • 一,效果圖。 二,代碼。 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>html 框架</title> </head> <body> <!--iframe 設置高度與寬度--> <iframe src="demo_iframe ...
  • 主要的代碼: var body = layer.getChildFrame('body', index); var iframeWin = window[layero.find('iframe')[0]['name']];//得到iframe頁的視窗對象,執行iframe頁的方法: var comp ...
  • 構造函數擁有名為prototype屬性,每個對象都擁有__proto__屬性,而且每個對象的__proto__屬性指向自身構造函數prototype。 當調用某種方法或屬性時,首先會在自身調用或查找,如果自身沒有該屬性或者方法,則會去它的__proto__屬性中調用查找,也就是它構造函數的proto ...
  • JavaScript: 知識點回顧篇(九):Window 對象、Navigator 對象 ...
  • 實現微信分享功能整理 1、引入js文件 2、通過config介面註入許可權驗證配置 3、config信息驗證後會執行ready方法,所有介面調用都必須在config介面獲得結果之後,config是一個客戶端的非同步操作,所以如果需要在頁面載入時就調用相關介面,則須把相關介面放在ready函數中調用來確保 ...
  • 本文主要介紹怎麼在el tree組件中通過render函數來el button。 這是element ui中el tree樹: 這是需要實現的效果: tree.vue文件中,具體實現的代碼如下: 主要說下這段代碼: 文檔中有詳細的說明:https://cn.vuejs.org/v2/guide/re ...
  • /* *js格式化數字代碼 * *value: 要格式化的數字值 *scale: 最多保留幾位小數 *zeroed: 是否保留尾0 *percented: 是否轉稱百分比形式 * */ function formatNumber(value, scale, zeroed, percented){ i ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...