關(guān)于 Redis 為什么這么快,除了之前提到的,數(shù)據(jù)存儲在內(nèi)存、底層數(shù)據(jù)結(jié)構(gòu)高效以外,還有什么其他原因呢?
我們都知道,Redis 是單線程高性能的。但是為什么 Redis 在單線程的情況下,還能做到高性能呢? 為什么不使用多線程呢? 多線程不是更快嗎?
首先,需要說明,Redis 單線程的意思是說,Redis 處理外部的鍵值對操作請求是單線程的,指的是Redis 的網(wǎng)絡(luò)IO和鍵值對讀寫是由一個線程完成的。 但是 Redis 其他保持高性能的功能,比如持久化、集群數(shù)據(jù)同步等,是由額外的線程處理的。
Redis 為啥使用單線程?
正如上文提到的那樣,Redis 為什么不使用多線程?多線程的效率不是更高嗎?
實際上,多線程的效率提升,并不是隨著線程數(shù)的增加成比例增長的。其關(guān)鍵的瓶頸就在于,當面臨多線程訪問共享資源時,會產(chǎn)生資源的競爭與等待。 比如,當有多個請求同時訪問某個 key 時,就可能產(chǎn)生資源競爭。 一言蔽之,就是多線程需要合理的機制來解決共享資源的并發(fā)訪問控制問題。
Redis 為什么使用單線程還能這么快
實際上,Redis 采用了多路復用機制,來保證其處理網(wǎng)絡(luò)IO大并發(fā)量請求操作時,能實現(xiàn)高吞吐量。
首先,我們需要知道,Redis 的單線程都處理了什么操作:

如上圖所示,就是接受請求,操作請求,響應請求。
其中,在網(wǎng)絡(luò)的IO處理中,可能導致的阻塞點在于 accept() 和 recv()。當 Redis 監(jiān)聽到連接請求,但是一直未能成功建立起連接時,會阻塞在 accept(),導致 Redis 無法和其他客戶端建立連接。同樣,當 Redis 通過 recv() 從客戶端讀取數(shù)據(jù)時,如果數(shù)據(jù)一直沒有達到,同樣會阻塞在 recv()。
基于多路復用的高性能IO模型
當監(jiān)聽到有請求發(fā)起連接時,Redis 會讓內(nèi)核監(jiān)聽這些套接字FD,一旦檢測到FD上有請求到達時,會觸發(fā)相應的回調(diào)函數(shù),觸發(fā)相應的事件。此時,Redis 線程就不會阻塞在某一個監(jiān)聽或者已連接套接字上。

通過回調(diào)函數(shù)觸發(fā)了相應的事件后,這些事件會被放在一個事件隊列中,Redis 單線程在對這個事件隊列不斷進行處理。
但是,在基于了多路復用的IO模型下,其單線程的阻塞點依然是有的。主要就阻塞在每次只能從事件隊列中拿出一個事件進行處理。當這個事件處理的耗時特別長時,后面的事件都需要等待。