一、Redis有多快?
Redis是基于內(nèi)存運行的高性能 K-V 數(shù)據(jù)庫,官方提供的測試報告是單機可以支持約10w/s的QPS

二、Redis為什么這么快?
(1)完全基于內(nèi)存,數(shù)據(jù)存在內(nèi)存中,絕大部分請求是純粹的內(nèi)存操作,非常快速,跟傳統(tǒng)的磁盤文件數(shù)據(jù)存儲相比,避免了通過磁盤IO讀取到內(nèi)存這部分的開銷。
(2)數(shù)據(jù)結(jié)構(gòu)簡單,對數(shù)據(jù)操作也簡單。Redis中的數(shù)據(jù)結(jié)構(gòu)是專門進行設(shè)計的,每種數(shù)據(jù)結(jié)構(gòu)都有一種或多種數(shù)據(jù)結(jié)構(gòu)來支持。Redis正是依賴這些靈活的數(shù)據(jù)結(jié)構(gòu),來提升讀取和寫入的性能。
(3)采用單線程,省去了很多上下文切換的時間以及CPU消耗,不存在競爭條件,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,也不會出現(xiàn)死鎖而導(dǎo)致的性能消耗。
(4)使用基于IO多路復(fù)用機制的線程模型,可以處理并發(fā)的鏈接。
Redis 基于 Reactor 模式開發(fā)了自己的網(wǎng)絡(luò)事件處理器,這個處理器被稱為文件事件處理器 file event handler。由于這個文件事件處理器是單線程的,所以Redis才叫做單線程的模型,但是它采用IO多路復(fù)用機制同時監(jiān)聽多個Socket,并根據(jù)Socket上的事件來選擇對應(yīng)的事件處理器進行處理。文件事件處理器的結(jié)構(gòu)包含4個部分,線程模型如下圖:
多個Socket
IO多路復(fù)用程序
文件事件分派器
事件處理器(命令請求處理器、命令回復(fù)處理器、連接應(yīng)答處理器)


多個 Socket 可能會產(chǎn)生不同的操作,每個操作對應(yīng)不同的文件事件,但是IO多路復(fù)用程序會監(jiān)聽多個Socket,將Socket產(chǎn)生的事件放入隊列中排隊,事件分派器每次從隊列中取出一個事件,把該事件交給對應(yīng)的事件處理器進行處理。
Redis客戶端對服務(wù)端的每次調(diào)用都經(jīng)歷了發(fā)送命令,執(zhí)行命令,返回結(jié)果三個過程。其中執(zhí)行命令階段,由于Redis是單線程來處理命令的,所有每一條到達服務(wù)端的命令不會立刻執(zhí)行,所有的命令都會進入一個隊列中,然后逐個被執(zhí)行。并且多個客戶端發(fā)送的命令的執(zhí)行順序是不確定的。但是可以確定的是不會有兩條命令被同時執(zhí)行,不會產(chǎn)生并發(fā)問題,這就是Redis的單線程基本模型。
多路I/O復(fù)用模型是利用 select、poll、epoll 可以同時監(jiān)察多個流的 I/O 事件的能力,在空閑的時候,會把當(dāng)前線程阻塞掉,當(dāng)有一個或多個流有 I/O 事件時,就從阻塞態(tài)中喚醒,然后程序就會輪詢一遍所有的流(epoll 是只輪詢那些真正發(fā)出了事件的流),并且依次順序的處理就緒的流,這種做法就避免了大量的無用操作。
這里“多路”指的是多個網(wǎng)絡(luò)連接,“復(fù)用”指的是復(fù)用同一個線程。采用多路 I/O 復(fù)用技術(shù)可以讓單個線程高效的處理多個客戶端的網(wǎng)絡(luò)IO連接請求(盡量減少網(wǎng)絡(luò) IO 的時間消耗)
(5)Redis直接自己構(gòu)建了VM 機制 ,避免調(diào)用系統(tǒng)函數(shù)的時候,浪費時間去移動和請求
三、為什么Redis是單線程?
這里我們強調(diào)的單線程,指的是網(wǎng)絡(luò)請求模塊使用一個線程來處理,即一個線程處理所有網(wǎng)絡(luò)請求,其他模塊仍用了多個線程。
那為什么使用單線程呢?官方答案是:因為CPU不是Redis的瓶頸,Redis的瓶頸最有可能是機器內(nèi)存或者網(wǎng)絡(luò)帶寬。既然單線程容易實現(xiàn),而且CPU不會成為瓶頸,那就順理成章地采用單線程的方案了。
但是,我們使用單線程的方式是無法發(fā)揮多核CPU 性能,不過我們可以通過在單機開多個Redis 實例來解決這個問題
四、Redis6.0 的多線程?
1、Redis6.0 之前為什么一直不使用多線程?
Redis使用單線程的可維護性高。多線程模型雖然在某些方面表現(xiàn)優(yōu)異,但是它卻引入了程序執(zhí)行順序的不確定性,帶來了并發(fā)讀寫的一系列問題,增加了系統(tǒng)復(fù)雜度、同時可能存在線程切換、甚至加鎖解鎖、死鎖造成的性能損耗。
2、Redis6.0 為什么要引入多線程呢?
因為Redis的瓶頸不在內(nèi)存,而是在網(wǎng)絡(luò)I/O模塊帶來CPU的耗時,所以Redis6.0的多線程是用來處理網(wǎng)絡(luò)I/O這部分,充分利用CPU資源,減少網(wǎng)絡(luò)I/O阻塞帶來的性能損耗。
3、Redis6.0 如何開啟多線程?
默認情況下Redis是關(guān)閉多線程的,可以在conf文件進行配置開啟:
io-threads-do-reads yes
io-threads 線程數(shù)
官方建議的線程數(shù)設(shè)置:4核的機器建議設(shè)置為2或3個線程,8核的建議設(shè)置為6個線程,線程數(shù)一定要小于機器核數(shù),盡量不超過8個。
4、多線程模式下,是否存在線程并發(fā)安全問題?
如圖,一次redis請求,要建立連接,然后獲取操作的命令,然后執(zhí)行命令,最后將響應(yīng)的結(jié)果寫到socket上。

在redis的多線程模式下,獲取、解析命令,以及輸出結(jié)果著兩個過程,可以配置成多線程執(zhí)行的,因為它畢竟是我們定位到的主要耗時點,但是命令的執(zhí)行,也就是內(nèi)存操作,依然是單線程運行的。所以,Redis 的多線程部分只是用來處理網(wǎng)絡(luò)數(shù)據(jù)的讀寫和協(xié)議解析,執(zhí)行命令仍然是單線程順序執(zhí)行,也就不存在并發(fā)安全問題。
作者:張維鵬
原文鏈接:
https://blog.csdn.net/a745233700/article/details/113488673