C10K問題

開宗明義,epoll以及BSD的kqueue就是推出來解決 C10K的。Linux2.6 2003年左右。html

 

能夠看這篇文章node

http://www.oschina.net/translate/the-secret-to-10-million-concurrent-connections-the-kernel程序員

另外我以前的文章算法

http://www.cnblogs.com/charlesblc/p/6242479.htmlapache

也講到了百萬級別鏈接的要點 epoll的一些內部實現編程

 

還有這一篇:服務器

http://rango.swoole.com/archives/381swoole

Epoll就是爲了解決C10K問題而生。網絡

Nginx,libevent,node.js這些就是Epoll時代的產物。併發

 

當程序員還沉浸在解決C10K問題帶來的成就感時,一個新的問題被拋出了。異步嵌套回調太TM難寫了。

因而一個新的技術被提出來了,那就是協程(coroutine)。這個技術本質上也是異步非阻塞技術,它是將事件回調進行了包裝,讓程序員看不到裏面的事件循環。

程序員就像寫阻塞代碼同樣簡單。好比調用 client->recv() 等待接收數據時,就像阻塞代碼同樣寫。其實是底層庫在執行recv時悄悄保存了一個狀態,好比代碼行數,局部變量的值。而後就跳回到EventLoop中了。何時真的數據到來時,它再把剛纔保存的代碼行數,局部變量值取出來,又開始繼續執行。

 

這就是協程的本質。協程是異步非阻塞的另一種展示形式。Golang,Erlang,Lua協程都是這個模型。

注:我理解,就是把異步交給語言去處理;暴露的接口是同步形式的。

 

實際上同步阻塞程序的性能並不差,它的效率很高,不會浪費資源。當進程發生阻塞後,操做系統會將它掛起,不會分配CPU。直到數據到達纔會分配CPU。多進程只是開多了以後反作用太大,由於進程多了互相切換有開銷。因此若是一個服務器程序只有1000左右的併發鏈接,同步阻塞模式是最好的。

 

異步回調是沒有切換開銷的,它等同於順序執行代碼。因此異步回調程序的性能是要優於協程模型的。

這裏是指Nginx這種多進程異步非阻塞程序。Node.js/Redis此類程序若是不開多個進程,因爲沒法利用多核計算優點,因此性能並很差。


再看第三篇

C10K的問題——過去十年 

十年前,工程師在處理C10K可擴展性問題時,都儘量的避免服務器處理超過10,000個的併發鏈接。經過修正操做系統內核以及用事件驅動型服務器(如Nginx和Node)替代線程式的服務器(如Apache)這個問題已經解決。從Apache轉移到可擴展的服務器上,人們用了十年的時間。在過去的幾年中,(咱們看到)可擴展服務器的採用率在大幅增加。

Apache的問題

  • Apache的問題是,(併發)鏈接數越多它的性能會越低下。
  • 關鍵問題:(服務器的)性能和可擴展性並非一碼事。它們指的不是同一件事情。當人們談論規模的時候每每也會談起性能的事情,可是規模和性能是不可同日而語的。好比Apache。
  • 在僅持續幾秒的短時鏈接時,好比快速事務處理,若是每秒要處理1,000個事務,那麼大約有1,000個併發鏈接到服務器。
  • 若是事務增長到10秒,要保持每秒處理1,000個事務就必需要開啓10K(10,000個)的併發鏈接。這時Apache的性能就會陡降,即便拋開DDos攻擊。僅僅是大量的下載就會使Apache宕掉。
  • 若是每秒須要處理的併發請求從5,000增長到10,000,你會怎麼作?假使你把升級硬件把處理器速度提高爲原來的兩倍。會是什麼狀況?你獲得了兩倍的性能,可是卻沒有獲得兩倍的處理規模。處理事務的規模或許僅僅提升到了每秒6,000個(即每秒6,000個併發請求)。繼續提升處理器速度,仍是無濟於事。甚至當性能提高到16倍時,併發鏈接數還不能達到10,000個。由此,性能和規模並非一回事。
  • 問題在於Apache老是建立了一個進程而後又把它關閉了,這並非可擴展的。
  • 爲何?由於內核採用的O(n^2) 算法致使服務器不能處理10,000個併發鏈接。
    • 內核中的兩個基本問題:
      • 鏈接數 = 線程數/進程數。當一個包(數據包)來臨時,它(內核)會遍歷全部的10,000個進程以決定由哪一個進程處理這個包。
      • 鏈接數= 選擇數/輪詢次數(單線程狀況下)。一樣的擴展性問題。每一個包不得不遍歷一遍列表中的socket。
    • 解決方法:修正內核在規定的時間內進行查找
      • 無論有多少線程,線程切換的時間都是恆定的
      • 使用一個新的可擴展的epoll()/IOCompletionPort在規定的時間內作socket查詢
  • 因爲線程調度依然沒有被擴展,所以服務器對sockt大規模的採用epoll,致使須要使用異步編程模式,然而這正是Node和Nginx所採用的方式。這種軟件遷移會獲得(和原來)不同的表現(指從apache遷移到ngix等)。即便在一臺很慢(配置較低)的服務器上增長鏈接數性能也不會陡降。介於此,在開啓10K併發鏈接時,一臺筆記本電腦(運行ngix)的速度甚至超越了一臺16核的服務器(運行Apache)。

 

  • 一個頗具影響的例子,就是在考慮到Apache的線程每一個鏈接模型(is to consider Apache’s thread per connection model)。 這就意味着線程調度器根據到來的數據(on which data arrives)決定調用哪個(不一樣的)read()函數(方法)。把線程調度系統當作(數據)包調度系統來使用(我很是喜歡這一點,以前歷來沒據說過相似的觀點)。
  • Nginx宣稱,它並不把線程調度看成(數據)包調度來用使用,它自已作(進行)包調度。使用select來查找socket,咱們知道數據來了,因而就能夠當即讀取並處理它,數據也不會堵塞。
  • 經驗:讓Unix處理網絡堆棧,以後的事情就由你自已來處理。
相關文章
相關標籤/搜索