服務器模型涉及到線程模式和IO模式,搞清楚這些就能針對各類場景有的放矢。該系列分紅三部分:服務器
這裏探討的服務器模型主要指的是服務器端對I/O的處理模型。從不一樣維度能夠有不一樣的分類,這裏從I/O的阻塞與非阻塞、I/O處理的單線程與多線程角度探討服務器模型。多線程
對於I/O,能夠分紅阻塞I/O與非阻塞I/O兩大類型。阻塞I/O在作I/O讀寫操做時會使當前線程進入阻塞狀態,而非阻塞I/O則不進入阻塞狀態。併發
對於線程,單線程狀況下由一條線程負責全部客戶端鏈接的I/O操做,而多線程狀況下則由若干線程共同處理全部客戶端鏈接的I/O操做。機器學習
單線程非阻塞I/O模型已經大大提升了機器的效率,而在多核的機器上能夠經過多線程繼續提升機器效率。最樸實、最天然的作法就是將客戶端鏈接按組分配給若干線程,每一個線程負責處理對應組內的鏈接。如圖所示,有4個客戶端訪問服務器,服務器將套接字1和套接字2交由線程1管理,而線程2則管理套接字3和套接字4,經過事件檢測及非阻塞讀寫就可讓每一個線程都能高效處理。分佈式
最經典的多線程非阻塞I/O模型方式是Reactor模式。首先看單線程下的Reactor,Reactor將服務器端的整個處理過程分紅若干個事件,例如分爲接收事件、讀事件、寫事件、執行事件等。Reactor經過事件檢測機制將這些事件分發給不一樣處理器去處理。如圖所示,若干客戶端鏈接訪問服務器端,Reactor負責檢測各類事件並分發處處理器,這些處理器包括接收鏈接的accept處理器、讀數據的read處理器、寫數據的write處理器以及執行邏輯的process處理器。在整個過程當中只要有待處理的事件存在,便可以讓Reactor線程不斷往下執行,而不會阻塞在某處,因此處理效率很高。高併發
基於單線程Reactor模型,根據實際使用場景,把它改進成多線程模式。常見的有兩種方式:一種是在耗時的process處理器中引入多線程,如使用線程池;另外一種是直接使用多個Reactor實例,每一個Reactor實例對應一個線程。學習
Reactor模式的一種改進方式如圖所示。其總體結構基本上與單線程的Reactor相似,只是引入了一個線程池。因爲對鏈接的接收、對數據的讀取和對數據的寫入等操做基本上都耗時較少,所以把它們都放到Reactor線程中處理。然而,對於邏輯處理可能比較耗時的工做,能夠在process處理器中引入線程池,process處理器本身不執行任務,而是交給線程池,從而在Reactor線程中避免了耗時的操做。將耗時的操做轉移到線程池中後,儘管Reactor只有一個線程,它也能保證Reactor的高效。.net
Reactor模式的另外一種改進方式如圖所示。其中有多個Reactor實例,每一個Reactor實例對應一個線程。由於接收事件是相對於服務器端而言的,因此客戶端的鏈接接收工做統一由一個accept處理器負責,accept處理器會將接收的客戶端鏈接均勻分配給全部Reactor實例,每一個Reactor實例負責處理分配到該Reactor上的客戶端鏈接,包括鏈接的讀數據、寫數據和邏輯處理。這就是多Reactor實例的原理。線程
多線程非阻塞I/O模式讓服務器端處理能力獲得很大提升,它充分利用機器的CPU,適合用於處理高併發的場景,但它也讓程序更復雜,更容易出現問題。設計
=============廣告時間===============
公衆號的菜單已分爲「分佈式」、「機器學習」、「深度學習」、「NLP」、「Java深度」、「Java併發核心」、「JDK源碼」、「Tomcat內核」等,可能有一款適合你的胃口。
鄙人的新書《Tomcat內核設計剖析》已經在京東銷售了,有須要的朋友能夠購買。感謝各位朋友。
=========================
歡迎關注: