Redis為什麼這麼快?Redis的線程模型與Redis多線程

fans news 發佈 2022-01-18T18:29:12+00:00

一、Redis有多快?Redis是基於內存運行的高性能 K-V 資料庫,官方提供的測試報告是單機可以支持約10w/s的QPS二、Redis為什麼這麼快?

一、redis有多快?

Redis是基於內存運行的高性能 K-V 資料庫,官方提供的測試報告是單機可以支持約10w/s的QPS

二、Redis為什麼這麼快?

(1)完全基於內存,數據存在內存中,絕大部分請求是純粹的內存操作,非常快速,跟傳統的磁碟文件數據存儲相比,避免了通過磁碟IO讀取到內存這部分的開銷。

(2)數據結構簡單,對數據操作也簡單。Redis中的數據結構是專門進行設計的,每種數據結構都有一種或多種數據結構來支持。Redis正是依賴這些靈活的數據結構,來提升讀取和寫入的性能。

(3)採用單線程,省去了很多上下文切換的時間以及CPU消耗,不存在競爭條件,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,也不會出現死鎖而導致的性能消耗。

(4)使用基於IO多路復用機制的線程模型,可以處理並發的連結。

Redis 基於 Reactor 模式開發了自己的網絡事件處理器,這個處理器被稱為文件事件處理器 file event handler。由於這個文件事件處理器是單線程的,所以Redis才叫做單線程的模型,但是它採用IO多路復用機制同時監聽多個Socket,並根據Socket上的事件來選擇對應的事件處理器進行處理。文件事件處理器的結構包含4個部分,線程模型如下圖:

多個Socket

IO多路復用程序

文件事件分派器

事件處理器(命令請求處理器、命令回復處理器、連接應答處理器)

多個 Socket 可能會產生不同的操作,每個操作對應不同的文件事件,但是IO多路復用程序會監聽多個Socket,將Socket產生的事件放入隊列中排隊,事件分派器每次從隊列中取出一個事件,把該事件交給對應的事件處理器進行處理。

Redis客戶端對服務端的每次調用都經歷了發送命令,執行命令,返回結果三個過程。其中執行命令階段,由於Redis是單線程來處理命令的,所有每一條到達服務端的命令不會立刻執行,所有的命令都會進入一個隊列中,然後逐個被執行。並且多個客戶端發送的命令的執行順序是不確定的。但是可以確定的是不會有兩條命令被同時執行,不會產生並發問題,這就是Redis的單線程基本模型。

多路I/O復用模型是利用 select、poll、epoll 可以同時監察多個流的 I/O 事件的能力,在空閒的時候,會把當前線程阻塞掉,當有一個或多個流有 I/O 事件時,就從阻塞態中喚醒,然後程序就會輪詢一遍所有的流(epoll 是只輪詢那些真正發出了事件的流),並且依次順序的處理就緒的流,這種做法就避免了大量的無用操作。

這裡「多路」指的是多個網絡連接,「復用」指的是復用同一個線程。採用多路 I/O 復用技術可以讓單個線程高效的處理多個客戶端的網絡IO連接請求(儘量減少網絡 IO 的時間消耗)

(5)Redis直接自己構建了VM 機制 ,避免調用系統函數的時候,浪費時間去移動和請求

三、為什麼Redis是單線程?

這裡我們強調的單線程,指的是網絡請求模塊使用一個線程來處理,即一個線程處理所有網絡請求,其他模塊仍用了多個線程。

那為什麼使用單線程呢?官方答案是:因為CPU不是Redis的瓶頸,Redis的瓶頸最有可能是機器內存或者網絡帶寬。既然單線程容易實現,而且CPU不會成為瓶頸,那就順理成章地採用單線程的方案了。

但是,我們使用單線程的方式是無法發揮多核CPU 性能,不過我們可以通過在單機開多個Redis 實例來解決這個問題

四、Redis6.0 的多線程?

1、Redis6.0 之前為什麼一直不使用多線程?

Redis使用單線程的可維護性高。多線程模型雖然在某些方面表現優異,但是它卻引入了程序執行順序的不確定性,帶來了並發讀寫的一系列問題,增加了系統複雜度、同時可能存在線程切換、甚至加鎖解鎖、死鎖造成的性能損耗。

2、Redis6.0 為什麼要引入多線程呢?

因為Redis的瓶頸不在內存,而是在網絡I/O模塊帶來CPU的耗時,所以Redis6.0的多線程是用來處理網絡I/O這部分,充分利用CPU資源,減少網絡I/O阻塞帶來的性能損耗。

3、Redis6.0 如何開啟多線程?

默認情況下Redis是關閉多線程的,可以在conf文件進行配置開啟:

io-threads-do-reads yes

io-threads 線程數

## 官方建議的線程數設置:4核的機器建議設置為2或3個線程,8核的建議設置為6個線程,線程數一定要小於機器核數,儘量不超過8個。

4、多線程模式下,是否存在線程並發安全問題?

如圖,一次redis請求,要建立連接,然後獲取操作的命令,然後執行命令,最後將響應的結果寫到socket上。

在redis的多線程模式下,獲取、解析命令,以及輸出結果著兩個過程,可以配置成多線程執行的,因為它畢竟是我們定位到的主要耗時點,但是命令的執行,也就是內存操作,依然是單線程運行的。所以,Redis 的多線程部分只是用來處理網絡數據的讀寫和協議解析,執行命令仍然是單線程順序執行,也就不存在並發安全問題。

作者:張維鵬

原文連結:https://blog.csdn.net/a745233700/article/details/113488673

關鍵字: