事件 - 《Redis設計與實現》讀書筆記
阿新 • • 發佈:2021-08-11
Redis伺服器是一個事件驅動程式
,伺服器處理的事件分為時間事件
和檔案事件
兩種型別
檔案事件
伺服器對套接字操作的抽象
Redis伺服器通過套接字與客戶端(或者其他Redis伺服器)進行連線
伺服器與客戶端(或者其他伺服器)的通訊會產生相應的檔案事件,而伺服器則通過監聽並處理
這些事件來完成一系列網路通訊操作
- 組成
/* File event structure */ typedef struct aeFileEvent { // 檔案事件類別:AE_READABLE、AE_WRITABLE、AE_BARRIER // 當客戶端對套接字執行connect、寫入write、關閉close操作,產生AE_READABLE事件 // 當客戶端對套接字執行read操作,產生AE_WRITABLE事件 // 如果一個套接字又可讀又可寫的話,那麼伺服器將先讀套接字,後寫套接字 int mask; // 檔案事件讀處理器 aeFileProc *rfileProc; // 檔案事件寫處理器 aeFileProc *wfileProc; void *clientData; } aeFileEvent;
檔案事件處理器
-
基於Reactor模式實現的網路通訊程式
-
實現原理
使用I/O多路複用程式同時監聽多個
套接字,
當被監聽的套接字準備好執行連線應答accept、讀取read、寫入write、關閉close等操作時,與操作相對應的檔案事件就會產生,
將所有產生事件的套接字都放到一個佇列
裡面,通過這個佇列,以阻塞、有序、同步、每次一個
的方式向檔案事件分派器傳送套接字,
經過檔案事件分派器
進行分發,根據套接字目前執行的任務來為套接字關聯
不同的事件處理器 -
組成
- 套接字
- I/O多路複用程式:evport、epoll、kqueue、select
自動選擇系統中效能最高的I/O多路複用函式庫作為底層
#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
- 檔案事件分派器:src/ae.c/aeProcessEvents
- 事件處理器
- 連線應答處理器:src/networking.c/acceptTcpHandler
- 命令請求處理器:src/networking.c/readQueryFromClient
- 命令回覆處理器:src/networking.c/sendReplyToClient
時間事件
伺服器在一般情況下只執行serverCron
函式這一個週期性時間事件
實現原理
:伺服器將所有時間事件都放在一個無序連結串列(不按when屬性的大小排序)
中,每當時間事件執行期執行時,遍歷整個連結串列,查詢所有已到達的時間事件,並呼叫相應的事件處理器
- 組成
typedef struct aeTimeEvent {
// 全域性唯一標識號ID,ID
long long id;
// 時間事件的到達事件,單位為微秒
monotime when;
// 時間事件處理器
aeTimeProc *timeProc;
aeEventFinalizerProc *finalizerProc;
void *clientData;
struct aeTimeEvent *prev;
struct aeTimeEvent *next;
int refcount;
} aeTimeEvent;
- 分類
- 定時事件:事件處理器返回
是
src/ae.h/AE_NOMORE值 - 週期性事件:事件處理器返回
不是
src/ae.h/AE_NOMORE值
- 定時事件:事件處理器返回
事件的排程與執行規則
- 檔案事件和時間事件之間是合作關係,伺服器會
輪流處理
這兩種事件,並且處理事件的過程中不會進行搶佔 - 對檔案事件和時間事件的處理都是
同步、有序、原子地執行
的,伺服器不會中途中斷
事件處理,也不會對事件進行搶佔
時間事件的實際處理事件通常會比設定的到達時間晚一些
,主要因為時間事件在檔案事件之後執行