關於大型網站技術演進的思考(一)--存儲的瓶頸(1)

来源:http://www.cnblogs.com/moyhui/archive/2016/04/20/5412087.html
-Advertisement-
Play Games

前不久公司請來了位互聯網界的技術大牛跟我們做了一次大型網站架構的培訓,兩天12個小時信息量非常大,知識的廣度和難度也非常大,培訓完後我很難完整理出全部聽到的知識,今天我換了個思路是回味這次培訓,這個思路就是通過本人目前的經驗和技術水平來思考下大型網站技術演進的過程。 首先我們要思考一個問題,什麼樣的 ...


前不久公司請來了位互聯網界的技術大牛跟我們做了一次大型網站架構的培訓,兩天12個小時信息量非常大,知識的廣度和難度也非常大,培訓完後我很難完整理出全部聽到的知識,今天我換了個思路是回味這次培訓,這個思路就是通過本人目前的經驗和技術水平來思考下大型網站技術演進的過程。

  首先我們要思考一個問題,什麼樣的網站才是大型網站,從網站的技術指標角度考慮這個問題人們很容易犯一個毛病就是認為網站的訪問量是衡量的指標,懂點行的人也許會認為是網站在單位時間里的併發量的大小來作為指標,如果按這些標準那麼像hao123這樣的網站就是大型網站了,如下圖所示:

 

  其實這種網站訪問量非常大,併發數也非常高,但是它卻能用最為簡單的web技術來實現:我們只要保持網站的充分的靜態化,多部署幾台伺服器,那麼就算地球上所有人都用它,網站也能正常運行。

  我覺得大型網站是技術和業務的結合,一個滿足某些用戶需求的網站只要技術和業務二者有一方難度很大,必然會讓企業投入更多的、更優秀的人力成本實現它,那麼這樣的網站就是所謂的大型網站了。

  一個初建的網站往往用戶群都是很小的,最簡單的網站架構就能解決實際的用戶需求,當然為了保證網站的穩定性和安全性,我們會把網站的應用部署到至少兩台機器上,後臺的存儲使用資料庫,如果經濟實力允許,資料庫使用單台伺服器部署,由於數據是網站的生命線,因此我們常常會把部署資料庫的伺服器使用的好點,這個網站結構如下所示:

 

  這個結構非常簡單,其實大部分初建網站開發里往往業務邏輯沒有企業級系統那麼複雜,所以只要有個好的idea,建設一個新網站的成本是非常低的,所使用的技術手段也是非常的基本和簡單,不過該圖我們要準備三台伺服器,而且還要租個機房放置我們的伺服器,這些成本對於草根和屌絲還是非常高的,幸運的是當下很多大公司和機構提供了雲平臺,我們可以花費很少的錢將自己的應用部署到雲平臺上,這種做法我們甚至不用去考慮把應用、資料庫分開部署的問題,更加進一步的降低了網站開發和運維的成本,但是這種做法也有一個問題,就是網站的小命被這個雲平臺捏住了,如果雲平臺掛了,俺們的網站服務也就跟著掛了。

  這裡我先講講自己獨立使用伺服器部署網站的問題,如果我們要把網站服務應用使用多台伺服器部署,這麼做的目的一般有兩個:

  1. 保證網站的可用性,多台伺服器部署應用,那麼其中一些伺服器掛掉了,只要網站還有伺服器能正常運轉,那麼網站對外任然可以正常提供服務。
  2. 提高網站的併發量,伺服器越多那麼網站能夠服務的用戶,單位時間內能承載的請求數也就越大。

  不過要做到以上兩點,並不是我們簡單將網站分開部署就可以滿足的,因為大多數網站在用戶使用時候都是要保持用戶的狀態,具體點就是網站要記住請求是歸屬到那一個客戶端,而這個狀態在網站開發里就是通過會話session來體現的。分開部署的web應用服務要解決的一個首要問題就是要保持不同物理部署伺服器之間的session同步問題,從而達到當用戶第一次請求訪問到伺服器A,第二個請求訪問到伺服器B,網站任然知道這兩個請求是同一個人,解決方案很直接:伺服器A和伺服器B上的session信息要時刻保持同步,那麼如何保證兩台伺服器之間session信息的同步呢?

  為了回答上面的問題,我們首先要理解下session的機制,session信息在web容器里都是存儲在記憶體里的,web容器會給每個連接它的客戶端生成一個sessionid值,這個sessionid值會被web容器置於http協議里的cookie域下,當響應被客戶端處理後,客戶端本地會存儲這個sessionid值,用戶以後的每個請求都會讓這個sessionid值隨cookie一起傳遞到伺服器,伺服器通過sessionid找到記憶體中存儲的該用戶的session內容,session在記憶體的數據結構是一個map的格式。那麼為了保證不同伺服器之間的session共用,那麼最直接的方案就是讓伺服器之間session不斷的傳遞和複製,例如java開發里常用的tomcat容器就採用這種方案,以前我測試過tomcat這種session同步的性能,我發現當需要同步的web容器越多,web應用所能承載的併發數並沒有因為伺服器的增加而線性提升,當伺服器數量達到一個臨界值後,整個web應用的併發數甚至還會下降,為什麼會這樣了?

  原因很簡單,不同伺服器之間session的傳遞和複製會消耗伺服器本身的系統資源,當伺服器數量越大,消耗的資源越多,當用戶請求越頻繁,系統消耗資源也會越來越大。如果我們多部署伺服器的目的只是想保證系統的穩定性,採用這種方案還是不錯的,不過web應用最好部署少點,這樣才不會影響到web應用的性能問題,如果我們還想提升網站的併發量那麼就得採取其他的方案了。

  時下使用的比較多的方案就是使用獨立的緩存伺服器,也就是將session的數據存儲在一臺獨立的伺服器上,如果覺得存在一臺伺服器不安全,那麼可以使用memcached這樣的分散式緩存伺服器進行存儲,這樣既可以滿足了網站穩定性問題也提升了網站的併發能力。

  不過早期的淘寶在這個問題解決更加巧妙,他們將session的信息直接存儲到瀏覽器的cookie里,每次請求cookie信息都會隨著http一起傳遞到web伺服器,這樣就避免了web伺服器之間session信息同步的問題,這種方案會讓很多人詬病,詬病的原因是cookie的不安全性是總所周知的,如果有人惡意截取cookie信息那麼網站不就不安全了嗎?這個答案還真不好說,但是我覺得我們僅僅是跟蹤用戶的狀態,把session存在cookie里其實也沒什麼大不了的。

  其實如此專業的淘寶這麼做其實還是很有深意的,還記得本文開篇提到的hao123網站,它是可以承載高併發的網站,它之所以可以做到這一點,原因很簡單它是個靜態網站,靜態網站的特點就是不需要記錄用戶的狀態,靜態網站的伺服器不需要使用寶貴的系統資源來存儲大量的session會話信息,這樣它就有更多系統資源來處理請求,而早期淘寶將cookie存在客戶端也是為了達到這樣的目的,所以這個方案在淘寶網站架構里還是使用了很長時間的。

  在我的公司里客戶端的請求到達web伺服器之前,會先到F5,F5是一個用來做負載均衡的硬體設備,它的作用是將用戶請求均勻的分發到後臺的伺服器集群,F5是硬體的負載均衡解決方案,如果我們沒那麼多錢買這樣的設備,也有軟體的負載均衡解決方案,這個方案就是大名鼎鼎的LVS了,這些負載均衡設備除了可以分發請求外它們還有個能力,這個能力是根據http協議的特點設計的,一個http請求從客戶端到達最終的存儲伺服器之前可能會經過很多不同的設備,如果我們把一個請求比作高速公路上的一輛汽車,這些設備也可以叫做這些節點就是高速路上的收費站,這些收費站都能根據自己的需求改變http報文的內容,所以負載均衡設備可以記住每個sessionid值對應的後臺伺服器,當一個帶有sessionid值的請求通過負載均衡設備時候,負載均衡設備會根據該sessionid值直接找到指定的web伺服器,這種做法有個專有名詞就是session粘滯,這種做法也比那種session信息在不同伺服器之間拷貝複製要高效,不過該做法還是比存cookie的效率低下,而且對於網站的穩定性也有一定影響即如果某台伺服器掛掉了,那麼連接到該伺服器的用戶的會話都會失效。

  解決session的問題的本質也就是解決session的存儲問題,其本質也就是解決網站的存儲問題,一個初建的網站在早期的運營期需要解決的問題基本都是由存儲導致的。上文里我提到時下很多新建的web應用會將伺服器部署後雲平臺里,好的雲平臺里或許會幫助我們解決負載均衡和session同步的問題,但是雲平臺里有個問題很難解決那就是資料庫的存儲問題,如果我們使用的雲平臺發生了重大事故,導致雲平臺存儲的數據丟失,這種會不會導致我們在雲平臺里資料庫的信息也會丟失了,雖然這個事情的概率不高,但是發生這種事情的幾率還是有的,雖然很多雲平臺都聲稱自己多麼可靠,但是真實可靠性有多高不是局中人還真不清楚哦,因此使用雲平臺我們首要考慮的就是要做好數據備份,假如真發生了數據丟失,對於一個快速成長的網站而言可能非常致命。

  寫到這裡一個嬰兒般的網站就這樣被我們創造出來了,我們希望網站能健康快速的成長,如果網站真的按我們預期成長了,那麼一定會有一天我們製造的寶寶屋已經滿足不了現實的需求,這個時候我們應該如何抉擇了?換掉,全部換掉,使用新的架構例如我們以前長提的SOA架構,分散式技術,這個方法不錯,但是SOA和分散式技術是很難的,成本是很高的,如果這時候我們通過添加幾台伺服器就能解決問題的話,我們絕對不要去選擇什麼分散式技術,因為這個成本太高了。上面我講到幾種session共用的方案,這個方案解決了應用的水平擴展問題,那麼當我們網站出現瓶頸時候就多加幾台伺服器不就行了嗎?那麼這裡就有個問題了,當網站成長很快,網站首先碰到的瓶頸到底是哪個方面的問題?

  本人是做金融網站的,我們所做的網站有個特點就是當用戶訪問到我們所做的網站時候,目的都很明確就是為了付錢,用戶到了我們所做的網站時候都希望能快點,再快點完成本網站的操作,很多用戶在使用我們做的網站時候不太去關心網站的其他內容,因此我們所做的網站相對於資料庫而言就是讀寫比例其實非常的均勻,甚至很多場景寫比讀要高,這個特點是很多專業服務網站的特點,其實這樣的網站和企業開發的特點很類似:業務操作的重要度超過了業務展示的重要度,因此專業性網站吸納企業系統開發的特點比較多。但是大部分我們日常常用的網站,我們逗留時間很長的網站按資料庫角度而言往往是讀遠遠大於寫,例如大眾點評網站它的讀寫比率往往是9比1。

  12306或許是中國最著名的網站之一,我記得12306早期經常出現一個問題就是用戶登錄老是登不上,甚至在高峰期整個網站掛掉,頁面顯示503網站拒絕訪問的問題,這個現象很好理解就是網站併發高了,大量人去登錄網站,購票,系統掛掉了,最後所有的人都不能使用網站了。當網站出現503拒絕訪問時候,那麼這個網站就出現了最致命的問題,解決大用戶訪問的確是個超級難題,但是當高併發無法避免時候,整個網站都不能使用這個只能說網站設計上發生了致命錯誤,一個好的網站設計在應對超出自己能力的併發時候我們首先應該是不讓他掛掉,因為這種結果是誰都不能使用,我們希望那些在可接受的請求下,讓在可接受請求範圍內的請求還是可以正常使用,超出的請求可以被拒絕,但是它們絕對不能影響到全網站的穩定性,現在我們看到了12306網站的峰值從未減少過,而且是越變越多,但是12306出現全站掛掉的問題是越來越少了。通過12036網站改變我們更進一步思考下網站的瓶頸問題。

  排除一些不可控的因素,網站在高併發下掛掉的原因90%都是因為資料庫不堪重負所致,而應用的瓶頸往往只有在解決了存儲瓶頸後才會暴露,那麼我們要升級網站能力的第一步工作就是提升資料庫的承載能力,對於讀遠大於寫的網站我們採取的方式就是將資料庫從讀寫這個角度拆分,具體操作就是將資料庫讀寫分離,如下圖所示:

 

  我們這時要設計兩個資料庫,一個資料庫主要負責寫操作我們稱之為主庫,一個資料庫專門負責讀操作我們稱之為副庫,副庫的數據都是從主庫導入的,資料庫的讀寫分離可以有效的保證關鍵數據的安全性,但是有個缺點就是當用戶瀏覽數據時候,讀的數據都會有點延時,這種延時比起全站不可用那肯定是可以接受的。不過針對12306的場景,僅僅讀寫分離還是遠遠不夠的,特別是負責讀操作的副庫,在高訪問下也是很容易達到性能的瓶頸的,那麼我們就得使用新的解決方案:使用分散式緩存,不過緩存的缺點就是不能有效的實時更新,因此我們使用緩存前首先要對讀操作的數據進行分類,對於那些經常不發生變化的數據可以事先存放到緩存里,緩存的訪問效率很高,這樣會讓讀更加高效,同時也減輕了資料庫的訪問壓力。至於用於寫操作的主庫,因為大部分網站讀寫的比例是嚴重失衡,所以讓主庫達到瓶頸還是比較難的,不過主庫也有一個讀的壓力就是主庫和副庫的數據同步問題,不過同步時候數據都是批量操作,而不是像請求那樣進行少量數據讀取操作,讀取操作特別多,因此想達到瓶頸還是有一定的難度的。聽人說,美國牛逼的facebook對數據的任何操作都是事先合併為批量操作,從而達到減輕資料庫壓力的目的。

  上面的方案我們可以保證在高併發下網站的穩定性,但是針對於讀,如果數據量太大了,就算網站不掛掉了,用戶能很快的在海量數據里檢索到所需要的信息又成為了網站的一個瓶頸,如果用戶需要很長時間才能獲得自己想要的數據,很多用戶會失去耐心從而放棄對網站的使用,那麼這個問題又該如何解決了?

  解決方案就是我們經常使用的百度,谷歌哪裡得來,對於海量數據的讀我們可以採用搜索技術,我們可以將資料庫的數據導出到文件里,對文件建立索引,使用倒排索引技術來檢索信息,我們看到了百度,谷歌有整個互聯網的信息我們任然能很快的檢索到數據,搜索技術是解決快速讀取數據的一個有效方案,不過這個讀取還是和資料庫的讀取有所區別的,如果用戶查詢的數據是通過資料庫的主鍵欄位,或者是通過很明確的建立了索引的欄位來檢索,那麼資料庫的查詢效率是很高的,但是使用網站的人跟喜歡使用一些模糊查詢來查找自己的信息,那麼這個操作在資料庫里就是個like操作,like操作在資料庫里效率是很低的,這個時候使用搜索技術的優勢就非常明顯了,搜索技術非常適合於模糊查詢操作。

  OK,很晚了,關於存儲的問題今天就寫在這裡,下一篇我將接著這個主題講解,解決存儲問題是很複雜的,下篇我儘量講仔細點。

                                                                          

                                                          原文地址:http://www.cnblogs.com/sharpxiajun/p/4237704.html


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

