主頁 > 知識(shí)庫(kù) > Redis不是一直號(hào)稱單線程效率也很高嗎,為什么又采用多線程了?

Redis不是一直號(hào)稱單線程效率也很高嗎,為什么又采用多線程了?

熱門標(biāo)簽:鄭州人工智能電銷機(jī)器人系統(tǒng) 山東外呼銷售系統(tǒng)招商 北京400電話辦理收費(fèi)標(biāo)準(zhǔn) 貴州電銷卡外呼系統(tǒng) 魔獸2青云地圖標(biāo)注 十堰營(yíng)銷電銷機(jī)器人哪家便宜 日本中國(guó)地圖標(biāo)注 超呼電話機(jī)器人 宿遷便宜外呼系統(tǒng)平臺(tái)

Redis是目前廣為人知的一個(gè)內(nèi)存數(shù)據(jù)庫(kù),在各個(gè)場(chǎng)景中都有著非常豐富的應(yīng)用,前段時(shí)間Redis推出了6.0的版本,在新版本中采用了多線程模型。

因?yàn)槲覀児臼褂玫膬?nèi)存數(shù)據(jù)庫(kù)是自研的,按理說我對(duì)Redis的關(guān)注其實(shí)并不算多,但是因?yàn)镽edis用的比較廣泛,所以我需要了解一下這樣方便我進(jìn)行面試。

總不能候選人用過Redis,但是我非要問人家阿里的Tair是怎么回事吧。

所以,在Redis 6.0 推出之后,我想去了解下為什么采用多線程,現(xiàn)在采用的多線程和以前版本有什么區(qū)別?為什么這么晚才使用多線程?

Redis不是已經(jīng)采用了多路復(fù)用技術(shù)嗎?不是號(hào)稱很高的性能了嗎?為啥還要采用多線程模型呢?

本文就來分析下這些問題以及背后的思考。

Redis為什么最開始被設(shè)計(jì)成單線程的?

Redis作為一個(gè)成熟的分布式緩存框架,它由很多個(gè)模塊組成,如網(wǎng)絡(luò)請(qǐng)求模塊、索引模塊、存儲(chǔ)模塊、高可用集群支撐模塊、數(shù)據(jù)操作模塊等。

很多人說Redis是單線程的,就認(rèn)為Redis中所有模塊的操作都是單線程的,其實(shí)這是不對(duì)的。

我們所說的Redis單線程,指的是"其網(wǎng)絡(luò)IO和鍵值對(duì)讀寫是由一個(gè)線程完成的",也就是說,Redis中只有網(wǎng)絡(luò)請(qǐng)求模塊和數(shù)據(jù)操作模塊是單線程的。而其他的如持久化存儲(chǔ)模塊、集群支撐模塊等是多線程的。

所以說,Redis中并不是沒有多線程模型的,早在Redis 4.0的時(shí)候就已經(jīng)針對(duì)部分命令做了多線程化。

那么,為什么網(wǎng)絡(luò)操作模塊和數(shù)據(jù)存儲(chǔ)模塊最初并沒有使用多線程呢?

這個(gè)問題的答案比較簡(jiǎn)單!因?yàn)椋?沒必要!"

為什么沒必要呢?我們先來說一下,什么情況下要使用多線程?

多線程適用場(chǎng)景

一個(gè)計(jì)算機(jī)程序在執(zhí)行的過程中,主要需要進(jìn)行兩種操作分別是讀寫操作和計(jì)算操作。

其中讀寫操作主要是涉及到的就是I/O操作,其中包括網(wǎng)絡(luò)I/O和磁盤I/O。計(jì)算操作主要涉及到CPU。

而多線程的目的,就是通過并發(fā)的方式來提升I/O的利用率和CPU的利用率。

那么,Redis需不需要通過多線程的方式來提升提升I/O的利用率和CPU的利用率呢?

首先,我們可以肯定的說,Redis不需要提升CPU利用率,因?yàn)?strong>Redis的操作基本都是基于內(nèi)存的,CPU資源根本就不是Redis的性能瓶頸。

所以,通過多線程技術(shù)來提升Redis的CPU利用率這一點(diǎn)是完全沒必要的。

那么,使用多線程技術(shù)來提升Redis的I/O利用率呢?是不是有必要呢?

Redis確實(shí)是一個(gè)I/O操作密集的框架,他的數(shù)據(jù)操作過程中,會(huì)有大量的網(wǎng)絡(luò)I/O和磁盤I/O的發(fā)生。要想提升Redis的性能,是一定要提升Redis的I/O利用率的,這一點(diǎn)毋庸置疑。

但是,提升I/O利用率,并不是只有采用多線程技術(shù)這一條路可以走!

多線程的弊端

我們?cè)诤芏辔恼轮薪榻B過一些Java中的多線程技術(shù),如內(nèi)存模型、鎖、CAS等,這些都是Java中提供的一些在多線程情況下保證線程安全的技術(shù)。

線程安全:是編程中的術(shù)語,指某個(gè)函數(shù)、函數(shù)庫(kù)在并發(fā)環(huán)境中被調(diào)用時(shí),能夠正確地處理多個(gè)線程之間的共享變量,使程序功能正確完成。

