Reactor 反應堆設計模式

爲了應對高併發的服務器端開發,微軟在2009年提出了一種更優雅地實現異步編程的方式Reactive Programming即反應式編程。隨後其餘技術緊隨其後,好比ES6經過引入相似的異步編程方式等。react

在高性能的I/O設計中,有兩個比較著名的模式ReactorProactor模式,其中Reactor模式用於同步I/O,Proactor用於異步I/O操做。shell

Reactor模式稱之爲響應器模式,一般用於NIO非阻塞IO的網絡通訊框架中。數據庫

在這以前,須要弄明白幾個概念:編程

  • 什麼是阻塞和非阻塞?

阻塞和非阻塞是針對於進程在訪問數據時,根據IO操做的就緒狀態而採起的不一樣方式,簡單來講是一種讀取或寫入操做函數的實現方式,阻塞方式下讀取或寫入函數將一直等待。非阻塞方式下,讀取和寫入函數會當即返回一個狀態值。設計模式

  • 什麼是同步和異步?

同步和異步是針對應用程序和內核的交互而言的,同步是指用戶進程觸發IO操做並等待或輪詢的查看IO操做是否就緒,異步是指用戶進程觸發IO操做之後便開始作本身的事情,當IO操做完成時會獲得通知,換句話說異步的特色就是通知。安全

  • 什麼是IO模型?

通常而言,IO模型能夠分爲四種:同步阻塞、同步非阻塞、異步阻塞、異步非阻塞服務器

  1. 同步阻塞IO是指用戶進程在發起一個IO操做後必須等待IO操做完成,只有當真正完成了IO操做後用戶進程才能運行。網絡

  2. 同步非阻塞IO是指用戶進程發起一個IO操做後當即返回,程序也就能夠作其餘事情。可是用戶進程須要不時的詢問IO操做是否就緒,這就要求用戶進程不停的去詢問,從而引入沒必要要的CPU資源浪費。多線程

  3. 異步阻塞IO是指應用發起一個IO操做後沒必要等待內核IO操做的完成,內核完成IO操做後會通知應用程序。這實際上是同步和異步最關鍵的區別,同步必須等待或主動詢問IO操做是否完成,那麼爲何說是阻塞呢?由於此時是經過select系統調用來完成的,而select函數自己的實現方式是阻塞的,採用select函數的好處在於能夠同時監聽多個文件句柄,從而提升系統的併發性。架構

  4. 異步非阻塞IO是指用戶進程只須要發起一個IO操做後當即返回,等IO操做真正完成後,應用系統會獲得IO操做完成的通知,此時用戶進程只須要對數據進行處理便可,不須要進行實際的IO讀寫操做,由於真正的IO讀寫操做已經由內核完成。

NIO非阻塞IO處理流程

 
非阻塞IO處理流程
  1. Acceptor註冊Selector並監聽accept事件
  2. 當客戶端鏈接後會觸發accept事件
  3. 服務器構建對應的Channel並在其上註冊Selector,用於監聽讀寫事件。
  4. 當發生讀寫事件後進行相應的讀寫處理

NIO非阻塞IO的優勢在於性能瓶頸高,缺點在於模型複雜、編碼複雜、須要處理半包問題。簡單來講非阻塞IO不須要一個鏈接創建一個線程,它能夠在一個線程中處理全部的鏈接。可是因爲是非阻塞的,因此應用沒法知道何時消息讀完了,也就會存在半包的問題。

什麼是半包問題呢?

TCP/IP在發送消息時可能會拆包,拆包會致使接收端沒法得知何時接收到的數據是一個完整的數據。在BIO阻塞性IO模型中,當讀取步到數據後會阻塞,而在NIO非阻塞IO中則不會,因此須要自行進行處理。好比以換行符做爲判斷依據,或者是定長消息發送,或者是自定義協議等。

什麼是Reactor模式?

Reactor模式是處理併發I/O常見的一種模式,用於同步I/O,其中心思想是將全部要處理的I/O事件註冊到一箇中心I/O多路複用器上,同時主線程阻塞在多路複用器上,一旦有I/O事件到來或是準備就緒,多路複用器將返回並將相應I/O事件分發到對應的處理器中。

Reactor是一種事件驅動機制,和普通函數調用不一樣的是應用程序不是主動的調用某個API來完成處理,偏偏相反的是Reactor逆置了事件處理流程,應用程序需提供相應的接口並註冊到Reactor上,若是有相應的事件發生,Reactor將主動調用應用程序註冊的接口(回調函數)。

