天天看點

Socket Server的N種并發模型彙總

本文主要介紹常見的Server的并發模型,這些模型與程式設計語言本身無關,有的程式設計語言可能在文法上直接透明了模型本質,是以開發者沒必要一定要基于模型去編寫,隻是需要知道和了解并發模型的構成和特點即可。

在了解并發模型之前,我們需要兩個必備的前置知識:

  • socket網絡程式設計
  • 多路IO複用機制
  • 多線程/多程序等并發程式設計理論

提綱

模型一

單線程Accept(無I/O複用)

模型二

單線程Accept+多線程讀寫業務(無I/O複用)

模型三

單線程多路I/O複用

模型四

單線程多路I/O複用+多線程讀寫業務(業務工作池)

模型五

單線程多路I/O複用+多線程多路I/O複用(線程池)

模型五(程序版)

單程序多路I/O複用+多程序多路I/O複用(程序池)

模型六

單線程多路I/O複用+多線程多路I/O複用+多線程

模型一、單線程Accept(無I/O複用)

01

模型結構圖

Socket Server的N種并發模型彙總

02

模型分析

① 主線程

main thread

執行阻塞Accept,每次用戶端Connect連結過來,

main thread

中accept響應并建立連接配接

② 建立連結成功,得到

Connfd1

套接字後, 依然在

main thread

串行處理套接字讀寫,并處理業務。

③ 在②處理業務中,如果有新用戶端

Connect

過來,

Server

無響應,直到目前套接字全部業務處理完畢。

④ 目前用戶端處理完後,完畢連結,處理下一個用戶端請求。

03

優缺點

優點:

  • socket程式設計流程清晰且簡單,适合學習使用,了解socket基本程式設計流程。

缺點:

  • 該模型并非并發模型,是串行的伺服器,同一時刻,監聽并響應最大的網絡請求量為

    1

    。即并發量為

    1

  • 僅适合學習基本socket程式設計,不适合任何伺服器Server建構。

模型二、單線程Accept+多線程讀寫業務(無I/O複用)

01

模型結構圖

Socket Server的N種并發模型彙總

02

模型分析

① 主線程

main thread

執行阻塞Accept,每次用戶端Connect連結過來,

main thread

中accept響應并建立連接配接

② 建立連結成功,得到

Connfd1

套接字後,建立一個新線程

thread1

用來處理用戶端的讀寫業務。

main thead

依然回到

Accept

阻塞等待新用戶端。

thread1

通過套接字

Connfd1

與用戶端進行通信讀寫。

④ server在②處理業務中,如果有新用戶端

Connect

過來,

main thread

Accept

依然響應并建立連接配接,重複②過程。

03

優缺點

優點:

  • 基于

    模型一:單線程Accept(無IO複用)

    支援了并發的特性。
  • 使用靈活,一個用戶端對應一個線程單獨處理,

    server

    處理業務内聚程度高,用戶端無論如何寫,服務端均會有一個線程做資源響應。

缺點:

  • 随着用戶端的數量增多,需要開辟的線程也增加,用戶端與server線程數量

    1:1

    正比關系,一次對于高并發場景,線程數量受到硬體上限瓶頸。
  • 對于長連結,用戶端一旦無業務讀寫,隻要不關閉,server的對應線程依然需要保持連接配接(心跳、健康監測等機制),占用連接配接資源和線程開銷資源浪費。
  • 僅适合用戶端數量不大,并且數量可控的場景使用。

僅适合學習基本socket程式設計,不适合任何伺服器Server建構。

模型三、單線程多路I/O複用

01

模型結構圖

Socket Server的N種并發模型彙總

02

模型分析

① 主線程

main thread

建立

listenFd

之後,采用多路I/O複用機制(如:select、epoll)進行IO狀态阻塞監控。有

Client1

用戶端

Connect

請求,I/O複用機制檢測到

ListenFd

觸發讀事件,則進行

Accept

建立連接配接,并将新生成的

connFd1

加入到

監聽I/O集合

中。

Client1

再次進行正常讀寫業務請求,

main thread

多路I/O複用機制

阻塞傳回,會觸該套接字的讀/寫事件等。

③ 對于

Client1

的讀寫業務,Server依然在

main thread

執行流程繼續執行,此時如果有新的用戶端

Connect

連結請求過來,Server将沒有即時響應。

④ 等到Server處理完一個連接配接的

Read+Write

