Redis 概覽

Redis 鍵相關的通用命令:

1. 查看全部鍵

KEYS

自1.0.0起可用。

時間複雜度: O(N), N 爲數據庫中 key 的數量。web

語法:KEYS pattern
說明:

查找全部符合給定模式 patternkeyredis

KEYS * 匹配數據庫中全部 key算法

KEYS h?llo 匹配 hellohallohxllo 等。shell

KEYS h*llo 匹配 hlloheeeeello 等。數據庫

KEYS h[ae]llo 匹配 hellohallo ,但不匹配 hillo數組

特殊符號用 \ 隔開安全

KEYS 的速度很是快,但在一個大的數據庫中使用它仍然可能形成性能問題,若是你須要從一個數據集中查找特定的 key ,你最好仍是用 Redis 的集合結構 (set)來代替。服務器

返回值:

符合給定模式的 key 列表。網絡

示例:
coderknock> KEYS *
 1) "name:45"
 2) "like_blog_num"
 3) "user:3"
 4) "40Key"
 5) "test"
 6) "coderknockCounter"
 7) "user:45"
 8) "str"
 9) "strHash"
10) "39Key"
11) "testChinese"
12) "user:5"
13) "intKey"
14) "embstrKey"
15) "map"
16) "user:34"
coderknock> KEYS user:*
1) "user:3"
2) "user:45"
3) "user:5"
4) "user:34"
coderknock> KEYS [34][09]Key
1) "40Key"
2) "39Key"
coderknock> KEYS user:[3]?
1) "user:34"
coderknock> KEYS user:[35]
1) "user:3"
2) "user:5"
coderknock> KEYS user:[3]*
1) "user:3"
2) "user:34"
coderknock> KEYS *Key
1) "40Key"
2) "39Key"
3) "intKey"
4) "embstrKey"

2. 鍵總數

DBSIZE

自1.0.0起可用。

時間複雜度: O(1)。數據結構

語法:DBSIZE
說明:

返回當前數據庫的 key 的數量。

返回值:

當前數據庫的 key 的數量。

示例:
coderknock> DBSIZE
(integer) 16
coderknock> DBSIZE
(integer) 16
coderknock> DBSIZE
(integer) 16
# 添加一個 key
coderknock> SET addKey name
coderknock> DBSIZE
(integer) 17
注意!:

DBSIZE 命令在計算鍵總數時不會遍歷全部鍵,而是直接獲取 Redis 內置的鍵總數變量,因此 DBSIZE 命令的時間複雜度是 O(1)。而 KEYS 命令會遍歷全部鍵,因此它的時間複雜度是 O(n),當 Redis 保存了大量鍵時,線上環境最好禁止使用 KEYS

3. 檢查鍵是否存在

EXISTS

自1.0.0起可用。

時間複雜度: O(1)。

語法:EXISTS key [key ...] Redis 3.0.3 及以上版本才能夠輸入多個 key
說明:

檢查給定 key 是否存在。

返回值:

key 存在,返回存在的 key 的個數,不然返回 0

示例:
coderknock> EXISTS addKey
(integer) 1
coderknock> EXISTS a
(integer) 0
# 同時查詢多個
coderknock> EXISTS addKey user:3 user:5 a embstrKey
(integer) 4

4. 刪除鍵

DEL

自1.0.0起可用。

時間複雜度: O(N), N 爲被刪除的 key 的數量。

刪除單個字符串類型的 key ,時間複雜度爲O(1)。

刪除單個列表、集合、有序集合或哈希表類型的 key ,時間複雜度爲O(M), M 爲以上數據結構內的元素數量。

語法:DEL key [key ...]
說明:

刪除給定的一個或多個 key

不存在的 key 會被忽略。

DEL 是一個通用命令,不管值是什麼數據結構類型,DEL 命令均可以將其刪除

返回值:

被刪除 key 的數量。