The reactor design pattern is an event handling pattern for handling service requests delivered concurrently by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to associated request handlers.

 
Reactor

Reactor模式稱爲反應器模式或應答者模式,是基於事件驅動的設計模式,擁有一個或多個併發輸入源,有一個服務處理器和多個請求處理器,服務處理器會同步的將輸入的請求事件以多路複用的方式分發給相應的請求處理器。

Reactor設計模式是一種爲處理併發服務請求,並將請求提交到一個或多個服務處理程序的事件設計模式。當客戶端請求抵達後,服務處理程序使用多路分配策略,由一個非阻塞的線程來接收全部請求,而後將請求派發到相關的工做線程並進行處理的過程。

在事件驅動的應用中,將一個或多個客戶端的請求分離和調度給應用程序,同步有序地接收並處理多個服務請求。對於高併發系統常常會使用到Reactor模式,用來替代經常使用的多線程處理方式以節省系統資源並提升系統的吞吐量。

基礎

什麼是C/S架構?

  • C表示Client客戶端
  • S表示Server服務器,服務器管理着某種資源Resource,經過操做這種資源爲客戶端提供服務。
 
C/S架構

C/S架構的工做流程

  1. 客戶端進程向服務器進程發送請求
  2. 服務器進程接收並處理請求
  3. 服務器進程向客戶端進程發送響應
  4. 客戶端進程處理響應

什麼是套接字Socket?

  • Socket原意爲插口,所表達的意思是插口與插槽之間的關係。
  • Socket是對TCP/IP編程的抽象,簡單來講,是send socket插入到receive socket中以創建鏈接進行通訊。
 
Socket之間創建鏈接並通訊的過程

C/S架構中Socket之間是如何創建鏈接並通訊的呢?

  1. 服務端Socket綁定bind到指定的端口上後監聽listen客戶端的插入
  2. 客戶端Socket鏈接到connect到服務端
  3. 當服務端accept到客戶端鏈接後
  4. 客戶端與服務端之間收發信息開發通訊
  5. 通訊完成後客戶端與服務器關閉close掉Socket

演化

當前分佈式計算Web服務盛行天下,網絡服務的底層都離不開對Socket的操做,而它們都具備一個共同的結構。

不一樣於傳統IO的串行調度方式,NIO非阻塞IO操做會將整個服務請求劃分爲五個階段。

在網絡服務和分佈式中對於網絡中請求的處理,處理流程大體可劃分爲五個階段。

  1. read 接收請求讀取數據
  2. decode 數據解碼
  3. compute 業務邏輯處理(計算處理)
  4. encode 編碼回覆
  5. send 發送回覆

在這五個階段中,以readsend階段IO操做最爲頻繁。

 
網絡中請求的處理流程

在處理網絡請求時,一般具備兩種體系結構。

  • 基於線程 thread-based architecture

基於線程的體系結構會使用多線程來處理客戶端的請求,每當接收一個請求便開啓一個獨立的線程來處理。這種方式雖然簡單直觀,但僅適用於併發訪問不大的場景。由於線程是須要佔用必定的內存資源,並且操做系統在線程之間的切換也須要必定的開銷。當線程過多時顯然會下降網絡服務器的性能。另外,當線程在處理IO操做時,在等待輸出的這段時間內線程是處於空閒狀態,形成CPU資源浪費。

  • 事件驅動 event-driver architecture

事件驅動體系結構是目前普遍使用的一種方式,這種方式定義了一系列的事件處理程序來響應事件的發生,並且將服務端接收鏈接和事件處理分離,事件自己只是一種狀態的改變。在事件驅動的應用中,會將一個或多個客戶端的服務請求分離demultiplex和調度dispatch給應用程序。

Reactor設計模式是event-driven architecture的一種實現方式,用於處理多個客戶端併發的向服務器請求服務的場景。每種服務在服務器上可能由多個方法組成。Reactor會解耦併發請求的服務並分發給對應的時間處理器來處理。

從結構上看,Reactor相似於生產消費模式,也就是一個或多個生產者會將事件放入一個隊列中,一個或多個消費者主動從隊列中poll拉取事件進行處理。Reactor並無使用隊列來作緩衝,每當一個事件輸入到服務處理程序以後,服務處理程序會主動根據不一樣的事件類型將其分發給對應的請求處理程序進行處理。

