Redis基于Reactor模式開(kāi)發(fā)了自己的網(wǎng)絡(luò)事件處理器,也就是文件事件處理器。文件事件處理器使用IO多路復(fù)用技術(shù),同時(shí)監(jiān)聽(tīng)多個(gè)套接字,并為套接字關(guān)聯(lián)不同的事件處理函數(shù)。當(dāng)套接字的可讀或者可寫(xiě)事件觸發(fā)時(shí),就會(huì)調(diào)用相應(yīng)的事件處理函數(shù)。
1. 為什么單線(xiàn)程的 Redis 能那么快?
Redis的瓶頸主要在IO而不是CPU,所以為了省開(kāi)發(fā)量,在6.0版本前是單線(xiàn)程模型;其次,Redis 是單線(xiàn)程主要是指 Redis 的網(wǎng)絡(luò) IO 和鍵值對(duì)讀寫(xiě)是由一個(gè)線(xiàn)程來(lái)完成的,這也是 Redis 對(duì)外提供鍵值存儲(chǔ)服務(wù)的主要流程。(但 Redis 的其他功能,比如持久化、異步刪除、集群數(shù)據(jù)同步等,其實(shí)是由額外的線(xiàn)程執(zhí)行的)。
Redis 采用了多路復(fù)用機(jī)制使其在網(wǎng)絡(luò) IO 操作中能并發(fā)處理大量的客戶(hù)端請(qǐng)求,實(shí)現(xiàn)高吞吐率。
2. Redis事件響應(yīng)框架ae_event及文件事件處理器
Redis并沒(méi)有使用 libevent 或者 libev 這樣的成熟開(kāi)源方案,而是自己實(shí)現(xiàn)一個(gè)非常簡(jiǎn)潔的事件驅(qū)動(dòng)庫(kù) ae_event。@pdai Redis 使用的IO多路復(fù)用技術(shù)主要有:select、epoll、evport和kqueue等。每個(gè)IO多路復(fù)用函數(shù)庫(kù)在 Redis 源碼中都對(duì)應(yīng)一個(gè)單獨(dú)的文件,比如ae_select.c,ae_epoll.c, ae_kqueue.c等。Redis 會(huì)根據(jù)不同的操作系統(tǒng),按照不同的優(yōu)先級(jí)選擇多路復(fù)用技術(shù)。事件響應(yīng)框架一般都采用該架構(gòu),比如 netty 和 libevent。
如下圖所示,文件事件處理器有四個(gè)組成部分,它們分別是套接字、I/O多路復(fù)用程序、文件事件分派器以及事件處理器。
文件事件是對(duì)套接字操作的抽象,每當(dāng)一個(gè)套接字準(zhǔn)備好執(zhí)行 accept、read、write和 close 等操作時(shí),就會(huì)產(chǎn)生一個(gè)文件事件。因?yàn)?Redis 通常會(huì)連接多個(gè)套接字,所以多個(gè)文件事件有可能并發(fā)的出現(xiàn)。
I/O多路復(fù)用程序負(fù)責(zé)監(jiān)聽(tīng)多個(gè)套接字,并向文件事件派發(fā)器傳遞那些產(chǎn)生了事件的套接字。
盡管多個(gè)文件事件可能會(huì)并發(fā)地出現(xiàn),但I(xiàn)/O多路復(fù)用程序總是會(huì)將所有產(chǎn)生的套接字都放到同一個(gè)隊(duì)列(也就是后文中描述的aeEventLoop的fired就緒事件表)里邊,然后文件事件處理器會(huì)以有序、同步、單個(gè)套接字的方式處理該隊(duì)列中的套接字,也就是處理就緒的文件事件。