示例:
coderknock> HGETALL user:5
1) "name"
2) "coverSanchan"
3) "website"
4) "https://www.coderknock.com"
5) "user"
6) "sanchan"
coderknock> DEL user:5
(integer) 1
coderknock> DEL user:5
(integer) 0

5. 鍵過時

EXPIRE

自1.0.0起可用。

時間複雜度: O(1)

語法:EXPIRE key seconds
說明:

爲給定 key 設置生存時間,當 key 過時時(生存時間爲 0 ),它會被自動刪除。

在 Redis 中,帶有生存時間的 key 被稱爲『易失的』(volatile)。

生存時間能夠經過使用 DEL 命令來刪除整個 key 來移除,或者被 SETGETSET 命令覆寫(overwrite),這意味着,若是一個命令只是修改(alter)一個帶生存時間的 key 的值而不是用一個新的 key 值來代替(replace)它的話,那麼生存時間不會被改變。

好比說,對一個 key 執行 INCR 命令,對一個列表進行 LPUSH 命令,或者對一個哈希表執行 HSET 命令,這類操做都不會修改 key 自己的生存時間。

另外一方面,若是使用 RENAME 對一個 key 進行更名,那麼更名後的 key 的生存時間和更名前同樣。

RENAME 命令的另外一種多是,嘗試將一個帶生存時間的 key 更名成另外一個帶生存時間的 another_key ,這時舊的 another_key (以及它的生存時間)會被刪除,而後舊的 key 會更名爲 another_key ,所以,新的 another_key 的生存時間也和本來的 key 同樣。

使用 PERSIST 命令能夠在不刪除 key 的狀況下,移除 key 的生存時間,讓 key 從新成爲一個『持久的』(persistent) key

更新生存時間

能夠對一個已經帶有生存時間的 key 執行 EXPIRE 命令,新指定的生存時間會取代舊的生存時間。

過時時間的精確度

在 Redis 2.4 版本中,過時時間的延遲在 1 秒鐘以內 —— 也便是,就算 key 已通過期,但它仍是可能在過時以後一秒鐘以內被訪問到,而在新的 Redis 2.6 版本中,延遲被下降到 1 毫秒以內。

Redis 2.1.3 以前的不一樣之處

在 Redis 2.1.3 以前的版本中,修改一個帶有生存時間的 key 會致使整個 key 被刪除,這一行爲是受當時複製(replication)層的限制而做出的,如今這一限制已經被修復。

返回值:

設置成功返回 1

key 不存在或者不能爲 key 設置生存時間時(好比在低於 2.1.3 版本的 Redis 中你嘗試更新 key 的生存時間),返回 0

示例:
redis> SET cache_website "www.coderknock.com"
OK

redis> EXPIRE cache_website 30  # 設置過時時間爲 30 秒
(integer) 1

redis> TTL cache_website    # 查看剩餘生存時間
(integer) 23

redis> EXPIRE cache_website 30000   # 更新過時時間
(integer) 1

redis> TTL cache_website
(integer) 29996

# 在 SET 命令中也能夠直接 設置過時時間【SET 命令在 《Redis 字符串》中會講解】
coderknock> SET cache_website "www.coderknock.com" EX 30
OK
coderknock> TTL cache_website
(integer) 13
# 30 秒後該鍵被刪除
coderknock> EXISTS cache_website
(integer) 0

6. TTL 命令會返回鍵的剩餘過時時間,它有3種返回值:

TTL

自1.0.0起可用。

時間複雜度: O(1)

語法:TTL key
說明:

以秒爲單位,返回給定 key 的剩餘生存時間(TTL, time to live)。

返回值:

key 不存在時,返回 -2

key 存在但沒有設置剩餘生存時間時,返回 -1

不然,以秒爲單位,返回 key 的剩餘生存時間。

在 Redis 2.8 之前,當 key 不存在,或者 key 沒有設置剩餘生存時間時,命令都返回 -1