Reactor模式和生產者和消費者之間最大的區別在於

  • 生產者消費者模式是基於隊列queue的實現,可以解決生產端和消費端處理速度不一樣步的問題,隊列能夠採用先有的MQ產品來實現。

  • Reactor模式是基於事件驅動模型,當接收到請求後會將請求封裝成事件,並將事件分發給相應處理事件的handlerhandler處理完成後將時間狀態修改成下一個狀態,再由Reactor將事件分發給可以處理下一個狀態的handle進行處理。
    Reactor模式與Observer觀察者模式在某些方面極爲類似,當一個主體發生改變時,全部依屬體都將獲得通知。不過觀察者模式與單個事件源關聯,而反應器模式則於多個事件源關聯。

Reactor模式的優勢很明顯:解耦、提高複用性、模塊化、可移植性、事件驅動、細粒度的開發控制等。Reactor模式的缺點也很明顯:模型複雜,涉及到內部回調、多線程處理、不容易調試、須要操做系統底層支持,所以致使不一樣操做系統可能會產生不同的結果。總來而言,若是併發要求不是很高,可以使用傳統的阻塞線程池足夠了。若是使用場景是產生瞬間大併發可以使用Reactor模式來實現。

傳統服務模型

最原始的網絡編程思路是服務器使用一個while循環並不斷監聽端口是否有新的socket套接字鏈接,若是有就會去調用一個處理函數。

while(true)
{
  socket = accept();
  handle(socket);
}

這種方式最大的問題是沒法併發且效率過低,若是當前請求沒有處理完畢後續請求只能被阻塞,所以服務器的吞吐量過低。

致使服務器阻塞的緣由是什麼呢?

  • 服務器socketaccept方法將阻塞等待客戶端鏈接,直到客戶端鏈接成功。
  • 線程從socket inputstream套接字輸入流讀取數據並進入阻塞狀態,直到所有數據讀取完畢
  • 線程向socket outputstream套接字輸出流寫入數據並進入阻塞狀態,直到所有數據寫入完畢。

因爲IO在阻塞時會處於等待狀態,所以在用戶負載增長時,性能降低的很是快。

多線程

改進的方式是使用多線程,也就是經典的connection per thread,每個鏈接擁有一個線程處理。

while(true)
{
  socket = accept();
  new thread(socket);
}

對於傳統的服務設計,每一個抵達的請求系統會分配一個線程去處理,Tomcat服務器早期版本是這樣實現的。

當系統請求量瞬間暴增時(高併發狀況下),會直接把系統拖垮,由於系統可以建立線程的數量是有限的。

多線程併發模式採用一個鏈接一個線程的方式,優勢是確實必定程度上提升了服務器的吞吐量,由於以前的請求在read讀阻塞後不會影響到後續的請求,因爲它們在不一樣的線程中,並且一個線程只能對應一個套接字socket,每個套接字socket都是阻塞的,因此一個線程中只能處理一個套接字。就算accept多個socket,若是前一個socket被阻塞其後的socket是沒法被執行到的。

 
多線程的服務器模型

多線程併發模式的缺點在於資源要求過高,系統中建立線程是須要消耗系統資源的,若是鏈接數太高系統將沒法承受。另外,線程反覆被建立和銷燬也是須要代價的。

線程池

雖然利用線程池能夠緩解線程建立和銷燬的代價,不過仍是存在一些問題,線程的粒度太大。每個線程會將一次交互操做所有處理完成,包括讀取和返回甚至是鏈接。表面上彷佛鏈接不在線程裏面,可是若是線程不夠,新鏈接將沒法獲得處理。因此線程的任務能夠簡化爲作三件事:鏈接、讀取、寫入。

顯然傳統一對一的線程處理沒法知足需求的變化,對此考慮使用線程池使得線程能夠被複用,大大下降建立線程和銷燬線程的時間。然而,線程池並不能很好知足高併發線程的需求。當海量請求抵達時線程池中的工做線程達到飽和狀態,此時可能就致使請求被拋棄,沒法完成客戶端的請求。對此,考慮到將一次完整的請求切分爲幾個小的任務,每一個小任務都是非阻塞的,對於讀寫操做使用NIO非阻塞IO對其進行讀寫,不一樣的任務將被分配到與之關聯的處理程序上進行處理,每一個處理器經過異步回調機制來實現。這樣能夠大大提升系統吞吐量,減小響應時間。

因爲線程同步的粒度太大限制了吞吐量,因此應該將一次鏈接操做拆分爲更細的粒度或過程,這些更細的粒度則是更小的線程。這樣作以後,整個線程池中線程的數量將會翻倍增長,但線程更加簡單且任務更爲單一。這也是Reactor出現的緣由。

