日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

Redis 属于单线程还是多线程?不同的版本有什么区别?

發(fā)布時間:2025/3/11 数据库 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis 属于单线程还是多线程?不同的版本有什么区别? 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Redis 是普及率最高的技術之一,同時也是面試中必問的一個技術模塊,所以從今天開始我們將從最熱門的 Redis 面試題入手,更加深入的學習和了解一下 Redis。

我們本文的面試題是 Redis 屬于單線程還是多線程?

典型回答

本文的問題在不同的 Redis 版本下答案是不同的,在 Redis 4.0 之前,Redis 是單線程運行的,但單線程并不意味著性能低,類似單線程的程序還有 Nginx 和 NodeJs 他們都是單線程程序,但是效率并不低。 Redis 的 FAQ(Frequently Asked Questions,常見問題)也回到過這個問題,具體內容如下:

Redis is single threaded. How can I exploit multiple CPU / cores?

It's not very frequent that CPU becomes your bottleneck with Redis, as usually Redis is either memory or network bound. For instance, using pipelining Redis running on an average Linux system can deliver even 1 million requests per second, so if your application mainly uses O(N) or O(log(N)) commands, it is hardly going to use too much CPU.

However, to maximize CPU usage you can start multiple instances of Redis in the same box and treat them as different servers. At some point a single box may not be enough anyway, so if you want to use multiple CPUs you can start thinking of some way to shard earlier.

You can find more information about using multiple Redis instances in the Partitioning page.

However with Redis 4.0 we started to make Redis more threaded. For now this is limited to deleting objects in the background, and to blocking commands implemented via Redis modules. For future releases, the plan is to make Redis more and more threaded.

詳情請見:https://redis.io/topics/faq

他的大體意思是說 Redis 是基于內存操作的,因此他的瓶頸可能是機器的內存或者網(wǎng)絡帶寬而并非 CPU,既然 CPU 不是瓶頸,那么自然就采用單線程的解決方案了,況且使用多線程比較麻煩。但是在 Redis 4.0 中開始支持多線程了,例如后臺刪除等功能。

簡單來說 Redis 之所以在 4.0 之前一直采用單線程的模式是因為以下三個原因:

  • 使用單線程模型是 Redis 的開發(fā)和維護更簡單,因為單線程模型方便開發(fā)和調試;
  • 即使使用單線程模型也并發(fā)的處理多客戶端的請求,主要使用的是多路復用(詳見本文下半部分);
  • 對于 Redis 系統(tǒng)來說,主要的性能瓶頸是內存或者網(wǎng)絡帶寬而并非 CPU。

Redis 在 4.0 中引入了惰性刪除(也可以叫異步刪除),意思就是說我們可以使用異步的方式對 Redis 中的數(shù)據(jù)進行刪除操作了,例如 unlink key / flushdb async / flushall async 等命令,他們的執(zhí)行示例如下:

> unlink key # 后臺刪除某個 key > OK # 執(zhí)行成功 > flushall async # 清空所有數(shù)據(jù) > OK # 執(zhí)行成功

這樣處理的好處是不會導致 Redis 主線程卡頓,會把這些刪除操作交給后臺線程來執(zhí)行。

小貼士:通常情況下使用 del 指令可以很快的刪除數(shù)據(jù),而當被刪除的 key 是一個非常大的對象時,例如時包含了成千上萬個元素的 hash 集合時,那么 del 指令就會造成 Redis 主線程卡頓,因此使用惰性刪除可以有效的避免 Redis 卡頓的問題。

考點分析

關于 Redis 線程模型的問題(單線程或多線程)幾乎是 Redis 必問的問題之一,但能回答好的人卻寥寥無幾,大部分的人只能回到上來 Redis 是單線程的以及說出來單線程的眾多好處,但對于 Redis 4.0 和 Redis 6.0 中,尤其是 Redis 6.0 中的多線程能回答上來的人少之又少,和這個知識點相關的面試題還有以下這些。

  • Redis 主線程既然是單線程的,為什么還這么快?
  • 介紹一下 Redis 中的多路復用?
  • 介紹一下 Redis 6.0 中的多線程?

知識擴展

1.Redis 為什么這么快?

我們知道 Redis 4.0 之前是單線程的,那既然是單線程為什么還能這么快?

Redis 速度比較快的原因有以下幾點:

  • 基于內存操作:Redis 的所有數(shù)據(jù)都存在內存中,因此所有的運算都是內存級別的,所以他的性能比較高;
  • 數(shù)據(jù)結構簡單:Redis 的數(shù)據(jù)結構比較簡單,是為 Redis 專門設計的,而這些簡單的數(shù)據(jù)結構的查找和操作的時間復雜度都是 O(1),因此性能比較高;
  • 多路復用和非阻塞 I/O:Redis 使用 I/O 多路復用功能來監(jiān)聽多個 socket 連接客戶端,這樣就可以使用一個線程連接來處理多個請求,減少線程切換帶來的開銷,同時也避免了 I/O 阻塞操作,從而大大提高了 Redis 的性能;
  • 避免上下文切換:因為是單線程模型,因此就避免了不必要的上下文切換和多線程競爭,這就省去了多線程切換帶來的時間和性能上的消耗,而且單線程不會導致死鎖問題的發(fā)生。

官方使用基準測試的結果是,單線程的 Redis 吞吐量可以達到 10W/每秒,如下圖所示:

2.I/O 多路復用