操作,繼續回到

多路I/O複用機制

阻塞,其他連結過來重複 ②、③流程。

03

優缺點

優點:

  • 單流程解決了可以同時監聽多個用戶端讀寫狀态的模型,不需要

    1:1

    與用戶端的線程數量關系。
  • 多路I/O複用阻塞,非忙輪詢狀态,不浪費CPU資源, CPU使用率較高。

缺點:

  • 雖然可以監聽多個用戶端的讀寫狀态,但是同一時間内,隻能處理一個用戶端的讀寫操作,實際上讀寫的業務并發為1。
  • 多用戶端通路Server,業務為串行執行,大量請求會有排隊延遲現象,如圖中⑤所示,當

    Client3

    占據

    main thread

    流程時,

    Client1,Client2

    流程卡在

    IO複用

    等待下次監聽觸發事件。

模型四、單線程多路I/O複用+多線程讀寫業務

(業務工作池)

01

模型結構圖

Socket Server的N種并發模型彙總

02

模型分析

① 主線程

main thread

建立

listenFd

之後,采用多路I/O複用機制(如:select、epoll)進行IO狀态阻塞監控。有

Client1

用戶端

Connect

請求,I/O複用機制檢測到

ListenFd

觸發讀事件,則進行

Accept

建立連接配接,并将新生成的

connFd1

加入到

監聽I/O集合

中。

② 當

connFd1

有可讀消息,觸發讀事件,并且進行讀寫消息

main thread

按照固定的協定讀取消息,并且交給

worker pool

工作線程池, 工作線程池在server啟動之前就已經開啟固定數量的

thread

,裡面的線程隻處理消息業務,不進行套接字讀寫操作。

④ 工作池處理完業務,觸發

connFd1

寫事件,将回執用戶端的消息通過

main thead

寫給對方。

03

優缺點

優點:

  • 對于

    模型三

    , 将業務處理部分,通過工作池分離出來,減少多用戶端通路Server,業務為串行執行,大量請求會有排隊延遲時間。
  • 實際上讀寫的業務并發為1,但是業務流程并發為worker pool線程數量,加快了業務處理并行效率。

缺點:

  • 讀寫依然為

    main thread

    單獨處理,最高讀寫并行通道依然為1.
  • 雖然多個worker線程處理業務,但是最後傳回給用戶端,依舊需要排隊,因為出口還是

    main thread

    Read + Write

模型五、單線程I/O複用+多線程I/O複用

(線程池)

01

模型結構圖

Socket Server的N種并發模型彙總

02

模型分析

① Server在啟動監聽之前,開辟固定數量(N)的線程,用

Thead Pool

線程池管理

② 主線程

main thread

建立

listenFd

之後,采用多路I/O複用機制(如:select、epoll)進行IO狀态阻塞監控。有

Client1

用戶端

Connect

請求,I/O複用機制檢測到

ListenFd

觸發讀事件,則進行

Accept

建立連接配接,并将新生成的

connFd1

分發給

Thread Pool

中的某個線程進行監聽。

Thread Pool

中的每個

thread

都啟動

多路I/O複用機制(select、epoll)

,用來監聽

main thread

建立成功并且分發下來的socket套接字。

④ 如圖,

thread

監聽

ConnFd1、ConnFd2

,

thread2

監聽

ConnFd3

,

thread3

監聽

ConnFd4

. 當對應的

ConnFd

有讀寫事件,對應的線程處理該套接字的讀寫及業務。

03

優缺點

優點:

  • main thread

    的單流程讀寫,分散到多線程完成,這樣增加了同一時刻的讀寫并行通道,并行通道數量

    N

    N

    為線程池

    Thread

    數量。
  • server同時監聽的

    ConnFd套接字

    數量幾乎成倍增大,之前的全部監控數量取決于

    main thread

    多路I/O複用機制

    的最大限制(select 預設為1024, epoll預設與記憶體大小相關,約3~6w不等),是以理論單點Server最高響應并發數量為

    N*(3~6W)

    (

    N

    為線程池

    Thread

    數量,建議與CPU核心成比例1:1)。
  • 如果良好的線程池數量和CPU核心數适配,那麼可以嘗試CPU核心與Thread進行綁定,進而降低CPU的切換頻率,提升每個

    Thread

    處理合理業務的效率,降低CPU切換成本開銷。

