1. 程式人生 > >Redis效能解析--Redis為什麼那麼快?

Redis效能解析--Redis為什麼那麼快?

echo編輯整理,歡迎轉載,轉載請宣告文章來源。歡迎新增echo微信(微訊號:t2421499075)交流學習。 百戰不敗,依不自稱常勝,百敗不頹,依能奮力前行。——這才是真正的堪稱強大!!!


Redis的實際被應用都是因為它的效能,在眾多快取中Redis也是一個比較快的中介軟體,而且它是單執行緒操作,沒有過的記憶體開銷,給程式帶來了更多的擴充套件空間。

Redis的效能展示

在保證網路通暢的情況下,相同的CPU和相同的Redis版本,處理不同大小的資料,Redis的吞吐量如下圖所示,該圖來自Redis的官方網站。我們可以在網站中看到。Redis在處理1000位元組的資料的時候,都是穩定位置吞吐量在10w,當處理的資料不斷增大的時候,吞吐量才慢慢開始下降。


圖片來自redis官網

下圖是提供的QPS測試圖,官方提供的資料是可以達到100000+的QPS(每秒內查詢次數)。

圖片來自redis官網

Redis為什麼那麼快?

  • 純記憶體KV操作
  • 內部是單程實現的(不需要建立/銷燬執行緒,避免上下文切換,無併發資源競爭的問題)
  • 非同步非阻塞的I/O(多路複用)

存記憶體KV操作快在哪裡?

我們從上面的介紹裡面我們看到了Redis是一個純kv的操作。並且Redis絕大部分請求是純粹的記憶體操作,所以速度非常快。資料存在記憶體中,型別與存在hashMap中,那麼為什麼那麼快呢?我們可以一起來看一下幾種常用資料結構的對比,和他們的優勢。

資料結構 操作 時間複雜度
List insert O(N)
List select O(1)
Set insert O(1)
Set select O(1)
HashMap insert O(1)
HashMap select O(1)

從上圖我們可以看出,HashMap的優勢就是查詢和操作的時間複雜度都是O(1),所以Redis內部採用這種結構能夠從根本上獲得足夠的優勢,當讓,Redis的快速不僅僅是資料結構成就的,還有單程成和非同步I/O

Redis為什麼使用單執行緒?

Redis使用單執行緒就夠了!我們可以看到下圖中官網的描述,Redis的使用瓶頸並不是CPU,它主要受到記憶體和網路的限制。例如,使用在一般Linux系統上執行的流水線Redis每秒可以傳送一百萬個請求,因此,如果您的應用程式主要使用O(N)或O(log(N))命令,則幾乎不會使用過多的CPU 。

從描述中我們可以看到,Redis在使用的時候,使用單執行緒就已經能夠獲取Redis足夠使用的CPU資源,主要的瓶頸在於記憶體。但是單執行緒為什麼能夠做到這麼快的速度的呢?

Redis使用單執行緒,相比於多執行緒快在哪裡?

從上面官網的介紹我們看到了,Redis的瓶頸不線上程,不在獲取CPU的資源,所以如果使用多執行緒就會帶來多餘的資源佔用。比如上下文切換、資源競爭、鎖的操作。

  • 上下文的切換
    • 上下文其實不難理解,它就是CPU暫存器和程式計數器。主要的作用就是存放沒有被分配到資源的執行緒,多執行緒操作的時候,不是每一個執行緒都能夠直接獲取到CPU資源的,我們之所以能夠看到我們電腦上能夠執行很多的程式,是應為多執行緒的執行和CPU不斷對多執行緒的切換。但是總有執行緒獲取到資源,也總有執行緒需要等待獲取資源,這個時候,等待獲取資源的執行緒就需要被掛起,也就是我們的寄存。這個時候我們的上下文就產生了,當我們的上下文再次被喚起,得到資源的時候,就是我們上下文的切換。
  • 競爭資源
    • 競爭資源相對來說比較好理解,CPU對上下文的切換其實就是一種資源分批,但是在切換之前,到底切換到哪一個上下文,就是資源競爭的開始。在我redis中由於是單執行緒的,所以所有的操作都不會涉及到資源的競爭。
  • 鎖的消耗
    • 對於多執行緒的情況來講,不能迴避的就是鎖的問題。如果說多執行緒操作出現併發,有可能導致資料不一致,或者操作達不到預期的效果。這個時候我們就需要鎖來解決這些問題。當我們的執行緒很多的時候,就需要不斷的加鎖,釋放鎖,該操作就會消耗掉我們很多的時間

I/O複用,非阻塞模型

對於I/O阻塞可能有很多人不知道,I/O操作的阻塞到底是怎麼引起的,Redis又是怎麼解決的呢?

  • I/O操作的阻塞:當用戶執行緒發出IO請求之後,核心會去檢視資料是否就緒,如果沒有就緒就會等待資料就緒,而使用者執行緒就會處於阻塞狀態,使用者執行緒交出CPU。當資料就緒之後,核心會將資料拷貝到使用者執行緒,並返回結果給使用者執行緒,使用者執行緒才解除block狀態。
  • Redis採用多路複用:I/O 多路複用其實是在單個執行緒中通過記錄跟蹤每一個sock(I/O流) 的狀態來管理多個I/O流。select, poll, epoll 都是I/O多路複用的具體的實現。epoll效能比其他幾者要好。redis中的I/O多路複用的所有功能通過包裝常見的select、epoll、evport和kqueue這些I/O多路複用函式庫來實現的。

做一個有底線的部落格