'洛陽課工場—面試官要是問你如何解決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.程序語言

編譯型語言的性能一般好於解釋型語言的性能,比如go語言性能就好於php語言性能,當語言短期不會替換時,可以通過堆機器解決高併發問題。

8.數據庫性能

一臺服務器上部署的數據庫總是有一個瓶頸的,比如每秒查詢數、每秒寫入數。

我們可以通過增加很多從庫解決查詢(select語句)的瓶頸,稱之為多從庫模型,需要注意的是主從同步數據可能有延遲,當修改數據後馬上需要查詢時需要設置強制從主庫讀取。

我們可以將業務拆分,讓某些表存儲在一個數據庫實例上,另一些表存儲在其他數據庫實例上,雖然一個數據庫實例有自己的瓶頸,但是很多的數據庫實例堆積起來性能就會大大改善,多個數據庫實例的方案稱之為多主庫模型,主要是為了解決寫入瓶頸(insert語句、update語句、delete語句)。

如果你有多個主庫又有多個從庫,你就實現了多主多從模型。

如果一個表存儲的數據量很大,這個時候就要考慮分表了(一般用中間件實現),比如按時間分表或者按用戶分表,當把一個表的所有分表都放在一個數據庫實例上都滿足不了要求的時候,你應該把某些分表存儲在新的數據庫實例上,這個時候一個表的數據分佈到了不同的數據庫實例上,這就是所謂的分佈式數據庫方案了,你需要處理的事情就很複雜了,比如處理分佈式事務。

數據庫的併發連接數也是有限制的,我們可以用連接池技術來應對,就是保持一定數量的和數據庫的連接不斷開的長連接,需要連接數據庫的時候就從池子裡選擇一個連接,用完放回去就好了,這個一般也是用中間件來實現。

好的索引也能提高數據庫的性能,有時候比堆多個從庫的方案還要好。

如果能夠減少數據庫的讀寫,也算間接提高了數據庫的性能,比如我們用redis來做緩存,用消息隊列異步落庫等。

有時候某些數據用數據庫來計算需要很長時間,可以取到元數據(最小粒度的數據)用程序來計算,這稱之為用內存換時間。

9.程序架構

比如實現同樣的功能,初級程序員寫的程序需要循環100次,而高級程序員寫的程序只需要循環10次,效果肯定不一樣。

總結

一般大型項目基本是前後端分離的,從性能方面說就是為了將頁面渲染的處理在客戶端運行,降低服務器的壓力。

從帶寬層面考慮,css、圖片、視頻、JavaScript等文件資源能用CDN的就用CDN,能壓縮的就儘量壓縮,接口能減小返回數據的大小就儘量減小。

為了解決編程語言的不足或者單臺服務器的瓶頸,可以先堆機器應對。

索引、多主多從、分佈式數據庫、緩存、連接池、消息隊列等是從數據庫方便考慮如何優化性能。

有時候程序的耦合性低比程序的性能高更重要,不要一味地追求高性能。

"

所謂高併發,就是同一時間有很多流量(通常指用戶)訪問程序的接口、頁面及其他資源,解決高併發就是當流量峰值到來時保證程序的穩定性。

我們一般用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.程序語言

編譯型語言的性能一般好於解釋型語言的性能,比如go語言性能就好於php語言性能,當語言短期不會替換時,可以通過堆機器解決高併發問題。

8.數據庫性能

一臺服務器上部署的數據庫總是有一個瓶頸的,比如每秒查詢數、每秒寫入數。

我們可以通過增加很多從庫解決查詢(select語句)的瓶頸,稱之為多從庫模型,需要注意的是主從同步數據可能有延遲,當修改數據後馬上需要查詢時需要設置強制從主庫讀取。

我們可以將業務拆分,讓某些表存儲在一個數據庫實例上,另一些表存儲在其他數據庫實例上,雖然一個數據庫實例有自己的瓶頸,但是很多的數據庫實例堆積起來性能就會大大改善,多個數據庫實例的方案稱之為多主庫模型,主要是為了解決寫入瓶頸(insert語句、update語句、delete語句)。

如果你有多個主庫又有多個從庫,你就實現了多主多從模型。

如果一個表存儲的數據量很大,這個時候就要考慮分表了(一般用中間件實現),比如按時間分表或者按用戶分表,當把一個表的所有分表都放在一個數據庫實例上都滿足不了要求的時候,你應該把某些分表存儲在新的數據庫實例上,這個時候一個表的數據分佈到了不同的數據庫實例上,這就是所謂的分佈式數據庫方案了,你需要處理的事情就很複雜了,比如處理分佈式事務。

數據庫的併發連接數也是有限制的,我們可以用連接池技術來應對,就是保持一定數量的和數據庫的連接不斷開的長連接,需要連接數據庫的時候就從池子裡選擇一個連接,用完放回去就好了,這個一般也是用中間件來實現。

好的索引也能提高數據庫的性能,有時候比堆多個從庫的方案還要好。

如果能夠減少數據庫的讀寫,也算間接提高了數據庫的性能,比如我們用redis來做緩存,用消息隊列異步落庫等。

有時候某些數據用數據庫來計算需要很長時間,可以取到元數據(最小粒度的數據)用程序來計算,這稱之為用內存換時間。

9.程序架構

比如實現同樣的功能,初級程序員寫的程序需要循環100次,而高級程序員寫的程序只需要循環10次,效果肯定不一樣。

總結

一般大型項目基本是前後端分離的,從性能方面說就是為了將頁面渲染的處理在客戶端運行,降低服務器的壓力。

從帶寬層面考慮,css、圖片、視頻、JavaScript等文件資源能用CDN的就用CDN,能壓縮的就儘量壓縮,接口能減小返回數據的大小就儘量減小。

為了解決編程語言的不足或者單臺服務器的瓶頸,可以先堆機器應對。

索引、多主多從、分佈式數據庫、緩存、連接池、消息隊列等是從數據庫方便考慮如何優化性能。

有時候程序的耦合性低比程序的性能高更重要,不要一味地追求高性能。

洛陽課工場—面試官要是問你如何解決web高併發,你就這樣回答

文章來源於小馬奔騰

"

相關推薦

推薦中...