Redis使用IO多路複用進行事件處理機制

jock_javaEE發表於2024-11-06

一、epoll多路複用

這裡重點要說的就是redis的IO程式設計模型,首先了解下


為什麼要有多路複用呢 ?


案例

引用知乎上一個高讚的回答來解釋什麼是I/O多路複用。假設你是一個老師,讓30個學生解答一道題目,然後檢查學生做的是否正確,你有下面幾個選擇:


第一種選擇:按順序逐個檢查,先檢查A,然後是B,之後是C、D....這中間如果有一個學生卡住,全班都會被耽誤。這種模式就好比,你用迴圈挨個處理socket,根本不具有併發能力。


第二種選擇:你建立30個分身,每個分身檢查一個學生的答案是否正確。 這種類似於為每一個使用者建立一個程序或者 - 執行緒處理連線。


第三種選擇,你站在講臺上等,誰解答完誰舉手。這時C、D舉手,表示他們解答問題完畢,你下去依次檢查C、D的答案,然後繼續回到講臺上等。此時E、A又舉手,然後去處理 E 和 A。


如果沒有多路複用,一個執行緒只能監聽一個埠的一個連線,這樣這個效率比較低。當然我們有幾種辦法可以破除這個,一個是使用多執行緒模型,我們還是監聽一個埠,

但是一個請求進來,我們為其建立一個執行緒。但是這種消耗是比較大的。所以我們一直想辦法,有沒有辦法一個執行緒監聽多個埠,或者多個一個埠的多個連線(fd)。


這裡再說說fd, 檔案描述符(file descriptor)是核心為了高效管理已被開啟的檔案所建立的索引,其是一個非負整數(通常是小整數),用於指代被開啟的檔案,

所有執行I/O操作(包括網路socket操作)的系統呼叫都透過檔案描述符。每個連線請求上來,都會建立一個連線套接字,一個連線使用一個連線套接字。


對於監聽埠,我們會有一個監聽套接字,對應監聽fd。我們所有的監聽業務都是從監聽這個套接字開始的。


那麼如果我一個程式能同時監聽多個連線套接字,是不是就很讚了。是的,這就是linux的io多路複用邏輯。但是這麼多連線套接字,傳遞資料等是斷斷續續的,

A連線接收一個包,B連線再接收一個包,A連線再接收一個包,B連線再接收一個包....如果我等著A連線把包都接收完再處理B,那效率是非常慢的。所以,

這裡我們就需要有一個通知機制,讓有收到包的時候通知下處理執行緒。


linux的IO多路複用邏輯主要有三種:select、 poll、 epoll


select

select模型監聽的三個事件:讀資料事件,寫資料事件,異常事件。


使用select模型的步驟如下:

  • 我們確定要監聽的監聽fd列表

  • 呼叫select監聽所有監聽fd,阻塞執行緒。

  • select只有當有事件出現並且有事件的fd已經等待完畢

  • 如果是建立一個連線事件:

    • 建立一個連線套接字,連線fd

    • 將連線fd和監聽fd集合放在一起


如果是一個讀寫事件:

  • 遍歷所有fd,判斷是否是準備好的fd

  • 如果是準備好的fd,進行業務讀寫邏輯


poll模型:


poll傳遞給核心的是:

  • 監聽的fd集合

  • 需要監聽的事件型別

  • 實際發生的事件型別


poll的模型邏輯是:

  • 我們確定要監聽的監聽fd列表

  • 呼叫poll監聽所有監聽fd,阻塞執行緒。

  • poll只有當有事件出現才解除阻塞

  • 如果是建立一個連線事件:

    • 建立一個連線套接字,連線fd

    • 將連線fd和監聽fd集合放在一起


如果是一個讀寫事件:

  • 遍歷所有fd,判斷是否是有讀寫事件的fd

  • 如果fd有讀寫事件,進行業務讀寫邏輯

相關文章