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