1. 程式人生 > 其它 >對網際網路三高框架的認識

對網際網路三高框架的認識

對網際網路三高框架的認識

網際網路三高架構:高併發、高效能、高可用,簡稱三高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、記憶體、伺服器數量),絕大部分時候是能夠提升應用的併發能力和效能 (前提是應用可以支援多工平行計算,多伺服器分散式計算才行),但也是要避免其中的一些問題,才能夠更好的更有效率的利用伺服器資源。