日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

性能測試報告

查看了下阿里云 redis 的性能測試報告如下,能夠達到數十萬、百萬級別的 QPS(暫時忽略阿里對 Redis 所做的優化),我們從 Redis 的設計和實現來分析一下 Redis 是怎么做的。

為什么單線程的Redis能夠達到百萬級的QPS?

 

Redis 的設計與實現

其實 Redis 主要是通過三個方面來滿足這樣高效吞吐量的性能需求

  • 高效的數據結構
  • 多路復用 IO 模型
  • 事件機制

高效的數據結構

Redis 支持的幾種高效的數據結構 string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集 合)

以上幾種對外暴露的數據結構它們的底層編碼方式都是做了不同的優化的,不細說了,不是本文重點

多路復用 IO 模型

假設某一時刻與 Redis 服務器建立了 1 萬個長連接,對于阻塞式 IO 的做法就是,對每一條連接都建立一個線程來處理,那么就需要 1萬個線程,同時根據我們的經驗對于 IO 密集型的操作我們一般設置,線程數 = 2 * CPU 數量 + 1,對于 CPU 密集型的操作一般設置線程 = CPU 數量 + 1,當然各種書籍或者網上也有一個詳細的計算公式可以算出更加合適準確的線程數量,但是得到的結果往往是一個比較小的值,像阻塞式 IO 這也動則創建成千上萬的線程,系統是無法承載這樣的負荷的更加彈不上高效的吞吐量和服務了。

而多路復用 IO 模型的做法是,用一個線程將這一萬個建立成功的鏈接陸續的放入 event_poll,event_poll 會為這一萬個長連接注冊回調函數,當某一個長連接準備就緒后(建立建立成功、數據讀取完成等),就會通過回調函數寫入到 event_poll 的就緒隊列 rdlist 中,這樣這個單線程就可以通過讀取 rdlist 獲取到需要的數據

需要注意的是,除了異步 IO 外,其它的 I/O 模型其實都可以歸類為阻塞式 I/O 模型,不同的是像阻塞式 I/O 模型在第一階段讀取數據的時候,如果此時數據未準備就緒需要阻塞,在第二階段數據準備就緒后需要將數據從內核態復制到用戶態這一步也是阻塞的。而多路復用 IO 模型在第一階段是不阻塞的,只會在第二階段阻塞

通過這種方式,就可以用 1 個或者幾個線程來處理大量的連接了,極大的提升了吐吞量

為什么單線程的Redis能夠達到百萬級的QPS?

 

事件機制

redis 客戶端與 redis 服務端建立連接,發送命令,redis 服務器響應命令都是需要通過事件機制來做的,如下圖(來自互聯網的某處...)

為什么單線程的Redis能夠達到百萬級的QPS?

 

 

  1. 首先 redis 服務器運行,監聽套接字的 AE_READABLE 事件處于監聽的狀態下,此時連接應答處理器工作,
  2. 客戶端與 redis 服務器發起建立連接,監聽套接字產生 AE_READABLE 事件,當 IO 多路復用程序監聽到其準備就緒后,將該事件壓入隊列中,由文件事件分派器獲取隊列中的事件交于連接應答處理器工作處理,應答客戶端建立連接成功,同時將客戶端 socket 的 AE_READABLE 事件壓入隊列由文件事件分派器獲取隊列中的事件交命令請求處理器關聯
  3. 客戶端發送 set key value 請求,客戶端 socket 的 AE_READABLE 事件,當 IO 多路復用程序監聽到其準備就緒后,將該事件壓入隊列中,由文件事件分派器獲取隊列中的事件交于命令請求處理器關聯處理
  4. 命令請求處理器關聯處理完成后,需要響應客戶端操作完成,此時將產生 socket 的 AE_WRITEABLE 事件壓入隊列,由文件事件分派器獲取隊列中的事件交于命令恢復處理器處理,返回操作結果,完成后將解除 AE_WRITEABLE 事件與命令恢復處理器的關聯

reactor模式

大體上可以說 Redis 的工作模式是,reactor 模式配合一個隊列,用一個 serverAccept 線程來處理建立請求的鏈接,并且通過 IO 多路復用模型,讓內核來監聽這些 socket,一旦某些 socket 的讀寫事件準備就緒后就對應的事件壓入隊列中,然后 worker 工作,由文件事件分派器從中獲取事件交于對應的處理器去執行,當某個事件執行完成后文件事件分派器才會從隊列中獲取下一個事件進行處理

可以類比在 netty 中,我們一般會設置 bossGroup 和 workerGroup 默認情況下 bossGroup 為 1,workerGroup = 2 * cpu 數量,這樣可以由多個線程來處理讀寫就緒的事件,但是其中不能有比較耗時的操作如果有的話需要將其放入線程池中,不然會降低其吐吞量。在 redis 中我們可以看做這二者的值都是 1

為什么說存儲的值不宜過大

比如一個 string key = a,存儲了 500MB,首先讀取事件壓入隊列中,文件事件分派器從中獲取到后,交于命令請求處理器處理,此處就涉及到從磁盤中加載 500MB,比如是普通的 SSD 硬盤,讀取速度 200MB/S,那么需要 2.5S 的讀取時間,此時其它 socket 所有的請求都將處于等待過程中,就會導致阻塞了 2.5S,同時又會占用較大的帶寬導致吞吐量進一步下降


作者:在江湖中coding
鏈接:https://juejin.im/post/5e6097846fb9a07c9f3fe744

分享到:
標簽:Redis
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定