Redis(一):?jiǎn)尉€程為何還能這么快煌妈?

提到redis馬上在我們腦海中會(huì)浮現(xiàn)出這樣一些關(guān)鍵字:?jiǎn)尉€程、高性能煤篙、內(nèi)存數(shù)據(jù)庫斟览、kv存儲(chǔ)......這些關(guān)鍵字都從不同層面描述了redis的一些相關(guān)特性和技術(shù)實(shí)現(xiàn)。那么為什么redis具備這些特性以及是如何實(shí)現(xiàn)的辑奈,本文將進(jìn)行一一分析苛茂。

一、單線程

1.1 為什么是單線程

總結(jié)Redis的普通KV存儲(chǔ)瓶頸不在 CPU鸠窗,而往往可能受到內(nèi)存和網(wǎng)絡(luò)I/O 的制約妓羊。

Redis 中有多種類型的數(shù)據(jù)操作,甚至包括一些事務(wù)處理稍计,如果采用多線程躁绸,則會(huì)被多線程產(chǎn)生的切換問題而困擾,也可能因?yàn)榧渔i導(dǎo)致系統(tǒng)架構(gòu)變的異常復(fù)雜造成性能損耗臣嚣。

Redis作者咋說的:

image

總結(jié)來說就是對(duì)于redis來說單線程的設(shè)計(jì)能夠保證性能涨颜,多線程在設(shè)計(jì)和實(shí)現(xiàn)上會(huì)帶來更多的復(fù)雜度。但是使用單線程的方式確實(shí)無法很好發(fā)揮多核CPU 的性能茧球,可以通過在單機(jī)開多個(gè)Redis 實(shí)例來完善!

1.2 有多線程的考量嗎

Redis4.0版本對(duì)于一些大鍵值對(duì)的刪除操作星持,引入多線程來非阻塞地釋放內(nèi)存空間抢埋,能減少對(duì) Redis 主線程阻塞的時(shí)間,提高執(zhí)行的效率督暂。

Redis6.0 引入多線程來提高網(wǎng)絡(luò) IO 讀寫性能揪垄。

這里要注意的是Redis 的多線程只是在網(wǎng)絡(luò)數(shù)據(jù)的讀寫這類耗時(shí)操作上使用了, 執(zhí)行命令仍然是單線程順序執(zhí)行逻翁。Redis6中默認(rèn)是禁用多線程的饥努,可以通過修改redis的配置文件中io-threads-do-reads=true來開啟。除此之外還需要設(shè)置現(xiàn)場(chǎng)的數(shù)量才能正真開啟多線程八回,配置參數(shù)為io-threads 3表示開啟三個(gè)線程酷愧。

線程設(shè)置建議:關(guān)于線程數(shù)的設(shè)置驾诈,官方的建議是如果為 4 核的 CPU,建議線程數(shù)設(shè)置為 2 或 3溶浴,如果為 8 核 CPU 建議線程數(shù)設(shè)置為 6乍迄,線程數(shù)一定要小于機(jī)器核數(shù),線程數(shù)并不是越大越好士败。

二闯两、高性能

通常我們的理解是單線程性能沒有多線程好,那redis又是如何做到高性能的了谅将?

2.1 I/O多路復(fù)用

這是我們最多看到的一句解釋漾狼,redis使用了I/O多路復(fù)用的模式,所以性能高饥臂,那么到底什么是I/O多路復(fù)用模型逊躁,以及在redis中怎么實(shí)現(xiàn)的。我這里先打幾個(gè)比方來方便大家理解擅笔。

要過年了志衣,老王去火車站買票回家過年,春運(yùn)期間票不好買猛们,老王買了三天買到了一張退票念脯。這樣一個(gè)場(chǎng)景老王有三種方式來完成這次買票:

方式一:老王去到火車站售票大廳,在長(zhǎng)椅上躺了兩夜弯淘,終于在第三天等到了一張票绿店,興高采烈的回家了。(老王在火車站待了三天庐橙,其他啥事沒干假勿,還耗費(fèi)了6桶泡面一床棉被)

方式二:老王去到火車站售票大廳買票,沒買到态鳖,之后每天中午再去一次转培,終于在第三天買到了票。(老王往返車站6次浆竭,路上耗費(fèi)了3小時(shí)浸须,不過這幾天其他時(shí)間送了三天外賣,又給家里的老婆掙了不少錢)

方式三:老王去到火車站售票大廳買票邦泄,沒買到删窒,這時(shí)候看到一個(gè)黃牛在幫別人買票,老王想著還有外賣要送顺囊,就讓黃牛幫他買肌索,三天后黃牛買到了票通知他下班后來取。(老王往返車站兩次特碳,路上耗費(fèi)1小時(shí)诚亚,給了黃牛50塊手續(xù)費(fèi)晕换,其他時(shí)間送了三天外賣,由于老王臨近過年每天都沒耽擱的加班送外賣亡电,平臺(tái)獎(jiǎng)勵(lì)了老王500塊)

image

