redis线程阻塞原因排插_每次面试都要被问:为什么采用单线程的Redis也会如此之快?...
眾所周知,Redis在內(nèi)存庫(kù)數(shù)據(jù)庫(kù)領(lǐng)域非常地火熱,它極高的性能和豐富的數(shù)據(jù)結(jié)構(gòu)為我們的開(kāi)發(fā)提供了極大的便利。
但我們也聽(tīng)說(shuō)了,Redis是單線(xiàn)程的,為什么采用單線(xiàn)程的Redis也會(huì)如此之快呢?這篇文章我們來(lái)分析一下其中的緣由。
其實(shí),嚴(yán)格來(lái)說(shuō),Redis Server是多線(xiàn)程的,只是它的請(qǐng)求處理整個(gè)流程是單線(xiàn)程處理的。 這一點(diǎn)我們一定要清楚了解到,不要單純地認(rèn)為Redis Server是單線(xiàn)程的!
我們平時(shí)說(shuō)的Redis單線(xiàn)程快是指它的請(qǐng)求處理過(guò)程非常地快!
下面我們就來(lái)分析一下為什么請(qǐng)求處理使用單線(xiàn)程,依舊可以達(dá)到這么高的性能。
Redis的性能非常之高,每秒可以承受10W+的QPS,它如此優(yōu)秀的性能主要取決于以下幾個(gè)方面:
- 純內(nèi)存操作
- 使用IO多路復(fù)用技術(shù)
- 非CPU密集型任務(wù)
- 單線(xiàn)程的優(yōu)勢(shì)
純內(nèi)存操作
Redis是一個(gè)內(nèi)存數(shù)據(jù)庫(kù),它的數(shù)據(jù)都存儲(chǔ)在內(nèi)存中,這意味著我們讀寫(xiě)數(shù)據(jù)都是在內(nèi)存中完成,這個(gè)速度是非常快的。
Redis是一個(gè)KV內(nèi)存數(shù)據(jù)庫(kù),它內(nèi)部構(gòu)建了一個(gè)哈希表,根據(jù)指定的KEY訪(fǎng)問(wèn)時(shí),只需要O(1)的時(shí)間復(fù)雜度就可以找到對(duì)應(yīng)的數(shù)據(jù)。同時(shí),Redis提供了豐富的數(shù)據(jù)類(lèi)型,并使用高效的操作方式進(jìn)行操作,這些操作都在內(nèi)存中進(jìn)行,并不會(huì)大量消耗CPU資源,所以速度極快。
使用IO多路復(fù)用技術(shù)
Redis采用單線(xiàn)程,那么它是如何處理多個(gè)客戶(hù)端連接請(qǐng)求呢?
Redis采用了IO多路復(fù)用技術(shù)和非阻塞IO,這個(gè)技術(shù)由操作系統(tǒng)實(shí)現(xiàn)提供,Redis可以方便地操作系統(tǒng)的API即可。Redis可以在單線(xiàn)程中監(jiān)聽(tīng)多個(gè)Socket的請(qǐng)求,在任意一個(gè)Socket可讀/可寫(xiě)時(shí),Redis去讀取客戶(hù)端請(qǐng)求,在內(nèi)存中操作對(duì)應(yīng)的數(shù)據(jù),然后再寫(xiě)回到Socket中。
整個(gè)過(guò)程非常高效,Redis利用了IO多路復(fù)用技術(shù)的事件驅(qū)動(dòng)模型,保證在監(jiān)聽(tīng)多個(gè)Socket連接的情況下,只針對(duì)有活動(dòng)的Socket采取反應(yīng)。
非CPU密集型任務(wù)
采用單線(xiàn)程的缺點(diǎn)很明顯,無(wú)法使用多核CPU。Redis作者提到,由于Redis的大部分操作并不是CPU密集型任務(wù),而Redis的瓶頸在于內(nèi)存和網(wǎng)絡(luò)帶寬。
在高并發(fā)請(qǐng)求下,Redis需要更多的內(nèi)存和更高的網(wǎng)絡(luò)帶寬,否則瓶頸很容易出現(xiàn)在內(nèi)存不夠用和網(wǎng)絡(luò)延遲等待的情況。
當(dāng)然,如果你覺(jué)得單個(gè)Redis實(shí)例的性能不足以支撐業(yè)務(wù),Redis作者推薦部署多個(gè)Redis節(jié)點(diǎn),組成集群的方式來(lái)利用多核CPU的能力,而不是在單個(gè)實(shí)例上使用多線(xiàn)程來(lái)處理。
單線(xiàn)程的優(yōu)勢(shì)
基于以上特性,Redis采用單線(xiàn)程已足夠達(dá)到非常高的性能,所以Redis沒(méi)有采用多線(xiàn)程模型。
另外,單線(xiàn)程模型還帶了以下好處:
- 沒(méi)有了多線(xiàn)程上下文切換的性能損耗
- 沒(méi)有了訪(fǎng)問(wèn)共享資源加鎖的性能損耗
- 開(kāi)發(fā)和調(diào)試非常友好,可維護(hù)性高
所以Redis正是基于以上這些方面,所以采用了單線(xiàn)程模型來(lái)完成請(qǐng)求處理的工作。
多線(xiàn)程優(yōu)化
在文章開(kāi)頭已經(jīng)特別說(shuō)明,Redis Server本身是多線(xiàn)程的,除了請(qǐng)求處理流程是單線(xiàn)程處理之外,Redis內(nèi)部還有其他工作線(xiàn)程在后臺(tái)執(zhí)行,它負(fù)責(zé)異步執(zhí)行某些比較耗時(shí)的任務(wù),例如AOF每秒刷盤(pán)、AOF文件重寫(xiě)都是在另一個(gè)線(xiàn)程中完成的。
而在Redis 4.0之后,Redis引入了lazyfree的機(jī)制,提供了unlink、flushall aysc、flushdb async等命令和lazyfree-lazy-eviction、lazyfree-lazy-expire等機(jī)制來(lái)異步釋放內(nèi)存,它主要是為了解決在釋放大內(nèi)存數(shù)據(jù)導(dǎo)致整個(gè)redis阻塞的性能問(wèn)題。
在刪除大key時(shí),釋放內(nèi)存往往都比較耗時(shí),所以Redis提供異步釋放內(nèi)存的方式,讓這些耗時(shí)的操作放到另一個(gè)線(xiàn)程中異步去處理,從而不影響主線(xiàn)程的執(zhí)行,提高性能。
到了Redis 6.0,Redis又引入了多線(xiàn)程來(lái)完成請(qǐng)求數(shù)據(jù)的協(xié)議解析,進(jìn)一步提升性能。它主要是解決高并發(fā)場(chǎng)景下,單線(xiàn)程解析請(qǐng)求數(shù)據(jù)協(xié)議帶來(lái)的壓力。請(qǐng)求數(shù)據(jù)的協(xié)議解析由多線(xiàn)程完成之后,后面的請(qǐng)求處理階段依舊還是單線(xiàn)程排隊(duì)處理。
可見(jiàn),Redis并不是保守地認(rèn)為單線(xiàn)程有多好,也不是為了使用多線(xiàn)程而引入多線(xiàn)程。Redis作者很清楚單線(xiàn)程和多線(xiàn)程的使用場(chǎng)景,針對(duì)性地優(yōu)化,這是非常值得我們學(xué)習(xí)的。
缺點(diǎn)
上面介紹了單線(xiàn)程可以達(dá)到如此高的性能,并不是說(shuō)它就沒(méi)有缺點(diǎn)了。
單線(xiàn)程處理最大的缺點(diǎn)就是,如果前一個(gè)請(qǐng)求發(fā)生耗時(shí)比較久的操作,那么整個(gè)Redis就會(huì)阻塞住,其他請(qǐng)求也無(wú)法進(jìn)來(lái),直到這個(gè)耗時(shí)久的操作處理完成并返回,其他請(qǐng)求才能被處理到。
我們平時(shí)遇到Redis變慢或長(zhǎng)時(shí)間阻塞的問(wèn)題,90%也都是因?yàn)镽edis處理請(qǐng)求是單線(xiàn)程這個(gè)原因?qū)е碌摹?/p>
所以,我們?cè)谑褂肦edis時(shí),一定要避免非常耗時(shí)的操作,例如使用時(shí)間復(fù)雜度過(guò)高的方式獲取數(shù)據(jù)、一次性獲取過(guò)多的數(shù)據(jù)、大量key集中過(guò)期導(dǎo)致Redis淘汰key壓力變大等等,這些場(chǎng)景都會(huì)阻塞住整個(gè)處理線(xiàn)程,直到它們處理完成,勢(shì)必會(huì)影響業(yè)務(wù)的訪(fǎng)問(wèn)。
我會(huì)在后期的文章中專(zhuān)門(mén)介紹具體有哪些場(chǎng)景會(huì)引發(fā)Redis阻塞的問(wèn)題,并提供規(guī)避問(wèn)題的方法和優(yōu)化方案。
總結(jié)
Redis使用單線(xiàn)程,配合IO多路復(fù)用技術(shù),可以完成多個(gè)連接的請(qǐng)求處理。而且正是由于它的使用定位是內(nèi)存數(shù)據(jù)庫(kù),這樣幾乎所有的操作都在內(nèi)存中完成,它的性能可以達(dá)到非常之高。
同時(shí),單線(xiàn)程沒(méi)有了線(xiàn)程上下文切換和訪(fǎng)問(wèn)共享資源加鎖的性能損耗,而且單線(xiàn)程模型對(duì)程序的開(kāi)發(fā)和調(diào)試非常友好,因此Redis使用單線(xiàn)程模型也就在情理之中了。
Redis在最近的版本也對(duì)多線(xiàn)程進(jìn)行了優(yōu)化,用于解決釋放大內(nèi)存數(shù)據(jù)和請(qǐng)求數(shù)據(jù)協(xié)議解析對(duì)Redis產(chǎn)生的性能影響,進(jìn)一步提升了Redis的性能。
單線(xiàn)程結(jié)合上述場(chǎng)景可以達(dá)到非常高的性能,同時(shí)也存在耗時(shí)操作阻塞整個(gè)線(xiàn)程的問(wèn)題,我們?cè)谑褂肦edis時(shí)要避免耗時(shí)過(guò)長(zhǎng)的操作,才能更好地發(fā)揮Redis的性能。
總結(jié)
以上是生活随笔為你收集整理的redis线程阻塞原因排插_每次面试都要被问:为什么采用单线程的Redis也会如此之快?...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: python 时分秒毫秒_python将
- 下一篇: flex vue 垂直居中居上_推荐几种