中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么理解Redis中的epoll和文件事件

發布時間:2021-11-03 11:05:41 來源:億速云 閱讀:256 作者:iii 欄目:關系型數據庫

這篇文章主要講解了“怎么理解Redis中的epoll和文件事件”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“怎么理解Redis中的epoll和文件事件”吧!

怎么理解Redis中的epoll和文件事件

事件驅動

Redis 服務器是事件驅動程序,分為文件事件時間事件

  • 文件事件:socket 的可讀可寫事件

  • 定時任務

它們都被封裝到aeEventLoop結構體中

typedef struct aeEventLoop {
	int stop; // 標識事件是否結束
	aeFileEvent *events; // 文件事件數組,存儲已注冊的文件事件
	aeFireEvent *fired; // 存儲被觸發的文件事件
	aeTimeEvent *timteEventHead; // 多個時間事件形成的鏈表
	void *apidata; // I/O模型的封裝
	aeBeforeSleepProc *beforesleep; // 進程阻塞前執行
	aeBeforeSleepProc *aftersleep; // 進程被喚醒后執行
} aeEventLoop;

事件驅動程序實際上也是通過while/for循環,循環等待事件的發生

while (! eventLoop->stop) {
	if (eventLoop->beforesleep != NULL)
		eventLoop->beforesleep(eventLoop)
	aeProcessEvents(eventLoop, AE_ALL_EVENTS|AE_CALL_AFTER_SLEEP);
}

aeProcessEvents為事件處理主函數

epoll

Redis 客戶端通過 TCP socket 與服務端交互,文件事件指的就是 socket 的可讀可寫事件。一般使用非阻塞模式,相關的 I/O 多路復用有select/epoll/kqueue等,不同的操作系統不同的實現。

epoll為例,它是 Linux 內核為處理大量并發網絡連接而提出解決方案。epoll提供3個 API

  • epoll_create 創建一個 epoll 專用的文件描述符,用于后續 epoll 相關 API 調用

int epoll_create(int size)
// size 告知內核程序期望注冊的網絡連接數目,Linux 2.6.8后改為內核動態分配
// 返回參數是 epoll 專用的文件描述符
  • epoll_ctl 函數向 epoll 注冊、修改或刪除需要監控的事件

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
// epfd 函數 epoll_create 返回的 epoll 文件描述符
// op 操作類型 EPOLL_CTL_ADD:注冊事件; EPOLL_CTL_MOD:修改網絡連接事件; EPOLL_CTL_DEL:刪除事件
// fd 網絡連接的 socket 文件描述符
// event 需要監控的事件
  • epoll_wait 函數會會阻塞進程,直到監控的若干網絡連接有事件發生

int epoll_wait(int epfd, struct epoll_event *event, int maxevents, int timeout)
// epfd 函數epoll_create返回的epoll文件描述符
// epoll_event 作為輸出參數使用,用于回傳已觸發的事件數組
// maxevents 每次能處理的最大事件數目
// timeout epoll_wait 函數阻塞超時時間,如果超過 timeout 時間還沒有事件發生,函數就不再阻塞直接返回;當 timeout 等于0是函數立即返回,timeout 等于-1時函數一直阻塞到有事件發生

文件事件

Reids 沒有直接使用 epoll 的 API,而是同時支持4種I/O多路復用模型,對這些模型的 API 進行了封裝。然后在編譯階段檢查操作系統支持的I/O多路復用模型,并按照策略來決定復用那張模型。

還是以 epoll 為例,Redis 進行了如下封裝

// 對應 epoll_create
static int aeApiCreate(aeEventLoop *eventLoop)

// 對應 epoll_ctl 添加事件
static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask)
// 對應 epoll_ctl 刪除事件
static int aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask)

// 對應 epoll_wait
static int aeApiPool(aeEventLoop *eventLoop, struct timeval *tvp)

回憶一下上面提到的eventLoop結構體,其成員 apidata 指向4種I/O多路復用模型對象;events 存儲需要監控的事件數組,以 socket 文件描述符作為數組索引存取元素;fired 存儲已觸發的事件數組。

文件事件的結構體定義如下:

typedef struct aeFileEvent {
	int mask; // 文件事件類型 AE_READABLE 可讀事件;AE_WRITEABLE 可寫事件
	aeFileProc *rfileProc; // 讀事件處理函數指針
	aeFileProc *wfileProc; // 寫事件處理函數指針
	void *clientData; // 指向對應的客戶端對象
} aeFileEvent;

看一下創建文件事件 aeCreateFileEvent 的實現

