redis執行緒模式

來源:互聯網
上載者:User

標籤:順序   sys   數組   event   就是   通過   port   操作   初始化   

0. 前言

Redis 基於 Reactor 模式開發了自己的網路事件處理器: 這個處理器被稱為檔案事件處理器(file event handler):

  • 檔案事件處理器使用 I/O 多工(multiplexing)程式來同時監聽多個通訊端, 並根據通訊端目前執行的任務來為通訊端關聯不同的事件處理器。
  • 當被監聽的通訊端準備好執行串連應答(accept)、讀取(read)、寫入(write)、關閉(close)等操作時, 與操作相對應的檔案事件就會產生, 這時檔案事件處理器就會調用通訊端之前關聯好的事件處理器來處理這些事件。

雖然檔案事件處理器以單線程方式運行, 但通過使用 I/O 多工程式來監聽多個通訊端, 檔案事件處理器既實現了高效能的網路通訊模型, 又可以很好地與 redis 伺服器中其他同樣以單線程方式啟動並執行模組進行對接, 這保持了 Redis 內部單線程設計的簡單性。

1. 檔案事件處理器的構成

展示了檔案事件處理器的四個組成部分, 它們分別是通訊端、 I/O 多工程式、 檔案事件指派器(dispatcher)、 以及事件處理器。

檔案事件是對通訊端操作的抽象, 每當一個通訊端準備好執行串連應答(accept)、寫入、讀取、關閉等操作時, 就會產生一個檔案事件。 因為一個伺服器通常會串連多個通訊端, 所以多個檔案事件有可能會並發地出現。

I/O 多工程式負責監聽多個通訊端, 並向檔案事件指派器傳送那些產生了事件的通訊端。

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

檔案事件指派器接收 I/O 多工程式傳來的通訊端, 並根據通訊端產生的事件的類型, 調用相應的事件處理器。

伺服器會為執行不同任務的通訊端關聯不同的事件處理器,這些處理器是一個個函數, 它們定義了某個事件發生時, 伺服器應該執行的動作。

2. 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 在 I/O 多工程式的實現源碼中用 #include 宏定義了相應的規則, 程式會在編譯時間自動選擇系統中效能最高的 I/O 多工函數庫來作為 Redis 的 I/O 多工程式的底層實現。

3. 事件的類型

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 事件。

這也就是說, 如果一個通訊端又可讀又可寫的話, 那麼伺服器將先讀通訊端, 後寫通訊端。

4. API

ae.c/aeCreateFileEvent 函數接受一個通訊端描述符、 一個事件類型、 以及一個事件處理器作為參數, 將給定通訊端的給定事件加入到 I/O 多工程式的監聽範圍之內, 並對事件和事件處理器進行關聯。

ae.c/aeDeleteFileEvent 函數接受一個通訊端描述符和一個監聽事件類型作為參數, 讓 I/O 多工程式取消對給定通訊端的給定事件的監聽, 並取消事件和事件處理器之間的關聯。

ae.c/aeGetFileEvents 函數接受一個通訊端描述符, 返回該通訊端正在被監聽的事件類型:

  • 如果通訊端沒有任何事件被監聽, 那麼函數返回 AE_NONE 。
  • 如果通訊端的讀事件正在被監聽, 那麼函數返回 AE_READABLE 。
  • 如果通訊端的寫事件正在被監聽, 那麼函數返回 AE_WRITABLE 。
  • 如果通訊端的讀事件和寫事件正在被監聽, 那麼函數返回 AE_READABLE | AE_WRITABLE 。

ae.c/aeWait 函數接受一個通訊端描述符、一個事件類型和一個毫秒數為參數, 在給定的時間內阻塞並等待通訊端的給定類型事件產生, 當事件成功產生, 或者等待逾時之後, 函數返回。

ae.c/aeApiPoll 函數接受一個 sys/time.h/struct timeval 結構為參數, 並在指定的時間內, 阻塞並等待所有被 aeCreateFileEvent 函數設定為監聽狀態的通訊端產生檔案事件, 當有至少一個事件產生, 或者等待逾時後, 函數返回。

