解決web高併發概括
所謂高併發,就是同一時間有很多流量(通常指使用者)訪問程式的介面、頁面及其他資源,解決高併發就是當流量峰值到來時保證程式的穩定性。
我們一般用QPS(每秒查詢數,又叫每秒請求數)來衡量程式的綜合性能,數值越高越好,一般需要壓測(ab工具)得到資料。
假設我們的一個程序(也可以是執行緒或者協程)處理一次請求花費了50毫秒(業內達標範圍一般是20毫秒至60毫秒),那麼1秒鐘就可以處理20個請求,一臺伺服器是可以開很多這樣的程序並行去處理請求的,比如開了128個,那麼這臺機器理論上的QPS=2560。
千萬不要小瞧這個數字,當你的QPS真有這麼高的時候意味著你的DAU(使用者日活)有2560*200=51.2萬,業內一般是放大200倍計算,有這樣的日活說明做得很不錯了。
一臺伺服器能夠達到的最大QPS受很多因素的影響,比如機器引數配置、機房地理位置、CPU效能、記憶體大小、磁碟效能、頻寬大小、程式語言、資料庫效能、程式架構等,我們一一細說。
1.機器引數配置
比如伺服器最大可以開啟128個程序,你設定了最大隻開啟100個,這屬於伺服器調優。
2.機房地理位置
如果你做海外使用者,伺服器機房應該選擇國外的,反之應該選擇國內的,因為機房距離使用者越近,在傳輸上的間損耗就越低。
3.CPU效能
CPU效能越好,處理速度就越快,核心數越多,能夠並行開啟的程序就越多。
4.記憶體大小
記憶體越大,程式就能把更多的資料直接放到記憶體,從記憶體讀取資料比從磁碟讀取資料的速度快很多。
5.磁碟效能
一般固態硬碟的效能比機械硬碟的效能好很多,效能越好讀寫資料的速度就越快。
6.頻寬大小
伺服器的頻寬一般指流出頻寬,單位為Mb/S,比如頻寬為8Mb/S即1MB/S,如果提供檔案下載服務,可能一個使用者的下載行為就把伺服器頻寬用完了。 一般把圖片、視訊、css檔案、JavaScript指令碼等資源放到第三方的CDN去,按流量計費,這樣就不佔用伺服器帶寬了。 如果使用者規模小,基本上一臺伺服器就好了,這個時候一般會選按固定頻寬大小計費。 如果使用者規模很大了,基本上會用到負載均衡器來分流,即把流量按照一定的規則分配到不同的伺服器上,負載均衡器一般會按流量來計費。 如果平均一次請求返回的資料大小為50KB,為了達到1000QPS這個指標,需要的頻寬峰值=1000508/1024=390.625Mb/S。 我們在設計介面的時候應該儘量減少返回的資料大小,比如user_id就可以簡化為uid,像圖片、視訊、css等檔案壓縮的目的就是減少資料的大小。
7.程式語言
編譯型語言的效能一般好於解釋型語言的效能,比如java語言效能就好於php語言效能,當語言短期不會替換時,可以通過堆機器解決高併發問題。
8.資料庫效能
一臺伺服器上部署的資料庫總是有一個瓶頸的,比如每秒查詢數、每秒寫入數。
我們可以通過增加很多從庫解決查詢(select語句)的瓶頸,稱之為多從庫模型,需要注意的是主從同步資料可能有延遲,當修改資料後馬上需要查詢時需要設定強制從主庫讀取。
我們可以將業務拆分,讓某些表儲存在一個數據庫例項上,另一些表儲存在其他資料庫例項上,雖然一個數據庫例項有自己的瓶頸,但是很多的資料庫例項堆積起來效能就會大大改善,多個數據庫例項的方案稱之為多主庫模型,主要是為了解決寫入瓶頸(insert語句、update語句、delete語句)。 如果你有多個主庫又有多個從庫,你就實現了多主多從模型。
如果一個表儲存的資料量很大,這個時候就要考慮分表了(一般用中介軟體實現),比如按時間分表或者按使用者分表,當把一個表的所有分表都放在一個數據庫例項上都滿足不了要求的時候,你應該把某些分表儲存在新的資料庫例項上,這個時候一個表的資料分佈到了不同的資料庫例項上,這就是所謂的分散式資料庫方案了,你需要處理的事情就很複雜了,比如處理分散式事務。
資料庫的併發連線數也是有限制的,我們可以用連線池技術來應對,就是保持一定數量的和資料庫的連線不斷開的長連線,需要連線資料庫的時候就從池子裡選擇一個連線,用完放回去就好了,這個一般也是用中介軟體來實現。
好的索引也能提高資料庫的效能,有時候比堆多個從庫的方案還要好。 如果能夠減少資料庫的讀寫,也算間接提高了資料庫的效能,比如我們用redis來做快取,用訊息佇列非同步落庫等。 有時候某些資料用資料庫來計算需要很長時間,可以取到元資料(最小粒度的資料)用程式來計算,這稱之為用記憶體換時間。
9.程式架構
架構這個因為自己水平有限,舉個很簡單的例子,有些初級程式設計師寫一個功能,程式碼迴圈執行了100次,一個老手寫的迴圈執行了10次,差異就出來了。建議平時的程式碼,可以仔細琢磨一下,寫的更好,更簡潔,可複用性更高,耦合性更低。
10.總結
一般大型專案基本是前後端分離的,從效能方面說就是為了將頁面渲染的處理在客戶端執行,降低伺服器的壓力。 從頻寬層面考慮,css、圖片、視訊、JavaScript等檔案資源能用CDN的就用CDN,能壓縮的就儘量壓縮,介面能減小返回資料的大小就儘量減小。
為了解決程式語言的不足或者單臺伺服器的瓶頸,可以先堆機器應對。
索引、多主多從、分散式資料庫、快取、連線池、訊息佇列等是從資料庫方便考慮如何優化效能。
有時候程式的耦合性低比程式的效能高更重要,不要一味地追求高效能。