示例:
#TTL 正常使用在上面一個命令中已經有示例,下面演示一個對不存在 key 使用的狀況以及對沒有設置過時時間可使用的狀況
# 不存在 key
coderknock> TTL cache_website
(integer) -2
# 存在可是未設置過時時間的 key
coderknock> TTL user:3
(integer) -1

7. 查詢鍵對應的值的類型

TYPE

自1.0.0起可用。

時間複雜度: O(1)

語法:TTL key
說明:

返回 key 所儲存的值的類型。

返回值:

none (key不存在)

string (字符串)

list (列表)

set (集合)

zset (有序集)

hash (哈希表)

示例:
# 哈希
coderknock> TYPE user:3
hash
# 不存在
coderknock> TYPE a
none
# 字符串
coderknock> TYPE embstrKey
string

8. 掃描

SCAN

自2.8.0起可用。

時間複雜度: 增量式迭代命令每次執行的複雜度爲 O(1) , 對數據集進行一次完整迭代的複雜度爲 O(N), 其中 N 爲數據集中的元素數量。

語法:SCAN cursor [MATCH pattern][COUNT count]
說明:
SCAN

SCAN 命令及其相關的 SSCAN 命令、 HSCAN 命令和 ZSCAN 命令都用於增量地迭代(incrementally iterate)一集元素(a collection of elements):

  • SCAN 命令用於迭代當前數據庫中的數據庫鍵。
  • SSCAN 命令用於迭代集合鍵中的元素。
  • HSCAN 命令用於迭代哈希鍵中的鍵值對。
  • ZSCAN 命令用於迭代有序集合中的元素(包括元素成員和元素分值)。

以上列出的四個命令都支持增量式迭代, 它們每次執行都只會返回少許元素, 因此這些命令能夠用於生產環境, 而不會出現像 KEYS 命令、 SMEMBERS 命令帶來的問題 —— 當 KEYS 命令被用於處理一個大的數據庫時, 又或者 SMEMBERS 命令被用於處理一個大的集合鍵時, 它們可能會阻塞服務器達數秒之久。

不過, 增量式迭代命令也不是沒有缺點的: 舉個例子, 使用 SMEMBERS 命令能夠返回集合鍵當前包含的全部元素, 可是對於 SCAN 這類增量式迭代命令來講, 由於在對鍵進行增量式迭代的過程當中, 鍵可能會被修改, 因此增量式迭代命令只能對被返回的元素提供有限的保證 (offer limited guarantees about the returned elements)。

由於 SCANSSCANHSCANZSCAN 四個命令的工做方式都很是類似, 因此這個文檔會一併介紹這四個命令, 可是要記住:

  • SSCAN 命令、 HSCAN 命令和 ZSCAN 命令的第一個參數老是一個數據庫鍵。
  • SCAN 命令則不須要在第一個參數提供任何數據庫鍵 —— 由於它迭代的是當前數據庫中的全部數據庫鍵。
基本用法

SCAN 命令是一個基於遊標的迭代器(cursor based iterator): SCAN 命令每次被調用以後, 都會向用戶返回一個新的遊標, 用戶在下次迭代時須要使用這個新遊標做爲 SCAN 命令的遊標參數, 以此來延續以前的迭代過程。

SCAN 命令的遊標參數被設置爲 0 時, 服務器將開始一次新的迭代, 而當服務器向用戶返回值爲 0 的遊標時, 表示迭代已結束。

如下是一個 SCAN 命令的迭代過程示例:
coderknock> SCAN 0
1) "13" # 這個爲下一個 SCAN 使用的 cursor
2)  1) "name:45"
    2) "coderknockCounter"
    3) "intKey"
    4) "addKey"
    5) "like_blog_num"
    6) "map"
    7) "str"
    8) "user:45"
    9) "40Key"
   10) "user:3"
coderknock> SCAN 13
1) "0"
2) 1) "embstrKey"
   2) "testChinese"
   3) "strHash"
   4) "39Key"
   5) "test"
   6) "user:34"