ae.c/aeProcessEvents 函數是檔案事件指派器, 它先調用 aeApiPoll 函數來等待事件產生, 然後遍曆所有已產生的事件, 並調用相應的事件處理器來處理這些事件。

ae.c/aeGetApiName 函數返回 I/O 多工程式底層所使用的 I/O 多工函數庫的名稱: 返回 "epoll" 表示底層為 epoll 函數庫, 返回"select" 表示底層為 select 函數庫, 諸如此類。

5. 檔案事件的處理器

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

  • 為了對串連伺服器的各個用戶端進行應答, 伺服器要為監聽通訊端關聯串連應答處理器。
  • 為了接收用戶端傳來的命令請求, 伺服器要為用戶端通訊端關聯命令要求處理常式。
  • 為了向用戶端返回命令的執行結果, 伺服器要為用戶端通訊端關聯命令回複處理器。
  • 當主伺服器和從伺服器進行複製操作時, 主從伺服器都需要關聯特別為複製功能編寫的複製處理器。
  • 等等。
    在這些事件處理器裡面,伺服器最常用的要數與用戶端進行通訊的串連應答處理器、 命令要求處理常式和命令回複處理器。
5.1 串連應答處理器

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

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

5.2 命令要求處理常式

networking.c/readQueryFromClient 函數是 Redis 的命令要求處理常式, 這個處理器負責從通訊端中讀入用戶端發送的命令請求內容, 具體實現為 unistd.h/read 函數的封裝。

當一個用戶端通過串連應答處理器成功串連到伺服器之後, 伺服器會將用戶端通訊端的 AE_READABLE 事件和命令要求處理常式關聯起來, 當用戶端向伺服器發送命令請求的時候, 通訊端就會產生 AE_READABLE 事件, 引發命令要求處理常式執行, 並執行相應的通訊端讀入操作, 如所示。

在用戶端串連伺服器的整個過程中, 伺服器都會一直為用戶端通訊端的 AE_READABLE 事件關聯命令要求處理常式。

5.3 命令回複處理器

networking.c/sendReplyToClient 函數是 Redis 的命令回複處理器, 這個處理器負責將伺服器執行命令後得到的命令回複通過通訊端返回給用戶端, 具體實現為 unistd.h/write 函數的封裝。

當伺服器有命令回複需要傳送給用戶端的時候, 伺服器會將用戶端通訊端的 AE_WRITABLE 事件和命令回複處理器關聯起來, 當用戶端準備好接收伺服器傳回的命令回複時, 就會產生 AE_WRITABLE 事件, 引發命令回複處理器執行, 並執行相應的通訊端寫入操作, 如所示。

當命令回複發送完畢之後, 伺服器就會解除命令回複處理器與用戶端通訊端的 AE_WRITABLE 事件之間的關聯。

5.4 一次完整的用戶端與伺服器串連事件樣本

讓我們來追蹤一次 Redis 用戶端與伺服器進行串連並發送命令的整個過程, 看看在過程中會產生什麼事件, 而這些事件又是如何被處理的。

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

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

之後, 假設用戶端向主伺服器發送一個命令請求, 那麼用戶端通訊端將產生 AE_READABLE 事件, 引發命令要求處理常式執行, 處理器讀取用戶端的命令內容, 然後傳給相關程式去執行。

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

總結了上面描述的整個通訊過程, 以及通訊時用到的事件處理器。

5.5 接收網路連接

完成了服務端的網路初始化,而且事件輪詢者已經開始工作了,事件輪詢者做什麼事情呢,就是不斷輪訓多工器,看看之前註冊的事件有沒有發生,如果有發生,則將會將事件分離出來,放入EventLoop的fired數組中,然後處理這些事件。

Redis會不斷的輪訓多工器,將網路事件分離出來,如果是accept事件,則新接收用戶端串連並將其註冊到多工器以及EventLoop中,如果是查詢事件,則通過讀取用戶端的命令進行相應的處理,這一切都是單線程,順序的執行的,因此不會發生並發問題。

參考:
73732883

redis執行緒模式

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.