Reactor

在Reactor中這些被拆分的小線程或子過程對應的處理程序,每一種處理程序會去處理一種事件。Reactor中存在一個全局管理者Selector,開發者須要將Channel註冊到感興趣的事件上,Selector會不斷在Channel上檢測是否有該類型的事件發生,若是沒有主線程會被阻塞,不然會調用相應的事件處理函數來處理。

因爲典型的事件包括鏈接、讀取、寫入,所以須要爲這些事件分別提供對應的處理程序,每一個處理程序能夠採用線程的方式實現。一旦鏈接來了,並且顯示被讀取線程或處理程序處理了,則會再執行寫入。那麼以前的讀取就能夠被後面的請求複用,所以吞吐量就提升了。

傳統的thread per connection中線程在真正處理請求之間是須要從socket中讀取網絡請求,因爲讀取完成以前線程自己是被阻塞的不能作任何事情,這就致使線程資源被佔用,而線程資源自己很珍貴的,尤爲是在處理高併發請求時。Rector模式指出在等待IO時,線程能夠先退出,這樣就會由於有線程等待IO而佔用資源。可是這樣原先的執行流程就無法還原了。所以能夠利用事件驅動的方式,要求線程在退出以前向event loop事件循環中註冊回調函數,這樣IO完成時event loop事件循環就能夠調用回調函數完成剩下的操做。因此Reactor模式經過減小服務器的資源消耗提供併發能力。

 
Reactor

細分

Reactor從線程池和Reactor的選擇上可細分爲:Reactor單線程模型、Reactor多線程模型,Reactor主從模型

單線程Reactor模型

單線程的Reactor模式對於客戶端的全部請求使用一個專門的線程去處理,這個線程無限循環地監聽是否有客戶端的請求抵達,一旦收到客戶端的請求,就將其分發給響應處理程序進行處理。

 
事件驅動設計

採用基於事件驅動的設計,當有事件觸發時纔會調用處理器進行數據處理。使用Reactor模式能夠對線程的數量進行控制,可使用一個線程去處理大量的事件。

-Reactor 負責響應IO事件,當檢測到一個新的事件會將其發送給相應的處理程序去處理。

  • Handler 負責處理非阻塞的行爲,標識系統管理的資源,同時將處理程序與事件綁定。
 
Each handler may be started in its own thread

Reactor是單個線程,須要處理accept鏈接,同時發送請求處處理器中。因爲只是單個線程,因此處理器中的業務須要可以快速處理完畢。

 
單線程的Reactor

單線程的Reactor與NIO流程相似,只是將消息相關處理獨立到Handler中。雖然NIO中一個線程能夠支持全部的IO處理,但瓶頸也是顯而易見的。若是某個客戶端屢次進行請求時在Handler中的處理速度較慢,那麼後續的客戶端請求都會被積壓,致使響應變慢。因此須要引入Reactor多線程模型。

單線程的Reactor的特色是隻有一個Reactor線程,也就是說只有一個Selector事件通知器,所以字節的讀取I/O和後續的業務處理process()均由Reactor線程來作,很顯然業務的處理影響後續事件的分發,因此引出多線程版本進行優化。

從性能角度來看,單線程的Reactor沒有過多的提高空間,由於IO和CPU的速度嚴重不匹配。

單線程的Reactor模式並無解決IO和CPU處理速度不匹配問題,因此多線程的Reactor模式引入了線程池的概念,將耗時的IO操做交由線程池處理,處理完畢後再同步到selectionkey中。

多線程Reactor模型

考慮到工做線程的複用,能夠將工做線程設計線程池。將處理器的執行放入線程池,並使用多線程處理業務邏輯,Reactor仍然是單個線程。

 
使用多線程處理業務邏輯

Reactor讀線程模型是將Handler中的IO操做和非IO操做分開,操做IO的線程稱爲IO線程,非IO操做的線程稱爲工做線程。客戶端的請求會被直接丟到線程池中,所以不會發生堵塞。

 
Reactor多線程模型

多線程的Reactor的特色是一個Reactor線程和多個處理線程,將業務處理即process交給線程池進行了分離,Reactor線程只關注事件分發和字節的發送和讀取。須要注意的是,實際的發送和讀取仍是由Reactor來處理。當在高併發環境下,有可能會出現鏈接來不及接收。

當用戶進一步增長時Reactor也會出現瓶頸,由於Reactor既要處理IO操做請求也要響應鏈接請求。爲了分擔Reactor的負擔,能夠引入主從Reactor模型。