在上面這個例子中, 第一次迭代使用 0 做爲遊標, 表示開始一次新的迭代。

第二次迭代使用的是第一次迭代時返回的遊標, 也便是命令回覆第一個元素的值 —— 13

從上面的示例能夠看到, SCAN 命令的回覆是一個包含兩個元素的數組, 第一個數組元素是用於進行下一次迭代的新遊標, 而第二個數組元素則是一個數組, 這個數組中包含了全部被迭代的元素。

在第二次調用 SCAN 命令時, 命令返回了遊標 0 , 這表示迭代已經結束, 整個數據集(collection)已經被完整遍歷過了。

0 做爲遊標開始一次新的迭代, 一直調用 SCAN 命令, 直到命令返回遊標 0 , 咱們稱這個過程爲一次完整遍歷(full iteration)。

SCAN 命令的保證(guarantees)

SCAN 命令, 以及其餘增量式迭代命令, 在進行完整遍歷的狀況下能夠爲用戶帶來如下保證: 從完整遍歷開始直到完整遍歷結束期間, 一直存在於數據集內的全部元素都會被完整遍歷返回; 這意味着, 若是有一個元素, 它從遍歷開始直到遍歷結束期間都存在於被遍歷的數據集當中, 那麼 SCAN 命令總會在某次迭代中將這個元素返回給用戶。

然而由於增量式命令僅僅使用遊標來記錄迭代狀態, 因此這些命令帶有如下缺點:

  • 同一個元素可能會被返回屢次。 處理重複元素的工做交由應用程序負責, 好比說, 能夠考慮將迭代返回的元素僅僅用於能夠安全地重複執行屢次的操做上。
  • 若是一個元素是在迭代過程當中被添加到數據集的, 又或者是在迭代過程當中從數據集中被刪除的, 那麼這個元素可能會被返回, 也可能不會, 這是未定義的(undefined)。
SCAN 命令每次執行返回的元素數量

增量式迭代命令並不保證每次執行都返回某個給定數量的元素。

增量式命令甚至可能會返回零個元素, 但只要命令返回的遊標不是 0 , 應用程序就不該該將迭代視做結束。

不過命令返回的元素數量老是符合必定規則的, 在實際中:

  • 對於一個大數據集來講, 增量式迭代命令每次最多可能會返回數十個元素;
  • 而對於一個足夠小的數據集來講, 若是這個數據集的底層表示爲編碼數據結構(encoded data structure,適用因而小集合鍵、小哈希鍵和小有序集合鍵), 那麼增量迭代命令將在一次調用中返回數據集中的全部元素。

最後, 用戶能夠經過增量式迭代命令提供的 COUNT 選項來指定每次迭代返回元素的最大值。

COUNT 選項

雖然增量式迭代命令不保證每次迭代所返回的元素數量, 但咱們可使用 COUNT 選項, 對命令的行爲進行必定程度上的調整。

基本上, COUNT 選項的做用就是讓用戶告知迭代命令, 在每次迭代中應該從數據集裏返回多少元素。

雖然 COUNT 選項只是對增量式迭代命令的一種提示(hint), 可是在大多數狀況下, 這種提示都是有效的。

  • COUNT 參數的默認值爲 10
  • 在迭代一個足夠大的、由哈希表實現的數據庫、集合鍵、哈希鍵或者有序集合鍵時, 若是用戶沒有使用 MATCH 選項, 那麼命令返回的元素數量一般和 COUNT 選項指定的同樣, 或者比 COUNT 選項指定的數量稍多一些。
  • 在迭代一個編碼爲整數集合(intset,一個只由整數值構成的小集合)、 或者編碼爲壓縮列表(ziplist,由不一樣值構成的一個小哈希或者一個小有序集合)時, 增量式迭代命令一般會無視 COUNT 選項指定的值, 在第一次迭代就將數據集包含的全部元素都返回給用戶。

