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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

redis 为什么这么快,你真的知道吗?

發布時間:2024/3/12 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 redis 为什么这么快,你真的知道吗? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言


相信大家在面試過程中,都被面試官問到過這樣一個問題,緩存中間件大名鼎鼎的 redis 速度為什么這么快呢?

針對于面試過程中的痛點問題,筆者昨晚熬夜收集資料,并且通過走訪大量使用者,整理出如下的結論。我敢保證,你看了這篇文章,再問你這個問題,保準把面試官虐哭。

分析原因


這里就不賣關子了,先說結論,我們再對原因進行抽絲剝繭。

redis快的原因

  • 純內存操作(最主要條件)
  • 合適的線程模型
  • 優秀的數據結構
  • 合理的數據編碼方式
  • 純內存操作(最主要條件)


    首先最主要的原因一定是:redis 的數據操作是基于內存的

    眾所周知,內存的訪問速度是遠遠大于硬盤訪問速度的。我們來做個對比,拿數據庫(硬盤)和 redis (內存)對比,一個操作對應磁盤,一個操作對應內存。他們兩個的的訪問速度差了一個數量級。

    可能大家對數量級沒有什么該概念。那可是整整 1000 倍啊!現在大家知道了吧。
    下面是我精心為大家準備的訪問速度圖,已經驗證,方便大家食用。

    有的小伙伴要問了,redis不是有數據持久化嗎?
    怎么會是只操作內存呢?

    這位同學一看就是對 redis 理解的不夠透徹,redis 持久化線程和操作內存數據的線程,并不是一個線程,我們這里說的 redis 快,只是針對操作內存的線程來說的,操作很快。因為操作是直接客戶端響應時間息息相關的。

    合適的線程模型


    🥈單線程誤區

    先說一個常見誤區,就是大家在其他的文章或者面試題中,通過一段時間的以訛傳訛。
    大家都認為 redis 速度快,有一個原因是單線程!!!

    在這里先反駁一下這個觀點,這個結論是個明顯的因果顛倒,主次不分的結論!!

    為什么這么說呢?

    首先單線程 redis 不是純粹的單線程,我們所知曉的 redis 單線程只有 網絡請求模塊和 數據操作模塊是單線程的

    你要知道多線程的出現,本身就是為了解決多核心 CPU 利用率不足。如果單線程是快的原因的話,那么我們還要多線程干什么,小伙伴你說是吧!

    那為什么不用多線程呢?

    因為沒有必要,我們先來想一下多線程適用場景有哪些?
    在這之前,我們先了解一下計算機在運行過程中的主要操作分為以下兩種:

  • CPU 計算操作
  • 網絡和磁盤 IO 讀取操作
  • 多線程的出現以及適用場景目的就是為了提升單線程在 cpu利用率和io利用率之間的不足

    那么redis怎么不需要多線程呢?

    我們從上面的計算機操作分類來說

  • 從 CPU 計算來說,redis 操作都是基于內存操作,很少有一些耗費CPU 的計算操作,對于 redis 操作來說,CPU 計算不是瓶頸,瓶頸在于 redis 操作內存的速度
  • 從網絡 IO 來說,redis網絡 IO 接收事件,確實是一個很需要去提升的點 因為所有客戶端對 redis 的操作 最終都會由 redis 的網絡模塊接受 ,所以對于 redis 來說 提升網絡 IO 的利用率 很有必要
  • 結論:redis 在 CPU 計算上不存在瓶頸,性能瓶頸只存在于網絡 IO 中

    但是~想要提高網絡 IO 的利用率,不是只有多線程一條路。

  • redis 由于歷史遺留原因最終沒有采用多線程處理網絡 IO 而是采取了 單線程 + 多路復用器處理。
  • 在2020年,redis 6.0版本 已經開始做多線程處理網絡 IO ,性能提升巨大。
  • 所以說千萬不要陷入 redis 是單線程所以快,現在是 CPU 多核心時代,最差的情況 CPU 一個核心綁定一個線程,不同線程之間也不處理競態資源,也比你只用到一個核心處理快的多了吧!

    我這里總結一下我的看法redis 6.0版本 之前采用單線程處理網絡 IO 原因如下:

  • redis 為了保持一貫的語義,采用了單線程模型(也許是懶吧
  • 就算是單線程,也完全足夠用了,在不需要超大并發的情況下,也不需要上多線程。
  • 那為什么redis 6.0 還是采用了多線程處理網絡 IO ?

    不是說多路復用技術已經大大的提升了網絡 IO 利用率了么,為啥還需要多線程?

    主要是因為我們對 Redis 有著更高的要求。

    據測算,redis 將所有數據放在內存中,內存的響應時長大約為 100 納秒,對于小數據包,redis 服務器可以處理 80,000 到 100,000 QPS,這么高的對于 80% 的公司來說,單線程的 redis 已經足夠使用了。


    但隨著越來越復雜的業務場景,有些公司動不動就上億的交易量,因此需要更大的 QPS。

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

    而經過分析,限制 redis 的性能的主要瓶頸出現在網絡IO的處理上,雖然之前采用了多路復用技術。但是我們前面也提到過,多路復用的 IO 模型本質上仍然是同步阻塞型 IO 模型

    下圖是 redis 網絡 IO 多線程和單線程的速度對比圖,大家都來看一下


    從上面可以看到 `GET/SET` 命令在 4 線程 IO 時性能相比單線程是幾乎是翻倍了。

    結論:redis 6.0 多線程網絡 IO 性能提升巨大,不嚴謹條件下幾乎翻倍

    🥈單線程模式下快的原因

    說完了對于單線程的誤區,下面我們就要說一下在單線程模式下,redis 快的原因

    用四個字就可以來形容這個原因,那就是 多路復用

    多路復用是啥呢?

    簡單理解就是 單個線程同時檢測若干個網絡連接(Socket)是否可以執行IO操作的能力,就是將多個進程的網絡 IO Socket注冊到同一個管道上。 用最少的資源,干最多的事情。

    比較傳統的方式是使用多線程模型,每來一個客戶端連接,就分配一個線程,然后后續的讀寫都在對應的進程/線程,這種方式處理 100 個客戶端沒問題,但是當客戶端增大到 10000 個時,10000 個進程/線程的調度、上下文切換以及它們占用的內存,都會成為瓶頸。

    為了解決上面這個問題,就出現了 I/O 的多路復用,可以只在一個進程里處理多個文件的 I/O


    所有的 io 操作 由這一個管道來和內核進行統一交互 管道中的io請求數據準備好之后 管道會將數據 拷貝到用戶空間中。
    redis 中,每當一個套接字準備好執行連接應答、寫入、讀取、關閉等操作時,就會產生一個文件事件。因為一個服務器通常會連接多個套接字,所以多個文件事件有可能會并發地出現。

    但是出現的個數不可能有很多,這樣我們用一個線程來監聽這些消息,然后分派去給操作線程執行就可以。

    多路復用模型顯而易見的好處:

  • 單線程,省去多個線程創建和上下文切換操作
  • Socket 連接不多的情況,性能甚至比多線程有可能要高
  • 優秀的數據結構


    redis 在存儲數據結構的設計上還是花了一番心思的 不然這也不會成為它快的一點原因。
    它擁有五種常用的數據類型,幫助我們在各種各樣的場景上都能靈活應對,并且也能用對應的數據類型做出很多很有意思的事情。

    redis的五種數據類型主要有:

  • String 整數浮點數或者字符串
  • Set 集合
  • Zset 有序集合
  • Hash 散列表
  • List 列表
  • 舉個例子,我們都知道redis底層使用c語言寫的,但是 String 實現并不是簡單的用c語言的字符串實現的,而是采用一個 SDS(簡單動態字符串) 的結構體來實現的。

    Tips:這里給大家補充一個知識點,C語言的String是以 “\0” 結尾的,并且計算長度是得通過遍歷獲取,時間復雜度是 O(n) , 而且在數據中不能有 “\0” 出現,會導致計算錯誤。

    redis String 的 SDS 結構體,不僅讓長度的獲取是 O(1) 操作,而且二進制安全,沒有特殊字符的限制,可以存儲視頻圖片的數據。
    這里我想讓大家知道,redis 數據結構設計考慮還是很優秀的。

    數據結構的詳細解析,我們在這里就不多贅述了,我們放到我們的下一篇。
    歡迎小伙伴們前去圍觀,也歡迎批評指正。

    合理的數據編碼方式


    怎么理解這個合理的編碼方式呢?

    我們還是以 redis 中的 string 結構舉例子,redis為了存儲不同大小的字符串,精心設計了 5 種類型。
    sdshdr5、sdshdr8、sdshdr16、sdshdr32、sdshdr64
    它們的不同就是,本身的數據類型不同,舉個例子

  • sdshdr16 中的字段分配大小是 uint16 2^16
  • sdshdr32 中的字段分配大小是 uint32 2^32
  • 結論: 通過這種能夠靈活存儲不同大小的字符串,有效的節省了內存。字符串大的時候分配大的內存空間,小的時候就分配小的,高效利用內存。

    當然,在這里只是舉個例子,想了解更多redis 底層細節的小伙伴,我們放到了后續的系列。
    歡迎小伙伴們前去圍觀,也歡迎批評指正。

    總結


    至此,我們知道了這個 redis 經典面試題的答案了。
    原因無他。分別是:

  • 純內存操作
  • 多路復用線程模型
  • 優秀的數據結構
  • 合理的數據編碼方式
  • 不知道大家學會了嗎? 學會的小伙伴們,再也不怕那些刁鉆的面試官了,我敢保證,你看了這篇文章,再問你這個問題,保準把面試官虐哭。

    總結

    以上是生活随笔為你收集整理的redis 为什么这么快,你真的知道吗?的全部內容,希望文章能夠幫你解決所遇到的問題。

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