缺點:

  • 雖然監聽的并發數量提升,但是最高讀寫并行通道依然為

    N

    ,而且多個身處同一個Thread的用戶端,會出現讀寫延遲現象,實際上每個

    Thread

    的模型特征與

    模型三:單線程多路IO複用

    一緻。

模型五(程序版)、單程序多路I/O複用+多程序多路I/O複用

(程序池)

01

模型結構圖

Socket Server的N種并發模型彙總

02

模型分析

五、單線程IO複用+多線程IO複用(連結線程池)

無大差異。

不同處

  • 程序和線程的記憶體布局不同導緻,

    main process

    (主程序)不再進行

    Accept

    操作,而是将

    Accept

    過程分散到各個

    子程序(process)

    中.
  • 程序的特性,資源獨立,是以

    main process

    如果Accept成功的fd,其他程序無法共享資源,是以需要各子程序自行Accept建立連結
  • main process

    隻是監聽

    ListenFd

    狀态,一旦觸發讀事件(有新連接配接請求). 通過一些IPC(程序間通信:如信号、共享記憶體、管道)等, 讓各自子程序

    Process

    競争

    Accept

    完成連結建立,并各自監聽。

03

優缺點

五、單線程IO複用+多線程IO複用(連結線程池)

無大差異。

不同處:

多程序記憶體資源空間占用稍微大一些

多程序模型安全穩定性較強,這也是因為各自程序互不幹擾的特點導緻。

模型六、單線程多路I/O複用+多線程多路I/O複用+多線程

01

模型結構圖

Socket Server的N種并發模型彙總

02

模型分析

① Server在啟動監聽之前,開辟固定數量(N)的線程,用

Thead Pool

線程池管理

② 主線程

main thread

建立

listenFd

之後,采用多路I/O複用機制(如:select、epoll)進行IO狀态阻塞監控。有

Client1

用戶端

Connect

請求,I/O複用機制檢測到

ListenFd

觸發讀事件,則進行

Accept

建立連接配接,并将新生成的

connFd1

分發給

Thread Pool

中的某個線程進行監聽。

Thread Pool

中的每個

thread

都啟動

多路I/O複用機制(select、epoll)

,用來監聽

main thread

建立成功并且分發下來的socket套接字。一旦其中某個被監聽的用戶端套接字觸發

I/O讀寫事件

,那麼,會立刻開辟一個新線程來處理

I/O讀寫

業務。

④ 但某個讀寫線程完成目前讀寫業務,如果目前套接字沒有被關閉,那麼将目前用戶端套接字

如:ConnFd3

重新加回線程池的監控線程中,同時自身線程自我銷毀。

03

優缺點

優點:

  • 模型五、單線程IO複用+多線程IO複用(連結線程池)

    基礎上,除了能夠保證同時響應的

    最高并發數

    ,又能解決

    讀寫并行通道

    局限的問題。
  • 同一時刻的讀寫并行通道,達到

    最大化極限

    ,一個用戶端可以對應一個單獨執行流程處理讀寫業務,讀寫并行通道與用戶端數量

    1:1

    關系。

缺點:

  • 該模型過于理想化,因為要求CPU核心數量足夠大。
  • 如果硬體CPU數量可數(目前的硬體情況),那麼該模型将造成大量的CPU切換成本浪費。因為為了保證讀寫并行通道與用戶端

    1:1

    的關系,那麼Server需要開辟的

    Thread

    數量就與用戶端一緻,那麼線程池中做

    多路I/O複用

    的監聽線程池綁定CPU數量将變得毫無意義。
  • 如果每個臨時的讀寫

    Thread

    都能夠綁定一個單獨的CPU,那麼此模型将是最優模型。但是目前CPU的數量無法與用戶端的數量達到一個量級,目前甚至差的不是幾個量級的事。

總結

綜上,我們整理了7中Server的伺服器處理結構模型,每個模型都有各自的特點和優勢,那麼對于多少應付高并發和高CPU使用率的模型,目前多數采用的是模型五(或模型五程序版,如Nginx就是類似模型五程序版的改版)。

至于并發模型并非設計的越複雜越好,也不是線程開辟的越多越好,我們要考慮硬體的利用與和切換成本的開銷。“模型六”設計就極為複雜,線程較多,但以當今的硬體能力無法支撐,反倒導緻該模型性能極差。是以對于不同的業務場景也要選擇适合的模型建構,并不是一定固定就要使用某個來應用。

感謝觀看!