首頁  >  文章  >  資料庫  >  為什麼說redis是單線程的

為什麼說redis是單線程的

王林
王林轉載
2021-01-11 09:31:571735瀏覽

為什麼說redis是單線程的

Redis即遠端字典服務,是一個開源的使用ANSI C語言編寫、支援網路、可基於記憶體亦可持久化的日誌型、Key-Value資料庫,並提供多種語言的API。

(學習影片分享:redis影片教學

檔案事件處理器

Redis基於Reactor模式開發了網路事件處理器,這個處理器被稱為檔案事件處理器。它的組成結構為4部分:多個套接字、IO多工程式、檔案事件分派器、事件處理器。因為檔案事件分派器佇列的消費是單線程的,所以Redis才叫單線程模型。

為什麼說redis是單線程的

訊息處理流程

檔案事件處理器使用I/O多路復用(multiplexing)程式來同時監聽多個套接字,並根據套接字目前執行的任務來為套接字關聯不同的事件處理器。

當被監聽的套接字準備好執行連接應答(accept)、讀取(read)、寫入(write)、關閉(close)等操作時,與操作相對應的檔案事件就會產生,這時檔案事件處理器就會呼叫套接字之前關聯好的事件處理器來處理這些事件。

儘管多個檔案事件可能會並發地出現,但I/O多路復用程式總是會將所有產生事件的套接字都推到一個佇列裡面,然後通過這個佇列,以有序(sequentially)、同步(synchronously)、每次一個套接字的方式向文件事件分派器傳送套接字:當上一個套接字產生的事件被處理完畢之後(該套接字為事件所關聯的事件處理器執行完畢), I/O多工程式才會繼續傳送下一個套接字到檔案事件分派器。

I/O 多工程式的實作

Redis的I/O多工程式的所有功能是透過包裝select、epoll、evport和kqueue這些I/O多路復用函數庫來實現的,每個I/O多路復用函數庫在Redis原始碼中都對應一個單獨的文件,例如ae_select.c、ae_epoll.c、ae_kqueue.c等。

因為Redis為每個I/O多路復用函數庫都實作了相同的API,所以I/O多路復用程式的底層實作是可以互換的,如下圖所示。

為什麼說redis是單線程的

有關epoll的詳細講解,可以點擊查看,徹底搞懂epoll高效運行的原理

Redis在I/O多路復用程式的實作原始碼中用#include巨集定義了對應的規則,程式會在編譯時自動選擇系統中效能最好的I/O多工函數函式庫來作為Redis的I/O多工程式的底層實作:

/* Include the best multiplexing layer supported by this system.
 * The following should be ordered by performances, descending. */
#ifdef HAVE_EVPORT
#include "ae_evport.c"
#else
    #ifdef HAVE_EPOLL
    #include "ae_epoll.c"
    #else
        #ifdef HAVE_KQUEUE
        #include "ae_kqueue.c"
        #else
        #include "ae_select.c"
        #endif
    #endif
#endif

檔案事件的類型

I/O 多重化程式可以監聽多個套接字的ae.h/AE_READABLE事件和ae.h/AE_WRITABLE事件,這兩類別事件和套接字操作之間的對應關係如下:

當套接字變得可讀時(客戶端對套接字執行write操作,或執行close操作),或有新的可應答(acceptable)套接字出現時(客戶端對伺服器的監聽套接字執行connect操作),套接字會產生AE_READABLE 事件。

當套接字變得可寫時(客戶端對套接字執行read操作),套接字產生AE_WRITABLE事件。 I/O多工程式允許伺服器同時監聽套接字的AE_READABLE事件和AE_WRITABLE事件,如果一個套接字同時產生了這兩種事件,那麼檔案事件分派器會優先處理AE_READABLE事件,等到AE_READABLE事件處理完畢後,才處理AE_WRITABLE 事件。這也就是說,如果一個套接字又可讀又可寫的話,那麼伺服器將先讀套接字,後寫套接字。

檔案事件的處理器

Redis為檔案事件編寫了多個處理器,這些事件處理器分別用於實現不同的網路通訊需求,常用的處理器如下:

為了對連接伺服器的各個客戶端進行應答, 伺服器要為監聽套接字關聯連接應答處理器。

為了接收客戶端傳來的命令請求, 伺服器要為客戶端套接字關聯命令請求處理器。

為了傳回客戶端指令的執行結果, 伺服器要為客戶端套接字關聯指令回覆處理器。

連接應答處理器

networking.c中acceptTcpHandler函數是Redis的連接應答處理器,這個處理器用於對連接伺服器監聽套接字的客戶端進行應答,具體實現為sys/socket.h/accept函數的包裝。

當Redis伺服器進行初始化的時候,程式會將這個連接應答處理器和伺服器監聽套接字的AE_READABLE事件關聯起來,當有客戶端用sys/socket.h/connect函數連接伺服器監聽套接字的時候, 套接字就會產生AE_READABLE 事件, 引發連接應答處理器執行, 並執行對應的套接字應答操作,如圖所示。

為什麼說redis是單線程的

指令請求處理器

networking.c中readQueryFromClient函式是Redis的指令請求處理器,這個處理器負責從套接字讀入客戶端發送的命令請求內容, 具體實作為unistd.h/read函數的包裝。

當一個客戶端透過連接應答處理器成功連接到伺服器之後, 伺服器會將客戶端套接字的AE_READABLE事件和命令請求處理器關聯起來,當客戶端向伺服器發送命令請求的時候,套接字就會產生AE_READABLE事件,引發指令請求處理器執行,並執行對應的套接字讀入操作,如圖所示。

為什麼說redis是單線程的

在客戶端連接伺服器的整個過程中,伺服器都會一直為客戶端套接字的AE_READABLE事件關聯命令請求處理器。

指令回覆處理器

networking.c中sendReplyToClient函數是Redis的指令回覆處理器,這個處理器負責將伺服器執行指令後得到的指令回覆透過套接字回傳給客戶端,具體實作為unistd.h/write函數的包裝。

當伺服器有命令回覆需要傳送給客戶端的時候,伺服器會將客戶端套接字的AE_WRITABLE事件和命令回復處理器關聯起來,當客戶端準備好接收伺服器傳回的命令回复時,就會產生AE_WRITABLE事件,引發指令回覆處理器執行,並執行對應的套接字寫入操作, 如圖所示。

為什麼說redis是單線程的

當指令回覆傳送完畢之後, 伺服器就會解除指令回覆處理器與客戶端套接字的 AE_WRITABLE 事件之間的關聯。

一次完整的客戶端與伺服器連線事件範例

假設Redis伺服器正在運作,那麼這個伺服器的監聽套接字的AE_READABLE事件應該是處於監聽狀態之下,而該事件所對應的處理器為連接應答處理器。

如果這時有一個Redis客戶端向Redis伺服器發起連接,那麼監聽套接字將產生AE_READABLE事件, 觸發連接應答處理器執行:處理器會對客戶端的連接請求進行應答, 然後創建客戶端套接字,以及客戶端狀態,並將客戶端套接字的AE_READABLE 事件與命令請求處理器進行關聯,使得客戶端可以向主伺服器發送命令請求。

之後,客戶端向Redis伺服器發送一個命令請求,那麼客戶端套接字將產生AE_READABLE事件,引發命令請求處理器執行,處理器讀取客戶端的命令內容, 然後傳給相關程序去執行。

執行命令將產生相應的命令回复,為了將這些命令回復傳送回客戶端,伺服器會將客戶端套接字的AE_WRITABLE事件與命令回复處理器進行關聯:當客戶端嘗試讀取命令回复的時候,客戶端套接字將產生AE_WRITABLE事件, 觸發命令回复處理器執行, 當命令回复處理器將命令回復全部寫入到套接字之後, 伺服器就會解除客戶端套接字的AE_WRITABLE事件與命令回覆處理器之間的關聯。

為什麼說redis是單線程的

相關推薦:redis資料庫教學

#

以上是為什麼說redis是單線程的的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:csdn.net。如有侵權,請聯絡admin@php.cn刪除