和Java類似,所有支持多線程的編程語言或者框架,都不得不面對(duì)的一個(gè)問題,那就是如何解決多線程編程模式帶來的共享資源的并發(fā)控制問題。

雖然,采用多線程可以幫助我們提升CPU和I/O的利用率,但是多線程帶來的并發(fā)問題也給這些語言和框架帶來了更多的復(fù)雜性。而且,多線程模型中,多個(gè)線程的互相切換也會(huì)帶來一定的性能開銷。

所以,在提升I/O利用率這個(gè)方面上,Redis并沒有采用多線程技術(shù),而是選擇了多路復(fù)用 I/O技術(shù)。

小結(jié)

Redis并沒有在網(wǎng)絡(luò)請(qǐng)求模塊和數(shù)據(jù)操作模塊中使用多線程模型,主要是基于以下四個(gè)原因:

  • 1、Redis 操作基于內(nèi)存,絕大多數(shù)操作的性能瓶頸不在 CPU
  • 2、使用單線程模型,可維護(hù)性更高,開發(fā),調(diào)試和維護(hù)的成本更低
  • 3、單線程模型,避免了線程間切換帶來的性能開銷
  • 4、在單線程中使用多路復(fù)用 I/O技術(shù)也能提升Redis的I/O利用率

還是要記?。篟edis并不是完全單線程的,只是有關(guān)鍵的網(wǎng)絡(luò)IO和鍵值對(duì)讀寫是由一個(gè)線程完成的。

Redis的多路復(fù)用

多路復(fù)用這個(gè)詞,相信很多人都不陌生。我之前的很多文章中也夠提到過這個(gè)詞。

其中在介紹Linux IO模型的時(shí)候我們提到過它、在介紹HTTP/2的原理的時(shí)候,我們也提到過他。

那么,Redis的多路復(fù)用技術(shù)和我們之前介紹的又有什么區(qū)別呢?

這里先講講Linux多路復(fù)用技術(shù),就是多個(gè)進(jìn)程的IO可以注冊(cè)到同一個(gè)管道上,這個(gè)管道會(huì)統(tǒng)一和內(nèi)核進(jìn)行交互。當(dāng)管道中的某一個(gè)請(qǐng)求需要的數(shù)據(jù)準(zhǔn)備好之后,進(jìn)程再把對(duì)應(yīng)的數(shù)據(jù)拷貝到用戶空間中。

多看一遍上面這張圖和上面那句話,后面可能還會(huì)用得到。

也就是說,通過一個(gè)線程來處理多個(gè)IO流。

IO多路復(fù)用在Linux下包括了三種,select、poll、epoll,抽象來看,他們功能是類似的,但具體細(xì)節(jié)各有不同。

其實(shí),Redis的IO多路復(fù)用程序的所有功能都是通過包裝操作系統(tǒng)的IO多路復(fù)用函數(shù)庫(kù)來實(shí)現(xiàn)的。每個(gè)IO多路復(fù)用函數(shù)庫(kù)在Redis源碼中都有對(duì)應(yīng)的一個(gè)單獨(dú)的文件。

在Redis 中,每當(dāng)一個(gè)套接字準(zhǔn)備好執(zhí)行連接應(yīng)答、寫入、讀取、關(guān)閉等操作時(shí),就會(huì)產(chǎn)生一個(gè)文件事件。因?yàn)橐粋€(gè)服務(wù)器通常會(huì)連接多個(gè)套接字,所以多個(gè)文件事件有可能會(huì)并發(fā)地出現(xiàn)。

一旦有請(qǐng)求到達(dá),就會(huì)交給 Redis 線程處理,這就實(shí)現(xiàn)了一個(gè) Redis 線程處理多個(gè) IO 流的效果。

所以,Redis選擇使用多路復(fù)用IO技術(shù)來提升I/O利用率。

而之所以Redis能夠有這么高的性能,不僅僅和采用多路復(fù)用技術(shù)和單線程有關(guān),此外還有以下幾個(gè)原因:

1、完全基于內(nèi)存,絕大部分請(qǐng)求是純粹的內(nèi)存操作,非??焖?。

2、數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)單,對(duì)數(shù)據(jù)操作也簡(jiǎn)單,如哈希表、跳表都有很高的性能。

3、采用單線程,避免了不必要的上下文切換和競(jìng)爭(zhēng)條件,也不存在多進(jìn)程或者多線程導(dǎo)致的切換而消耗 CPU

4、使用多路I/O復(fù)用模型

為什么Redis 6.0 引入多線程

2020年5月份,Redis正式推出了6.0版本,這個(gè)版本中有很多重要的新特性,其中多線程特性引起了廣泛關(guān)注。

但是,需要提醒大家的是,Redis 6.0中的多線程,也只是針對(duì)處理網(wǎng)絡(luò)請(qǐng)求過程采用了多線程,而數(shù)據(jù)的讀寫命令,仍然是單線程處理的。

但是,不知道會(huì)不會(huì)有人有這樣的疑問:

Redis不是號(hào)稱單線程也有很高的性能么?