並不是每次迭代都要使用相同的 COUNT 值。

用戶能夠在每次迭代中按本身的須要隨意改變 COUNT 值, 只要記得將上次迭代返回的遊標用到下次迭代裏面就能夠了。

coderknock> SCAN 0 COUNT 20
1) "0"
2)  1) "name:45"
    2) "coderknockCounter"
    3) "intKey"
    4) "addKey"
    5) "like_blog_num"
    6) "map"
    7) "str"
    8) "user:45"
    9) "40Key"
   10) "user:3"
   11) "embstrKey"
   12) "testChinese"
   13) "strHash"
   14) "39Key"
   15) "test"
   16) "user:34"
coderknock> SCAN 0 COUNT 5
1) "10"
2) 1) "name:45"
   2) "coderknockCounter"
   3) "intKey"
   4) "addKey"
   5) "like_blog_num"
coderknock> SCAN 10
1) "15"
2)  1) "map"
    2) "str"
    3) "user:45"
    4) "40Key"
    5) "user:3"
    6) "embstrKey"
    7) "testChinese"
    8) "strHash"
    9) "39Key"
   10) "test"
coderknock> SCAN 15
1) "0"
2) 1) "user:34"
MATCH 選項

KEYS 命令同樣, 增量式迭代命令也能夠經過提供一個 glob 風格的模式參數, 讓命令只返回和給定模式相匹配的元素, 這一點能夠經過在執行增量式迭代命令時, 經過給定 MATCH <pattern> 參數來實現。

如下是一個使用 MATCH 選項進行迭代的示例:

coderknock> SADD test 1 2 3 4 11 12 13 14 a ab abc abcd
(integer) 12
coderknock> SSCAN test 0 MATCH ab*
1) "3"
2) 1) "abcd"
   2) "abc"
coderknock> SSCAN test 3 MATCH ab*
1) "0"
2) 1) "ab"
# 下面的語句說明要注意 調用 cursor 時 可選項一致,否則獲取的數據沒有意義
coderknock> SSCAN test 3
1) "0"
2) 1) "ab"
   2) "12"
coderknock>

須要注意的是, 對元素的模式匹配工做是在命令從數據集中取出元素以後, 向客戶端返回元素以前的這段時間內進行的, 因此若是被迭代的數據集中只有少許元素和模式相匹配, 那麼迭代命令或許會在屢次執行中都不返回任何元素。

如下是這種狀況的一個例子:

coderknock> keys *
 1) "name:45"
 2) "addKey"
 3) "40Key"
 4) "coderknockCounter"
 5) "testChinese"
 6) "strHash"
 7) "embstrKey"
 8) "map"
 9) "like_blog_num"
10) "user:3"
11) "test"
12) "str"
13) "user:45"
14) "39Key"
15) "intKey"
16) "user:34"
# 可選項的關鍵字不能輸入錯誤,不然會報錯
coderknock> SCAN 0 MACH em
(error) ERR syntax error
coderknock> SCAN 0 MATCH em
1) "13"
2) (empty list or set)
coderknock> SCAN 13 MATCH 5
1) "0"
2) (empty list or set)

如你所見, 以上的大部分迭代都不返回任何元素。

併發執行多個迭代

在同一時間, 能夠有任意多個客戶端對同一數據集進行迭代, 客戶端每次執行迭代都須要傳入一個遊標, 並在迭代執行以後得到一個新的遊標, 而這個遊標就包含了迭代的全部狀態, 所以, 服務器無須爲迭代記錄任何狀態。

中途中止迭代

由於迭代的全部狀態都保存在遊標裏面, 而服務器無須爲迭代保存任何狀態, 因此客戶端能夠在中途中止一個迭代, 而無須對服務器進行任何通知。

即便有任意數量的迭代在中途中止, 也不會產生任何問題。

使用錯誤的遊標進行增量式迭代