第一種方式就是阻塞IO模型届巩,第二種方式就是非阻塞IO模型,第三種方式就是IO復(fù)用模型了份乒。除了老王恕汇,老張老李......都找了黃牛買票,這樣大家都可以不用跑火車站了或辖,等黃牛消息就行瘾英。黃牛幫一個(gè)人買是買,幫多個(gè)人買也是買颂暇,反正都要在這里排隊(duì)缺谴,還能多掙幾份錢。老王老張老李的請(qǐng)求耳鸯,都復(fù)用這個(gè)黃牛搞定了湿蛔,老王他們節(jié)省了時(shí)間和精力干了其他事,黃牛一個(gè)人花費(fèi)了近乎一樣的時(shí)間和精力賺了多份錢县爬。 大概理解了I/O多路復(fù)用的概念接下來就看看在redis中是如何實(shí)現(xiàn)的阳啥。針對(duì)IO復(fù)用思想前后主要有select, poll, epoll 三種技術(shù)實(shí)現(xiàn)。

** Select:**select是I/O多路復(fù)用的第一個(gè)實(shí)現(xiàn)(1983年)财喳,有I/O事件發(fā)生了察迟,卻并不知道是哪幾個(gè)流,只能無差別輪詢所有流耳高,找出能讀出數(shù)據(jù)扎瓶,或者寫入數(shù)據(jù)的流,同時(shí)處理的流越多泌枪,輪詢時(shí)間就越長(zhǎng)概荷。就好比黃牛給多個(gè)人買票,但是并不知道買到票是誰的碌燕,只能不停的去問所有買票的人是不是你的乍赫。這樣買票的人越多,黃牛要問的人就越多陆蟆。

select本質(zhì)上是通過設(shè)置或者檢查存放fd標(biāo)志位的數(shù)據(jù)結(jié)構(gòu)來進(jìn)行下一步處理。這樣所帶來的缺點(diǎn)是:

單個(gè)進(jìn)程可監(jiān)視的fd數(shù)量被限制惋增,即能監(jiān)聽端口的大小有限叠殷。一般來說這個(gè)數(shù)目和系統(tǒng)內(nèi)存關(guān)系很大,具體數(shù)目可以cat /proc/sys/fs/file-max察看诈皿。32位機(jī)默認(rèn)是1024個(gè)林束。64位機(jī)默認(rèn)是2048.

對(duì)socket進(jìn)行掃描時(shí)是線性掃描像棘,即采用輪詢的方法,效率較低壶冒。

需要維護(hù)一個(gè)用來存放大量fd的數(shù)據(jù)結(jié)構(gòu)缕题,這樣會(huì)使得用戶空間和內(nèi)核空間在傳遞該結(jié)構(gòu)時(shí)復(fù)制開銷大。

Poll:poll本質(zhì)上和select沒有區(qū)別胖腾,它將用戶傳入的數(shù)組拷貝到內(nèi)核空間烟零,然后查詢每個(gè)fd對(duì)應(yīng)的設(shè)備狀態(tài),如果設(shè)備就緒則在設(shè)備等待隊(duì)列中加入一項(xiàng)并繼續(xù)遍歷咸作,如果遍歷完所有fd后沒有發(fā)現(xiàn)就緒設(shè)備锨阿,則掛起當(dāng)前進(jìn)程,直到設(shè)備就緒或者主動(dòng)超時(shí)记罚,被喚醒后它又要再次遍歷fd墅诡。這個(gè)過程經(jīng)歷了多次無謂的遍歷。它沒有最大連接數(shù)的限制桐智,原因是它是基于鏈表來存儲(chǔ)的末早。

Epoll:epoll可以理解為event poll,不同于忙輪詢和無差別輪詢说庭,epoll會(huì)把哪個(gè)流發(fā)生了怎樣的I/O事件通知我們然磷。epoll實(shí)際上是事件驅(qū)動(dòng)(每個(gè)事件關(guān)聯(lián)上fd)的,此時(shí)我們對(duì)這些流的操作都是有意義的口渔。

通過以上三種技術(shù)實(shí)現(xiàn)的分析样屠,epoll無疑是最好的選擇,那么redis中是這樣選擇的嗎缺脉?先來看下redis在做多路復(fù)用函數(shù)選擇時(shí)的代碼實(shí)現(xiàn):

ifdef HAVE_EVPORT
include "ae_evport.c"
else
    ifdef HAVE_EPOLL
    include "ae_epoll.c"
    else
        ifdef HAVE_KQUEUE
        include "ae_kqueue.c"
        else
        include "ae_select.c"
        endif
    endif
endif

執(zhí)行邏輯如下圖:

image

可以看到redis針對(duì)不同的操作系統(tǒng)會(huì)選用不同的實(shí)現(xiàn)痪欲,主流操作系統(tǒng)都有類似epoll的實(shí)現(xiàn)作為選擇,同時(shí)也提供了select方式作為備選攻礼。

2.2 Reactor(反應(yīng)堆模式)

有了epoll等IO復(fù)用技術(shù)的支撐业踢,接下來我們看看redis是如何利用IO復(fù)用來串連起socket連接請(qǐng)求和具體任務(wù)處理的。