不是說多路復(fù)用技術(shù)已經(jīng)大大的提升了IO利用率了么,為啥還需要多線程?

主要是因?yàn)槲覀儗?duì)Redis有著更高的要求。

根據(jù)測(cè)算,Redis 將所有數(shù)據(jù)放在內(nèi)存中,內(nèi)存的響應(yīng)時(shí)長(zhǎng)大約為 100 納秒,對(duì)于小數(shù)據(jù)包,Redis 服務(wù)器可以處理 80,000 到 100,000 QPS,這么高的對(duì)于 80% 的公司來說,單線程的 Redis 已經(jīng)足夠使用了。

但隨著越來越復(fù)雜的業(yè)務(wù)場(chǎng)景,有些公司動(dòng)不動(dòng)就上億的交易量,因此需要更大的 QPS。

為了提升QPS,很多公司的做法是部署Redis集群,并且盡可能提升Redis機(jī)器數(shù)。但是這種做法的資源消耗是巨大的。

而經(jīng)過分析,限制Redis的性能的主要瓶頸出現(xiàn)在網(wǎng)絡(luò)IO的處理上,雖然之前采用了多路復(fù)用技術(shù)。但是我們前面也提到過,多路復(fù)用的IO模型本質(zhì)上仍然是同步阻塞型IO模型。

下面是多路復(fù)用IO中select函數(shù)的處理過程:

從上圖我們可以看到,在多路復(fù)用的IO模型中,在處理網(wǎng)絡(luò)請(qǐng)求時(shí),調(diào)用 select (其他函數(shù)同理)的過程是阻塞的,也就是說這個(gè)過程會(huì)阻塞線程,如果并發(fā)量很高,此處可能會(huì)成為瓶頸。

雖然現(xiàn)在很多服務(wù)器都是多個(gè)CPU核的,但是對(duì)于Redis來說,因?yàn)槭褂昧藛尉€程,在一次數(shù)據(jù)操作的過程中,有大量的CPU時(shí)間片是耗費(fèi)在了網(wǎng)絡(luò)IO的同步處理上的,并沒有充分的發(fā)揮出多核的優(yōu)勢(shì)。

如果能采用多線程,使得網(wǎng)絡(luò)處理的請(qǐng)求并發(fā)進(jìn)行,就可以大大的提升性能。多線程除了可以減少由于網(wǎng)絡(luò) I/O 等待造成的影響,還可以充分利用 CPU 的多核優(yōu)勢(shì)。

所以,Redis 6.0采用多個(gè)IO線程來處理網(wǎng)絡(luò)請(qǐng)求,網(wǎng)絡(luò)請(qǐng)求的解析可以由其他線程完成,然后把解析后的請(qǐng)求交由主線程進(jìn)行實(shí)際的內(nèi)存讀寫。提升網(wǎng)絡(luò)請(qǐng)求處理的并行度,進(jìn)而提升整體性能。

但是,Redis 的多 IO 線程只是用來處理網(wǎng)絡(luò)請(qǐng)求的,對(duì)于讀寫命令,Redis 仍然使用單線程來處理。

那么,在引入多線程之后,如何解決并發(fā)帶來的線程安全問題呢?

這就是為什么我們前面多次提到的"Redis 6.0的多線程只用來處理網(wǎng)絡(luò)請(qǐng)求,而數(shù)據(jù)的讀寫還是單線程"的原因。

Redis 6.0 只有在網(wǎng)絡(luò)請(qǐng)求的接收和解析,以及請(qǐng)求后的數(shù)據(jù)通過網(wǎng)絡(luò)返回給時(shí),使用了多線程。而數(shù)據(jù)讀寫操作還是由單線程來完成的,所以,這樣就不會(huì)出現(xiàn)并發(fā)問題了。

參考資料:

https://www.cnblogs.com/Zzbj/p/13531622.html

https://xie.infoq.cn/article/b3816e9fe3ac77684b4f29348

https://jishuin.proginn.com/p/763bfbd2a1c2 《極客時(shí)間:Redis核心技術(shù)與實(shí)戰(zhàn)》

到此這篇關(guān)于Redis不是一直號(hào)稱單線程效率也很高嗎,為什么又采用多線程了?的文章就介紹到這了,更多相關(guān)Redis單線程多線程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • redis單線程快的原因和原理
  • Redis為什么快如何實(shí)現(xiàn)高可用及持久化
  • Redis憑啥可以這么快
  • 為啥Redis使用pipelining會(huì)更快
  • Redis高效率原因及數(shù)據(jù)結(jié)構(gòu)分析

標(biāo)簽:果洛 大慶 臺(tái)州 楊凌 朝陽 北京 江蘇 吉安

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Redis不是一直號(hào)稱單線程效率也很高嗎,為什么又采用多線程了?》,本文關(guān)鍵詞  Redis,不是,一直,號(hào)稱,單線程,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《Redis不是一直號(hào)稱單線程效率也很高嗎,為什么又采用多線程了?》相關(guān)的同類信息!
  • 本頁收集關(guān)于Redis不是一直號(hào)稱單線程效率也很高嗎,為什么又采用多線程了?的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章