使用間斷的(broken)、負數、超出範圍或者其餘非正常的遊標來執行增量式迭代並不會形成服務器崩潰, 但可能會讓命令產生未定義的行爲。

未定義行爲指的是, 增量式命令對返回值所作的保證可能會再也不爲真。

只有兩種遊標是合法的:

  1. 在開始一個新的迭代時, 遊標必須爲 0
  2. 增量式迭代命令在執行以後返回的, 用於延續(continue)迭代過程的遊標。
迭代終結的保證

增量式迭代命令所使用的算法只保證在數據集的大小有界(bounded)的狀況下, 迭代纔會中止, 換句話說, 若是被迭代數據集的大小不斷地增加的話, 增量式迭代命令可能永遠也沒法完成一次完整迭代。

從直覺上能夠看出, 當一個數據集不斷地變大時, 想要訪問這個數據集中的全部元素就須要作愈來愈多的工做, 可否結束一個迭代取決於用戶執行迭代的速度是否比數據集增加的速度更快。

返回值:

SCAN 命令、 SSCAN 命令、 HSCAN 命令和 ZSCAN 命令都返回一個包含兩個元素的 multi-bulk 回覆: 回覆的第一個元素是字符串表示的無符號 64 位整數(遊標), 回覆的第二個元素是另外一個 multi-bulk 回覆, 這個 multi-bulk 回覆包含了本次被迭代的元素。

SCAN 命令返回的每一個元素都是一個數據庫鍵。

SSCAN 命令返回的每一個元素都是一個集合成員。

HSCAN 命令返回的每一個元素都是一個鍵值對,一個鍵值對由一個鍵和一個值組成。

ZSCAN 命令返回的每一個元素都是一個有序集合元素,一個有序集合元素由一個成員(member)和一個分值(score)組成。

Redis 中的 7 種數據結構:

string(字符串)

字符串是一種最基本的Redis值類型。key 都是字符串類型,其餘幾種數據結構都是在字符串類型的基礎上構建的。Redis字符串是二進制安全的,這意味着一個Redis字符串能包含任意類型的數據,例如: 一張JPEG格式的圖片或者一個序列化的 Ruby 對象等。

一個字符串類型的值最多能存儲 512M 字節的內容。

字符串類型的值實際上能夠如下幾種:

  1. 字符串(包括 JSON、XML 等)
  2. 數字(整數、浮點數)
  3. 二進制(圖片、音頻、視頻)

你能夠用Redis字符串作許多有趣的事,例如你能夠:

  • 利用 INCR 命令簇(INCR DECR INCRBY)來把字符串看成原子計數器使用。
  • 使用 APPEND 命令在字符串後添加內容。
  • 將字符串做爲 GETRANGESETRANGE 的隨機訪問向量。
  • 在小空間裏編碼大量數據,或者使用 GETBITSETBIT 建立一個Redis支持的 Bloom 過濾器。

本系列教程後續會有 字符串 專題會對經常使用命令以及場景進行介紹

list(列表)

Redis 列表是簡單的字符串列表,按照插入順序排序。 你能夠添加一個元素到列表的頭部(左邊)或者尾部(右邊)。

LPUSH 命令插入一個新元素到列表頭部,而 RPUSH 命令 插入一個新元素到列表的尾部。當 對一個空 key 執行其中某個命令時,將會建立一個新表。 相似的,若是一個操做要清空列表,那麼 key 會從對應的 key 空間刪除。這是個很是便利的語義, 由於若是使用一個不存在的 key 做爲參數,全部的列表命令都會像在對一個空表操做同樣。

一個列表最多能夠包含2 ^ 32 - 1個元素(4294967295,每一個表超過40億個元素)。

從時間複雜度的角度來看,Redis 列表主要的特性就是支持時間常數的 插入和靠近頭尾部元素的刪除,即便是須要插入上百萬的條目。 訪問列表兩端的元素是很是快的,但若是你試着訪問一個很是大 的列表的中間元素仍然是十分慢的,由於那是一個時間複雜度爲 O(N) 的操做。