int aeCreateFileEvent (aeEventLoop *eventLoop, int fd, int mask, aeFileProc *proc, void *clientData) {
	aeFileEvent *fe = &eventLoop->evnts[fd];
	if (aeApiAddEvent(eventLoop, fd, mask) == -1)
		return AE_ERR;
	fe->mask |= mask;
	if (mask & AE_READABLE) fe->rfileProc = proc;
	if (mask & AE_WRITABLE) fe->wfileProc = proc;
	fe->clientData = clientData;
	return AE_OK;
}

Redis 服務器會通過創建各類文件事件來處理事務,比如:

  • 啟動時創建 socket 并監聽,等待客戶端連接

aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE, acceptTcpHandler, NULL);
  • 客戶端與服務器建立 socket 連接之后,服務器會等待客戶端的命令請求

aeCreateFileEvent(server.el, fd, AE_READABLLE, readQueryFromClient, c);
  • 服務器處理完客戶端的命令請求之后,命令回復會暫時緩存在client結構體的buf緩沖區,待客戶端文件描述符的可寫事件發生時,才會真正往客戶端發送命令回復

aeCreateFileEvent(server.el, c->fd, AE_READABLLE, sendReplyToClient, c);

Redis 所有事件的執行都是通過aeProcessEvents函數來控制。在其中,執行文件事件會出現阻塞情況(epoll_wait),如果阻塞事件太長了,會妨礙到時間事件(定時)的執行,為避免出現這種情況,在實現文件事件時傳入的等待時間,是計算最早發生的時間事件得到的

int aeProcessEvents(aeEventLoop *eventLoop, int flags) {
	shortest = aeSearchNearestTimer(eventLoop);
	long long ms = (shortest->when_sec - now_sec) * 1000 + \
		shortest->when_ms - now_ms;

	// 阻塞事件發生
	numevents = aeApiPoll(eventLoop, ms);

	for (j=0; j < numevents; j++) {
		aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j]].fd];
		// 處理文件事件,即根據類型執行rfileProc或wfileProc
	}

	// 處理時間事件
	processed += processTimeEvents(eventLoop);
}

總結

現在我們來整體看一下 Redis 服務器相應命令的流程

怎么理解Redis中的epoll和文件事件

aeMain 函數通過調用 aeProcessEvents 函數來進行文件事件和時間事件的調度和執行。aeEventLoop 中記錄了事件相關的信息。首先通過 aeSearchNearestTimer 函數獲取最短的時間事件的執行時間間隔n,然后調用 aeApiPoll 函數獲取監聽到的套接字,最后執行與套接字向對應的事件處理函數 rfileProc 和 wfileProc,最后再執行時間事件函數 processTimeEvents。

一次完整的客戶端與服務端連接事件:

  • 器監聽套件字的 AE_READABLE 事件,當客戶端發送連接請求產生 AE_READABLE  事件,服務端會對客戶端的連接請求進行應答,將客戶端套接字的 AE_READABLE 事件與命令請求處理函數(aeFileProc),客戶端可以向服務端發送命令請求了

  • 端向服務端發送一個命令請求,客戶端套接字將產生 AE_READABLE 事件,引發命令處理器去執行,執行命令將產生相應的命令回復,服務端將客戶端套接字的 AE_WRITABLE 事件與命令回復處理函數(aeFileProc)關聯

  • 端嘗試讀取命令回復時,客戶端套接字將產生 AE_WRITABLE 事件,觸發命令回復處理器執行,當命令回復處理器將命令回復全部寫入套接字之后,服務器就會接觸客戶端套接字的 AE_WRITABLE 事件與命令回復處理函數(aeFileProc)之間的關聯

感謝各位的閱讀,以上就是“怎么理解Redis中的epoll和文件事件”的內容了,經過本文的學習后,相信大家對怎么理解Redis中的epoll和文件事件這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節
推薦閱讀:
  1. 自己動手實現Epoll
  2. epoll

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

科技| 南城县| 芦山县| 顺昌县| 青州市| 呈贡县| 思茅市| 甘孜县| 武冈市| 赤城县| 庄浪县| 镇赉县| 宜章县| 农安县| 同德县| 郑州市| 天水市| 青川县| 固原市| 蒙阴县| 永川市| 临潭县| 吉安市| 万源市| 龙胜| 黄山市| 沅陵县| 延川县| 清水河县| 金平| 图们市| 鸡西市| 磴口县| 和林格尔县| 九龙坡区| 临朐县| 敦化市| 隆林| 龙陵县| 蓬莱市| 南投县|