-Advertisement-
Play Games
更多相關文章
  • 在JDBC應用中,如果你已經是稍有水平開發者,你就應該始終以PreparedStatement代替Statement.也就是說,在任何時候都不要使用Statement一.代碼的可讀性和可維護性.雖然用PreparedStatement來代替Statement會使代碼多出幾行,但這樣的代碼無論從可讀性 ...
  • 學習如何使用Swift寫項目 一.搭建微博項目的主框架 1.1--搭建功能模塊 1.2--在 AppDelegate 中的 didFinishLaunchingWithOptions 函數,設置啟動控制器 1.3--在MainViewController.swift中添加子控制器 二.如何動態的創建 ...
  • 直接看這裡,省的搬過來。。 ...
  • 1 Private Sub SaveAndClear() 2 3 Dim Header, Deatil, Order As Range 4 Dim lastrow1, lastrow2 As Long 5 Dim i As Integer 6 7 lastrow1 = Sheet1.[B65536] ...
  • python轉換已轉義的字元串 有時我們可能會獲取得以下這樣的字元串: Python代碼 >>> a = '{\\"name\\":\\"michael\\"}' >>> print a {\"name\":\"michael\"} Python代碼 Python代碼 那麼該如何將其轉換為一個字典呢 ...
  • Php代碼 <?php /** * 助手類 * @author www.shouce.ren * */ class Helper { /** * 判斷當前伺服器系統 * @return string */ public static function getOS(){ if(PATH_SEPARAT ...
  • 返回目錄 再說概念 這兩個模式確實有點相似,都為了實現程式的解耦產生的,觀察者一般又稱發佈/訂閱模式,它一般是有一個主題對象,然後有多個訂閱者去關註它,當它的狀態發生變化時,會自動通知這些訂閱者;而消費者模式類似一個緩存隊列的概念,它也稱為生產者/消費者模式,生產者只負責生產數據不去做處理(緩解高並 ...
  • 代理模式(Proxy) 定義 代理模式(Proxy),為其他對象提供一種代理以控制對這個對象的訪問。 類圖 描述 Subject,定義了ConcreteSubject和Proxy的共用介面,這樣就可以在任何使用ConcreteSubject的地方使用Proxy; Proxy,保存一個Concrete ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...