你能夠用 Redis 列表作許多有趣的事,例如你能夠:

  • 在社交網絡中創建一個時間線模型,使用 LPUSH 去添加新的元素到用戶時間線中,使用 LRANGE 去檢索一些最近插入的條目。
  • 你能夠同時使用 LPUSHLTRIM 去建立一個永遠不會超過指定元素數目的列表並同時記住最後的 N 個元素。
  • 列表能夠用來看成消息傳遞的基元(primitive),例如,衆所周知的用來建立後臺任務的 Resque Ruby 庫。
  • 你可使用列表作更多事,這個數據類型支持許多命令,包括像 BLPOP 這樣的阻塞命令。請查看全部可用的列表操做命令獲取更多的信息。

本系列教程後續會有 列表 專題會對經常使用命令以及場景進行介紹

set(集合)

Redis 集合是一個無序的字符串合集。你能夠以O(1) 的時間複雜度(不管集合中有多少元素時間複雜度都爲常量)完成 添加,刪除以及測試元素是否存在的操做。

Redis 集合有着不容許相同成員存在的優秀特性。向集合中屢次添加同一元素,在集合中最終只會存在一個此元素。實際上這就意味着,在添加元素前,你並不須要事先進行檢驗此元素是否已經存在的操做。

一個 Redis 列表十分有趣的事是,它們支持一些服務端的命令從現有的集合出發去進行集合運算。 因此你能夠在很短的時間內完成合並(union),求交(intersection), 找出不一樣元素的操做。

一個集合最多能夠包含2 ^ 32 - 1個元素(4294967295,每一個集合超過40億個元素)。

你能夠用 Redis 集合作不少有趣的事,例如你能夠:

  • 用集合跟蹤一個獨特的事。想要知道全部訪問某個博客文章的獨立IP?只要每次都用 來處理一個頁面訪問。那麼你能夠確定重複的IP是不會插入的。
  • Redis 集合能很好的表示關係。你能夠建立一個 tagging 系統,而後用集合來表明單個 tag 。接下來你能夠用SADD命令把全部擁有 tag 的對象的全部 ID 添加進集合,這樣來表示這個特定的 tag 。若是你想要同時有3個不一樣 tag 的全部對象的全部 ID ,那麼你須要使用 SINTER
  • 使用 SPOP 或者 SRANDMEMBER 命令隨機地獲取元素。

本系列教程後續會有 集合 專題會對經常使用命令以及場景進行介紹

zset(有序集合)

Redis 有序集合和 Redis 集合相似,是不包含 相同字符串的合集。它們的差異是,每一個有序集合 的成員都關聯着一個評分,這個評分用於把有序集 閤中的成員按最低分到最高分排列。

使用有序集合,你能夠很是快地(O(log(N)))完成添加,刪除和更新元素的操做。 由於元素是在插入時就排好序的,因此很快地經過評分(score)或者 位次(position)得到一個範圍的元素。 訪問有序集合的中間元素一樣也是很是快的,所以你可使用有序集合做爲一個沒用重複成員的智能列表。 在這個列表中, 你能夠輕易地訪問任何你須要的東西: 有序的元素,快速的存在性測試,快速訪問集合中間元素!

簡而言之,使用有序集合你能夠很好地完成 不少在其餘數據庫中難以實現的任務。

使用有序集合你能夠:

  • 在一個巨型在線遊戲中創建一個排行榜,每當有新的記錄產生時,使用 ZADD 來更新它。你能夠用 ZRANGE 輕鬆地獲取排名靠前的用戶, 你也能夠提供一個用戶名,而後用 ZRANK 取他在排行榜中的名次。 同時使用 ZRANKZRANGE 你能夠得到與指定用戶有相同分數的用戶名單。 全部這些操做都很是迅速。
  • 有序集合一般用來索引存儲在 Redis 中的數據。 例如:若是你有不少的 hash來表示用戶,那麼你可使用一個有序集合,這個集合的年齡字段用來看成評分,用戶 ID 看成值。用 ZRANGEBYSCORE 能夠簡單快速地檢索到給定年齡段的全部用戶。