主從Reactor模型

 
主從Reactor模型

對於多個CPU的機器,爲了充分利用系統資源會將Reactor拆分爲兩部分。

  • Main Reactor 負責監聽鏈接,將accept鏈接交給Sub Reactor處理,主Reactor用於響應鏈接請求。
  • Sub Reactor 處理accept鏈接,從Reactor用於處理IO操做請求。
 
多處理器

主從Reactor的特色是使用 一個Selector池,一般有一個主Reactor用於處理接收鏈接事件,多個從Reactor處理實際的IO。總體來看,分工合做,分而治之,很是高效。

爲何須要單獨拆分一個Reactor來處理監聽呢?

由於像TCP這樣須要通過3次握手才能創建鏈接,這個創建的過程也是須要消耗時間和資源的,單獨拆分一個Reactor來處理,能夠提升性能。

優缺點

Reactor模式的核心是解決多請求問題,若是有特別多的請求同時發生,不會由於線程池被短期佔滿而拒絕服務。通常實現多請求的模塊,會採用線程池的實現方案,這種方案對於併發量不是特別大的場景是足夠用的,好比單機TPS 1000如下都是夠用的。

線程池方案的最大缺點是:若是瞬間有大併發,則會一會兒耗滿線程,整個服務將會陷入阻塞中,後續請求沒法介入。基於Reactor模式實現的方案,會有一個Dispatcher先接收事件event,而後快速分發給相應的耗時eventHandler處理器去處理,這樣就不會阻塞請求的接收。

Reactor模式的優勢是什麼呢?

  • 響應快,不爲單個同步時間所阻塞,雖然Reactor自身依然是同步的。
  • 編程相對簡單,能夠最大程度的避免複雜的多線程以及同步問題和多線程以及多進程的切換開銷。
  • 可擴展性,能夠方便的經過增長Reactor實例個數來充分利用CPU資源。
  • 可複用性, Reactor框架自己與具體事件處理邏輯無關,具備很高的複用性。

Reactor模式的缺點是什麼呢?

  • 相比傳統的模型,Reactor增長了必定的複雜性,於是具備必定的門檻,而且不易於調試。
  • Reactor模式須要底層的Synchronous Event Demultiplexer支持,好比Java中的Selector支持,操做系統的select系統調用支持。
  • Reactor模式在IO讀寫數據時會在同一線程中實現,即便使用多個Reactor機制的狀況下,那些共享一個Reactor的Channel若是出現一個長時間的數據讀寫,會影響這個Reactor中其餘Channel的相應時間。例如在大文件傳輸時,IO操做會影響其餘客戶端的時間,於是對於這種操做,使用傳統的Thread-Per-Connection或許是一個更好的選擇,或者採用Proactor模式。

結構

Reactor中的核心組件有哪些呢?

  • Reactor
    IO事件的派發者,至關於有分發功能的Selector
  • Acceptor
    接收客戶端鏈接並創建對應客戶端的Handler,向Reactor註冊此Handler。至關於NIO中創建鏈接的那個判斷分支。
  • Handler
    和一個客戶端通信的實體,通常在基礎的Handler上會有更進一步的層次劃分,用來抽象諸如decodeprocessencode這些過程。至關於消息讀寫處理等操做類。

在Reactor模式中有五個關鍵的參與者:描述符handle、同步事件分離器demultiplexer、事件處理器接口event handler、具體的事件處理器、Reactor管理器

Reactor的結構

 
Reactor網路編程設計模式

Reactor模式要求主線程(I/O處理單元)只負責監聽文件描述符上是否有事件發生,若是有的話當即將該事件通知給工做線程(邏輯單元)。除此以外,主線程不作任何其它實質性的工做。讀寫數據、接收新鏈接、處理客戶端請求均在工做線程中完成。

  • Handle 文件描述符

Handle在Linux中通常稱爲文件描述符,在Windows中稱爲句柄,二者含義同樣。Handle是事件的發源地。好比網絡socket、磁盤文件等。發生在Handle上的事件能夠有connectionready for readready for write等。

Handle是操做系統的句柄,是對資源在操做系統上的一種抽象,它能夠是打開的文件、一個Socket鏈接、Timer定時器等。因爲Rector模式通常使用在網絡編程中,於是這裏通常指的是Socket Handle,也就是一個網絡鏈接(connection/channel)。這個channel註冊到同步事件分離器中,以監聽Handle中發生的事件,對ServerSocketChannel能夠是CONNECT事件,對SocketChannel能夠是readwriteclose事件等。

  • Synchronous Event Demultiplexer 同步(多路)事件分離器