image

由上圖可以看出redis處理并發(fā)客戶端連接的方式是利用epoll來實(shí)現(xiàn)IO多路復(fù)用礁扮,將連接信息和事件放到隊(duì)列中知举,之后依次放到文件事件分派器,事件分派器將事件分發(fā)給事件處理器太伊。這種處理方式叫做反應(yīng)堆模式雇锡。

Redis是基于Reactor模式(反應(yīng)堆模式)開發(fā)了自己的網(wǎng)絡(luò)模型,形成了一個(gè)完備的基于IO復(fù)用的事件驅(qū)動(dòng)服務(wù)器僚焦。

上面我們了解到epoll方式的多路復(fù)用實(shí)現(xiàn)已經(jīng)是很高性能的了锰提,那么為什么redis在此基礎(chǔ)上還要基于Reactor來實(shí)現(xiàn)自己的網(wǎng)絡(luò)模型了?

epoll將收集到的可讀寫事件全部放入隊(duì)列中等待業(yè)務(wù)線程的處理,此時(shí)線程池的工作線程拿到任務(wù)進(jìn)行處理立肘,實(shí)際場(chǎng)景中可能有很多種請(qǐng)求類型边坤,工作線程每拿到一種任務(wù)就進(jìn)行相應(yīng)的處理,處理完成之后繼續(xù)處理其他類型的任務(wù)谅年,工作線程需要關(guān)注各種不同類型的請(qǐng)求茧痒,對(duì)于不同的請(qǐng)求選擇不同的處理方法,因此請(qǐng)求類型的增加會(huì)讓工作線程復(fù)雜度增加融蹂,維護(hù)起來也變得越來越困難旺订。

如果我們?cè)趀poll的基礎(chǔ)上進(jìn)行業(yè)務(wù)區(qū)分,并且對(duì)每一種業(yè)務(wù)設(shè)置相應(yīng)的處理函數(shù)殿较,每次來任務(wù)之后對(duì)任務(wù)進(jìn)行識(shí)別和分發(fā)耸峭,每種處理函數(shù)只處理一種業(yè)務(wù),這種模型也就是Reactor反應(yīng)堆模式的設(shè)計(jì)思路淋纲。

通俗點(diǎn)講就是黃牛的業(yè)務(wù)做的很好劳闹,找黃牛除了買火車票還有買機(jī)票電影票的,那么黃牛每次處理不同的業(yè)務(wù)的時(shí)候就要不斷跑來跑去切換業(yè)務(wù)場(chǎng)景洽瞬,顯然這樣業(yè)務(wù)沒法做大做強(qiáng)本涕,黃牛就找了多個(gè)業(yè)務(wù)員,負(fù)責(zé)專門買火車票伙窃,飛機(jī)票菩颖,電影票,這樣黃牛接到不同業(yè)務(wù)的時(shí)候就交給不同的業(yè)務(wù)員去做为障,接客能力一下就增強(qiáng)了晦闰。

三、告一段落

到這里我們從redis的線程模型分析了redis為什么使用單線程鳍怨,以及從單線程性能依舊很出色分析了基于I/O多路復(fù)用的反應(yīng)堆模式請(qǐng)求處理流程呻右。下一篇將從redis的內(nèi)存模型來解讀redisdb的數(shù)據(jù)結(jié)構(gòu)以及內(nèi)存回收機(jī)制。

關(guān)注IT巔峰技術(shù)鞋喇,私信作者声滥,獲取以下2021全球架構(gòu)師峰會(huì)PDF資料。

image
image.gif
image
image.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末侦香,一起剝皮案震驚了整個(gè)濱河市落塑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌罐韩,老刑警劉巖憾赁,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異散吵,居然都是意外死亡龙考,警方通過查閱死者的電腦和手機(jī)膘壶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來洲愤,“玉大人,你說我怎么就攤上這事顷锰〖泶停” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵官紫,是天一觀的道長(zhǎng)肛宋。 經(jīng)常有香客問我,道長(zhǎng)束世,這世上最難降的妖魔是什么酝陈? 我笑而不...
    開封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮毁涉,結(jié)果婚禮上沉帮,老公的妹妹穿的比我還像新娘。我一直安慰自己贫堰,他們只是感情好穆壕,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著其屏,像睡著了一般喇勋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上偎行,一...
    開封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天川背,我揣著相機(jī)與錄音,去河邊找鬼蛤袒。 笑死熄云,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的汗盘。 我是一名探鬼主播皱碘,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼隐孽!你這毒婦竟也來了癌椿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎缔赠,沒想到半個(gè)月后聂宾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡都办,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片琳钉。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡势木,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出歌懒,到底是詐尸還是另有隱情啦桌,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布及皂,位于F島的核電站甫男,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏验烧。R本人自食惡果不足惜板驳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望碍拆。 院中可真熱鬧若治,春花似錦、人聲如沸倔监。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽浩习。三九已至静暂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谱秽,已是汗流浹背洽蛀。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疟赊,地道東北人郊供。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像近哟,于是被迫代替她去往敵國(guó)和親驮审。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容