有序集合或許是最高級的 Redis 數據類型,本系列教程後續會有 有序集合 專題會對經常使用命令以及場景進行介紹

hash(哈希)

Redis Hashes 是字符串字段和字符串值之間的映射,因此它們是完美的表示對象的數據類型。

一個擁有少許(100個左右)字段的 hash 須要 不多的空間來存儲,因此你能夠在一個小型的 Redis 實例中存儲上百萬的對象。

儘管 Hashes 主要用來表示對象,但它們也可以存儲許多元素,因此你也能夠用 Hashes 來完成許多其餘的任務。

一個 hash 最多能夠包含 2 ^ 32 - 1 個key-value鍵值對(超過40億)。
本系列教程後續會有 哈希 專題會對經常使用命令以及場景進行介紹

Bitmaps 和 HyperLogLogs

Bit arrays (或者說 simply bitmaps): 經過特殊的命令,你能夠將 String 值看成一系列 bits 處理:能夠設置和清除單獨的 bits,數出全部設爲 1 的 bits 的數量,找到最前的被設爲 1 或 0 的 bit,等等。

HyperLogLogs: 這是被用於估計一個 set 中元素數量的機率性的數據結構。

Redis 一樣支持 Bitmaps 和 HyperLogLogs 數據類型,其實是基於字符串的基本類型的數據類型,但有本身的語義。

內部編碼

每種數據結構都有本身底層的內部編碼實現,並且是多種實現,Redis 會在合適的場景選擇合適的內部編碼。這樣設計的好處:

Redis 經常使用數據結構

  1. 能夠改進內部編碼,而對外的數據結構和命令不會受到影響,利於版本的兼容,性能的提升
  2. 多種內部編碼實現能夠在不一樣場景下發揮各自的優點

能夠經過 object encoding 命令查詢內部編碼

Redis 的單線程架構

單線程架構

Redis 是使用了 單線程架構I/O多路複用模型 來實現高性能的內存數據庫服務。

Redis 客戶端交互

Redis 是單線程來處理命令的,因此命令到達 Redis 後並不會當即執行,而是進入隊列以後逐個執行。對於差很少同時到達的命令執行的順序是沒法肯定的。

單線程還保持高性能的祕密

  1. 純內存訪問。Redis 將全部的數據放在內存中,內存的響應時長大約爲 100 納秒,這是 Redis 能夠達到每秒萬級別訪問的基礎。
  2. 非阻塞 I/O。Redis 使用 epoll 做爲 I/O 多路複用技術的實現;Redis 自身的事件處理模型將 epoll 中的鏈接、讀寫、關閉都轉爲事件,從而避免了在網絡 I/O 上時間的浪費。

Redis 使用 IO 多路複用 和 自身實際模型示意

  1. 避免了線程切換和競態產生的消耗。

單線程的優勢

  1. 單線程能夠簡化數據結構和算法的實現
  2. 單線程避免了線程切換和競態產生的消耗。對於服務端開發來講,鎖和線程切換一般是性能殺手。

單線程的缺點

因爲命令是逐個執行的,若是某個命令執行時間過長,則會形成其餘命令的阻塞。因此 Redis 是面向快速執行場景的數據庫。

Redis 使用注意事項

  1. 當進行多個 key 操做時,儘量使用批量命令,如:MSET、MGET等
  2. Redis 中只有庫的概念以及鍵的概念,因此在設計鍵名時要注意規範,推薦使用:
業務名:對象名:id

的格式來聲明鍵,鍵名應該儘量簡短。

相關文章
相關標籤/搜索