套接字的讀寫方法默認情況下是阻塞的,例如當調用讀取操作 read 方法時,緩沖區(qū)沒有任何數(shù)據(jù),那么這個線程就會阻塞卡在這里,直到緩沖區(qū)有數(shù)據(jù)或者是連接被關閉時,read 方法才可以返回,線程才可以繼續(xù)處理其他業(yè)務。

但這樣顯然降低了程序的整體執(zhí)行效率,而 Redis 使用的就是非阻塞的 I/O,這就意味著 I/O 的讀寫流程不再是阻塞的,讀寫方法都是瞬間完成并返回的,也就是他會采用能讀多少讀多少能寫多少寫多少的策略來執(zhí)行 I/O 操作,這顯然更符合我們對性能的追求。

但這種非阻塞的 I/O 依然存在一個問題,那就是當我們執(zhí)行讀取數(shù)據(jù)操作時,有可能只讀取了一部分數(shù)據(jù),同樣寫入數(shù)據(jù)也是這種情況,當緩存區(qū)滿了之后我們的數(shù)據(jù)還沒寫完,剩余的數(shù)據(jù)何時寫何時讀就成了一個問題。

而 I/O 多路復用就是解決上面的這個問題的,使用 I/O 多路復用最簡單的實現(xiàn)方式就是使用 select 函數(shù),此函數(shù)為操作系統(tǒng)提供給用戶程序的 API 接口,是用于監(jiān)控多個文件描述符的可讀和可寫情況的,這樣就可以監(jiān)控到文件描述符的讀寫事件了,當監(jiān)控到相應的事件之后就可以通知線程處理相應的業(yè)務了,這樣就保證了 Redis 讀寫功能的正常執(zhí)行了。

I/O 多路復用執(zhí)行流程如下圖所示:

小貼士:現(xiàn)在的操作系統(tǒng)已經(jīng)很少使用 select 函數(shù)了,改為調用 epoll(linux)和 kqueue(MacOS)等函數(shù)了,因為 select 函數(shù)在文件描述符特別多時性能非常的差。

3.Redis 6.0 多線程

Redis 單線程的優(yōu)點很明顯,不但降低了 Redis 內部的實現(xiàn)復雜性,也讓所有操作都可以在無鎖的情況下進行操作,并且不存在死鎖和線程切換帶來的性能和時間上的消耗,但缺點也很明顯,單線程的機制導致 Redis 的 QPS(Query Per Second,每秒查詢率)很難得到有效的提高。

Redis 4.0 版本中雖然引入了多線程,但此版本中的多線程只能用于大數(shù)據(jù)量的異步刪除,然而對于非刪除操作的意義并不是很大。

如果我們使用多線程就可以分攤 Redis 同步讀寫 I/O 的壓力,以及充分的利用多核 CPU 的資源,并且可以有效的提升 Redis 的 QPS。在 Redis 中雖然使用了 I/O 多路復用,并且是基于非阻塞 I/O 進行操作的,但 I/O 的讀和寫本身是堵塞的,比如當 socket 中有數(shù)據(jù)時,Redis 會通過調用先將數(shù)據(jù)從內核態(tài)空間拷貝到用戶態(tài)空間,再交給 Redis 調用,而這個拷貝的過程就是阻塞的,當數(shù)據(jù)量越大時拷貝所需要的時間就越多,而這些操作都是基于單線程完成的。

因此在 Redis 6.0 中新增了多線程的功能來提高 I/O 的讀寫性能,他的主要實現(xiàn)思路是將主線程的 IO 讀寫任務拆分給一組獨立的線程去執(zhí)行,這樣就可以使多個 socket 的讀寫可以并行化了,但 Redis 的命令依舊是由主線程串行執(zhí)行的。

需要注意的是 Redis 6.0 默認是禁用多線程的,可以通過修改 Redis 的配置文件 redis.conf 中的 io-threads-do-reads 等于 true 來開啟多線程,完整配置為 io-threads-do-reads true,除此之外我們還需要設置線程的數(shù)量才能正確的開啟多線程的功能,同樣是修改 Redis 的配置,例如設置 io-threads 4 表示開啟 4 個線程。

小貼士:關于線程數(shù)的設置,官方的建議是如果為 4 核的 CPU,建議線程數(shù)設置為 2 或 3,如果為 8 核 CPU 建議線程數(shù)設置為 6,線程數(shù)一定要小于機器核數(shù),線程數(shù)并不是越大越好。

關于 Redis 的性能,Redis 作者 antirez 在 RedisConf 2019 分享時曾提到,Redis 6 引入的多線程 I/O 特性對性能提升至少是一倍以上。國內也有人在阿里云使用 4 個線程的 Redis 版本和單線程的 Redis 進行比較測試,發(fā)現(xiàn)測試的結果和 antirez 給出的結論基本吻合,性能基本可以提高一倍。

總結

本文我們介紹了 Redis 在 4.0 之前單線程依然很快的原因:基于內存操作、數(shù)據(jù)結構簡單、多路復用和非阻塞 I/O、避免了不必要的線程上下文切換,在 Redis 4.0 中已經(jīng)添加了多線程的支持,主要體現(xiàn)在大數(shù)據(jù)的異步刪除功能上,例如 unlink key、flushdb async、flushall async 等,Redis 6.0 新增了多線程 I/O 的讀寫并發(fā)能力,用于更好的提高 Redis 的性能。

總結

以上是生活随笔為你收集整理的Redis 属于单线程还是多线程?不同的版本有什么区别?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。