Redis底層數據結構
- 2019 年 10 月 7 日
- 筆記
在上一篇中我們已經介紹過了Redis有5種數據類型,但每一種數據類型底層的實現都是不同的,在學習Redis時,我們除了要掌握這5種數據類型外,還要了解它們具體的底層實現,這有助於我們更好的掌握Redis的,在遇到問題時,可以方便快速的解決問題,在這篇,我們主要了解全局命令、數據結構及內部編碼等方面的知識。
- 全局命令 Redis有5種數據結構,雖然它們底層不同,但還是有一些通用的命令是相同的。
- 查看所有鍵(返回所有的鍵,並它具體的鍵輸出出來)
keys *

- 查看鍵總數(返回當前資料庫中的鍵的個數)
dbsize

備註:dbsize命令在計算鍵總數時不會遍歷所有的鍵,而是直接獲Redis內置的鍵總數變數,所以dbsize命令的時間複雜度是O(1)。而keys命令則會遍歷所有鍵,所以它的時間複雜度是O(n),所以如果Redis中保存了大量的鍵時,keys命令要慎用。
- 檢查鍵是否存在
exists key

我們看exists命令是有返回值的當鍵存在時則返回值為1,當然鍵不存時返回值則為0。
- 刪除鍵
del key


我們知道在Redis中有5種數據結構,但del命令可以直接刪除任意類型的數據結構,而不用擔心它底層的實現。 我們看del命令和exists命令一樣,都是有返回值的。只不過不同的是del命令返回的時成功刪除鍵的個數。如果返回的是0,說明該鍵沒有被成功刪除,也就說明該鍵不存在。如果返回的是大於0的數,是表示多個鍵被刪除了。下面我們看一下刪除多個鍵的操作。
- 鍵過期
expire key seconds

Redis支援對鍵添加過期時間,當超過這個過期時間時,Redis會自動將鍵刪除。 當我們通過expire命令設置鍵的過期時間後,我們可以使用
ttl key
命令查看該鍵的剩餘過期時間,所以ttl命令是有返回值的,也就是該鍵的剩餘時間,單位是秒。除此之外,ttl命令有3種類型的返回值。下面我們看一下這3種返回值的區別。
>=0:表示剩餘的過期時間 -1:鍵沒設置過期時間 -2:鍵不存在
- 鍵的數據結構類型
type key

如果鍵是字元串則type命令返回的就是字元串,如果是其它的數據類型則會返回其它的數據類型(因為我們還沒有學習其它的類型,這裡暫時只考慮字元串),如果鍵不存在時,在返回none。
- 數據結構和內部編碼
上面我們知道type命令會返回Redis中鍵的數據類型,也就是string(字元串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)等。但這些只是對外的數據結構,實際上在Redis的內部不同的數據結構有不同的底層的內部編碼。不同內部編碼在Redis中有些不同的性能,並且在Redis中會自動判斷應該用哪種編碼來存儲數據,已保證Redis的性能。我們可以通過下面的命令來查看鍵的內部編碼。
object encoding key


我們可以看出,上面保存的jilinwula這個鍵的內部編碼就是embstr。下面我們看一下在Redis中所有的數據結構所對應的內部編碼。 下面我們分析一下,為什麼Redis要這樣設計數據結構及底層編碼呢。首先第一個好處就是可以改進內部編碼。當這樣做時,而不需要改變內部的數據結構,也就無需修改外部結構及命令了。第二個好處就是,我們知道不同的內部編碼有著不同的性能,當這樣設計時,如果我們要改變底層的內部編碼時,我們只需要根據Redis配置選項就可以,將我們曾經存儲過的key的底層編碼更改,這樣就可以針對不同的業務場景,個性化配置,進而提升性能。
- 單執行緒架構
我們知道Redis使用了單執行緒架構和I/O多路復用模型來實現高性能的記憶體服務。
- 單執行緒模型
每當客戶端調用命令時都會經歷3個步驟:發送命令、執行命令、返回結果3個過程。我們之前介紹過Redis是單執行緒的,所以每一條命令從客戶端發送到服務端,命令不會立即執行,而是將所有的命令都會進入一個隊列中,然後在順序執行。這樣,當我們客戶端啟動多個時執行命令時,不用考慮並發的問題,因為它們都會進入隊列,順序執行。
- 為什麼單執行緒處理速度這麼快 第一,我們知道Redis是將數據都存儲到記憶體中的,記憶體的處理速度,要比純硬碟IO的速度要快的多。 第二,非阻塞I/O,Redis使用epoll作為I/O多路復用技術實現的,在加上Redis自身的事件處理模型將epoll中的連接、讀寫、關閉都轉換為事件,不在網路I/O上浪費過多的時間。
- 單執行緒避免執行緒切換等消耗
第一,我們知道做項目開發時,如果要對多執行緒做兼容,那麼它要比單執行緒要複雜多了,程式碼變複雜了,出現BUG的可能性也就多了。

第二,在開發多種執行緒時,我們知道執行緒間的切換,是很耗資源的,並且對服務端來說,對執行緒添加鎖,每次執行時都會判斷鎖,是很費時間的。
雖然Redis的單執行緒架構是有好處的,但是這也是它的弊端,我們知道,在執行命令時是順序執行的,如果上一個命令沒有執行完,那麼剩下的命令是不會執行的,這也就造成了命令的阻塞。這對於Redis這種記憶體資料庫來說,如果發生了阻塞,那麼後果,可想而知,所以,我們在執行相關命令時,一定要慎重。