對網際網路三高框架的認識
對網際網路三高框架的認識
網際網路三高架構:高併發、高效能、高可用,簡稱三高hp
網際網路應用系統開發確定常常會看到高併發和高效能這兩個詞,可謂是耳熟能詳,而具體的含義和關係真的如你所想的,真正的理解了嗎?java
先來看一個例子:mysql
一個蓄水池,是1m*1m*1m=1立方米大小,有一個出水口,出水口每秒鐘流出0.1立方米,那麼這個蓄水池的併發量是1立方米,出水速度是0.1立方米/秒。nginx
若是增長一個出水口,都是每秒鐘流出0.1立方米,那麼這個蓄水池的併發量沒變,可是出水速度變成了0.2立方米/秒。web
同理,增大了出水口,蓄水池的出水速度也變快了。redis
上面咱們很容易知道,併發量是一個容量的概念,效能就是出水速度,並且有下面這些結果。演算法
- 增大蓄水池的長寬高,能夠增長併發能力。
- 出水口若是擴大了出口大小,則能夠提升出水的速度,也就是效能提升了。
- 增長出水口的數量,則是增長了並行處理的能力,一樣能夠提升效能。
那麼對照咱們計算機中,咱們的系統中,是怎麼樣的結果呢?sql
- 增長伺服器的記憶體大小,能夠增長併發量。由於記憶體增長了,就能夠開更多的程序,更多的執行緒,也能夠擴大任務佇列的大小。
- 提升cpu的主頻速度,優化程式,能夠提升效能。cpu更快了,程式優化的更好了,處理單個任務的時間也就更短了。
- 增長多核甚至分散式伺服器數量,也能夠提升效能,同時提升併發量。
若是隻是效能提升了,併發量是否也能提升呢?api
若是咱們靜態的理解併發量,那它是不會提升的。安全
而我更願意動態的來理解併發量,即:單位時間內能夠進來的最大數量。
那麼提升效能,是能夠線性提升併發量的,由於單位時間內,進來的同時也有出去。
咱們先來作一個假設:
單個程序(php fast-cgi)記憶體佔用10M
單個執行緒( java web)記憶體佔用2M
單個協程(go)記憶體佔用20K
佇列任務(nginx)記憶體佔用2K
咱們下面來看看記憶體與併發量的關係。
記憶體量 |
程序數 |
執行緒數 |
協程 |
佇列任務 |
1G |
100 |
500 |
50K |
500K |
2G |
200 |
1000 |
100K |
1000K |
4G |
400 |
2000 |
200K |
2000K |
8G |
800 |
4000 |
400K |
4000K |
從上面的結果中,咱們能夠很直觀的看出來,併發能力在不一樣的執行模式中的巨大區別。
多程序和多執行緒的模式,不只是記憶體開銷巨大,並且在數量不斷增長的狀況下,對CPU的壓力也是很是巨大,
這也是為何這類系統在併發量大的狀況下會很不穩定,甚至宕機。
假設上邊計算出來的資料,都是靜態的容量,若是全部任務都不處理,那麼記憶體確定都是會很快就被撐爆。
因此要達到更高的併發量,就須要有更快的處理速度,即作好效能優化。
下面,再來作一個假設。
咱們如今有一臺伺服器,配置是8核16G記憶體。
若是咱們的應用是計算密集型,純運算的系統,如:資料索引查詢、排序等操做。
並且還要假設,這個應用在多核並行運算時不存在鎖競爭的狀況(只讀)。
QPS = 1000ms/單個請求耗時*8
① 若是單個請求(任務)耗時100ms,那麼咱們能夠計算出來:qps = (1000ms/100ms)*8核 = 80個/秒
② 若是咱們優化處理的演算法,單個請求耗時下降到10ms,那麼:qps = (1000ms/10ms)*8核 = 800個/秒
③ 若是能夠繼續優化,將單個請求耗時下降到1ms,那麼:qps = (1000ms/1ms)*8核 = 8000個/秒
上面的狀況和優化的效果理解起來應該很容易,由於對伺服器資源的依賴更可能是CPU的運算能力和數量。
在實際的網際網路應用中,系統更可能是依賴mysql,redis,rest api或者微服務,屬於IO密集型。按照上面的計算方式,可能就不太準確了,由於cpu是有富餘的。
在IO阻塞的時候,開啟更多工的方式固然有上面多程序、多執行緒、多協程和佇列的方式來實現,並且也是有效且更好地利用伺服器資源的方法,能夠達到更高的併發量,
畢竟咱們把大部分的運算放到了應用外部的mysql,redis,rest api等服務。
到此為止,咱們已經知道併發量、效能優化跟伺服器資源(伺服器數量,cpu,記憶體)的關係,也知道效能優化對併發量的影響。
解疑答惑
1 記憶體越多,併發量必定能夠越大嗎?
答:大部分狀況是的。這個問題,上面有提到過,對於多程序、多執行緒的模式,執行緒太多的時候,執行緒搶佔時間片,CPU切換上下文會愈來愈慢。影響系統性能。
對於協程、佇列的執行模式,這個問題會好不少,固然協程排程、佇列維護的開銷,確定也是會增長,只是增長的開銷不至於對系統性能形成直線降低。
2 CPU越快,應用的效能必定越好嗎?
答:絕對的。只不過CPU和應用效能提高可能不成線性增加的關係,由於應用多是IO密集型,應用效能還會受到IO阻塞的影響。
3 CPU越多,應用的效能必定越好嗎?
答:大部分狀況是的。若是大量鎖存在,效能提高可能會大打折扣,由於並行能力會被鎖住,又變成單執行緒執行了,沒有最大的發揮多CPU的做用。
4 伺服器越多,併發量必定越大嗎?
答:絕對的。伺服器增長,CPU和記憶體資源相應也就越多,併發能力也就會增大,他們之間是線性相關。
5 伺服器越多,效能必定越好嗎?
答:大部分狀況是的。可是單個伺服器的效率可能會是降低的,資料一致性問題、同步問題、鎖問題,這些都會致使單個伺服器的效率(CPU利用率)降低,因此不是線性相關。
關於CPU利用率:
若是隻是考慮應用對CPU利用效率的話:單核=多核=多伺服器
單程序/單執行緒的系統對於伺服器資源的利用率更高。
到多核的系統中,就會由於鎖的問題,多工同步的問題,操做系統排程的問題,形成必定的資源浪費。而分散式系統中,這些浪費也會更嚴重。
6 怎樣更好的更有效的利用伺服器資源呢?
答:避免由於IO阻塞讓CPU閒置,致使CPU的浪費;
避免多執行緒間增長鎖來保證同步,致使並行系統序列化;
避免建立、銷燬、維護太多程序、執行緒,致使操做系統浪費資源在排程上;
避免分散式系統中多伺服器的關聯,好比:依賴同一個mysql,程式邏輯中使用分散式鎖,致使瓶頸在mysql,分散式又變成序列化運算。
上面說了要避免的地方,要具體怎麼來避免,到具體的業務場景就須要具體分析了。
並且有些時候,為了業務功能,或者其它方面的需求,好比:可用性、伸縮性、擴充套件性、安全性,不得不犧牲掉一部分效能。
最後,作一個總結:
併發量,是一個容量的概念,服務能夠接受的最大任務數量,動態的看待它,還須要把效能考慮進去。
效能,是一個速度的概念,單位時間內能夠處理的任務數量。
高併發和高效能是緊密相關的,提升應用的效能,是確定能夠提升系統的併發能力的。
應用效能優化的時候,對於計算密集型和IO密集型仍是有很大差異,須要分開來考慮。
增長伺服器資源(CPU、記憶體、伺服器數量),絕大部分時候是能夠提升應用的併發能力和效能 (前提是應用可以支援多工平行計算,多伺服器分散式計算才行),但也是要避免其中的一些問題,才能夠更好的更有效率的利用伺服器資源。