同步事件分離器本質上是系統調用,好比Linux中的selectpollepoll等。好比select()方法會一致阻塞直到文件描述符handle上有事件發生時纔會返回。

無限循環等待新請求的到來,一旦發現有新的事件到來就會通知初始事件分發器去調取特定的時間處理器。

  • Event Handler 事件處理器

事件處理器,定義一些回調方法或稱爲鉤子函數,當handle文件描述符上有事件發生時,回調方法便會執行。供初始事件分發器回調使用。

  • Concrete Event Handler 具體的事件處理器

具體的事件處理器,實現了Event Handler,在回調方法中實現具體的業務邏輯。

  • Initiation Dispatcher 初始事件分發器

初始事件分發器,提供了註冊、刪除、轉發Event Handler的方法。當Synchronous Event Demultiplexer檢測到handler上有事件發生時,便會通知initiation dispatcher調用特定的event handler的回調方法。

初始事件分發器用於管理Event Handler,定義註冊、移除EventHandler等。它還做爲Rector模式的入口調用Synchronous Event Demultiplexer同步多路事件分離器的select方法以阻塞等待事件返回,當阻塞等待返回時,根據事件發生的Handle將其分發給對應的Event Handle事件處理器進行處理,也就是回調EventHandler中的handle_event方法。

 
IO框架工做時序圖

事件多路分解器

現代操做系統大多提供了一種本機機制,該機制經過一種有效的方式處理併發和非阻塞資源,這種機制稱爲同步事件多路分解器或事件通知接口。

Reactor啓動流程

  1. 建立Reactor
  2. 註冊事件處理器
  3. 調用事件多路分發器進入無限事件循環
  4. 當操做系統通知某描述符狀態就緒時,事件分發器找出並調用此描述註冊的事件處理器。

使用同步IO模型(以epoll_wait爲例)實現的Reactor模式的工做流程

  1. 主線程向epoll內核事件表中註冊socket上的讀就緒事件
  2. 主線程調用epoll_wait等待socket上有數據可讀
  3. socket上有數據可讀時,epoll_wait通知主線程,主線程將socket可讀事件放入請求隊列。
  4. 休眠在請求隊列上的某個工做線程被喚醒,從socket中讀取數據並處理客戶端請求,而後向epoll內核事件表中註冊該socket上的寫就緒事件。
  5. 主線程調用epoll_wait等待socket可寫
  6. socket可寫時epoll_wait通知主線程,主線程將socket可寫事件放入請求隊列。
  7. 休眠在請求隊列上的某個工做線程被喚醒,向socket上寫入服務器處理客戶請求的結果。
 
Reactor模式的工做流程

案例

例如:使用Reactor實現的日誌服務器

日誌服務器中的Reactor模式實現分爲兩部分

  • 客戶端鏈接到日誌服務器
 
客戶端鏈接到日誌服務器
  • 客戶端向日志服務器寫入日誌
 
客戶端向日志服務器寫入日誌

例如:須要創建一個提供分佈式日誌服務的事件驅動服務器,客戶端向服務器發送請求記錄本身的狀態信息,信息包括錯誤通知、調試信息、表現診斷等。日誌服務器對於收到的信息進行分類和分發,具體包括顯示屏顯示、打印機打印、數據庫存儲等。

 
日誌服務器

爲了保證數據可靠性,客戶端和服務器之間的通訊協議一般選用TCP等面向鏈接的協議,經過IP和端口的四元組來確認客戶端和服務器。日誌服務器被多個客戶端同時使用,爲此日誌服務器須要保證多用戶鏈接請求和日誌記錄的併發性。

爲了保證併發性,可採用多線程的方式去實現該服務器,即每一個線程專門針對一個鏈接。然而使用多線程的方式實現服務器存在着如下問題:

  • 效率

多線程致使的上下文切換、同步、數據移動等可能帶來效率的降低。

  • 編程簡單性

多線程須要考慮複雜的併發設計,包括線程安全等諸多因素。

  • 可移植性

多線程在不一樣的操做系統下是不一樣的,所以會影響到可移植性。

因爲以上問題,多線程設計每每既不是最高效也不是最易於實現的方案,所以須要其餘方案來實現能夠並行請求的服務器。



做者:JunChow520
連接: https://www.jianshu.com/p/458e4b276607 來源:簡書 著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
相關文章
相關標籤/搜索