鍍金池/ 教程/ 大數(shù)據(jù)/ 從入門到精通(上)
使用 Redis 實(shí)現(xiàn) Twitter(上)
集群(下)
使用 Redis 實(shí)現(xiàn) Twitter(下)
使用 Redis 作為 LRU 緩存
高可用(上)
高可用客戶端指引
集群(中)
高可用(下)
持久化
Redis 介紹
集中插入
集群(上)
從入門到精通(上)
從入門到精通(下)
從入門到精通(中)
分片
數(shù)據(jù)類型初探
復(fù)制

從入門到精通(上)

Redis 不是一個(gè)無(wú)格式 (plain) 的鍵值存儲(chǔ),而是一個(gè)支持各種不同類型值的數(shù)據(jù)結(jié)構(gòu)服務(wù)器。這就是說(shuō),傳統(tǒng)鍵值存儲(chǔ)是關(guān)聯(lián)字符串值到字符串鍵,但是 Redis 的值不僅僅局限于簡(jiǎn)單字符串,還可以持有更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。下面列的是 Redis 支持的所有數(shù)據(jù)結(jié)構(gòu),后面將逐一介紹:

  • 二進(jìn)制安全 (binary-safe) 的字符串。
  • 列表:按照插入順序排序的字符串元素 (element) 的集合 (collection)。通常是鏈表。
  • 集合:唯一的,無(wú)序的字符串元素集合。
  • 有序集合:和集合類似,但是每個(gè)字符串元素關(guān)聯(lián)了一個(gè)稱為分?jǐn)?shù) (score) 的浮點(diǎn)數(shù)。元素總是按照分?jǐn)?shù)排序,所以可以檢索一個(gè)范圍的元素 (例如,給我前 10,或者后 10 個(gè)元素)。
  • 哈希:由字段 (field) 及其關(guān)聯(lián)的值組成的映射。字段和值都是字符串類型。這非常類似于 Ruby 或 Python 中的哈希 / 散列。
  • 位數(shù)組 (位圖):使用特殊的命令,把字符串當(dāng)做位數(shù)組來(lái)處理:你可以設(shè)置或者清除單個(gè)位值,統(tǒng)計(jì)全部置位為 1 的位個(gè)數(shù),尋找第一個(gè)復(fù)位或者置位的位,等等。
  • 超重對(duì)數(shù) (HyperLogLog):這是一個(gè)用于估算集合的基數(shù) (cardinality,也稱勢(shì),譯者注) 的概率性數(shù)據(jù)結(jié)構(gòu)。不要害怕,它比看起來(lái)要簡(jiǎn)單,稍后為你揭曉。

理解這些數(shù)據(jù)結(jié)構(gòu)是如何工作的,以及從命令參考手冊(cè)中選擇什么命令來(lái)解決實(shí)際問(wèn)題,并不總是一件繁瑣的事情,本文檔就是學(xué)習(xí) Redis 數(shù)據(jù)結(jié)構(gòu)及其最常用模式的速成班。

后面的所有例子我們都是使用 redis-cli 工具,這是一個(gè)簡(jiǎn)單而又方便的命令行工具,用于發(fā)送命令給 Redis 服務(wù)器。

Redis 鍵 (Keys)

Redis 鍵是二進(jìn)制安全的,這意味著你可以使用任何二進(jìn)制序列作為鍵,從像”foo” 這樣的字符串到一個(gè) JPEG 文件的內(nèi)容。空字符串也是合法的鍵。

關(guān)于鍵的其他一些規(guī)則:

  • 不要使用太長(zhǎng)的鍵,例如,不要使用一個(gè) 1024 字節(jié)的鍵,不僅是因?yàn)閮?nèi)存占用,而且在數(shù)據(jù)集中查找鍵時(shí)需要多次耗時(shí)的鍵比較。即使手頭需要匹配一個(gè)很大值的存在性,對(duì)其進(jìn)行哈希 (例如使用 SHA1) 是個(gè)不錯(cuò)的主意,尤其是從內(nèi)存和帶寬的角度。
  • 不要使用太短的鍵。用”u1000flw” 取代”user:1000:followers” 作為鍵并沒(méi)有什么實(shí)際意義,后者更具有可讀性,相對(duì)于鍵對(duì)象本身以及值對(duì)象來(lái)說(shuō),增加的空間微乎其微。然而不可否認(rèn),短的鍵會(huì)消耗少的內(nèi)存,你的任務(wù)就是要找到平衡點(diǎn)。
  • 堅(jiān)持一種模式 (schema)。例如,”object-type:id” 就不錯(cuò),就像”user:1000”。點(diǎn)或者橫線常用來(lái)連接多單詞字段,如”comment:1234:reply.to”,或者”comment:1234:reply-to”。
  • 鍵的最大大小是 512MB。

Redis 字符串 (Strings)

Redis 字符串是可以關(guān)聯(lián)給 redis 鍵的最簡(jiǎn)單值類型。字符串是 Memcached 的唯一數(shù)據(jù)類型,所以新手使用起來(lái)也是很自然的。

由于 Redis 的鍵也是字符串,當(dāng)我們使用字符串作為值的時(shí)候,我們是將一個(gè)字符串映射給另一個(gè)字符串。字符串?dāng)?shù)據(jù)類型適用于很多場(chǎng)景,例如,緩存 HTML 片段或者頁(yè)面。

讓我們用 redis-cli 來(lái)玩玩字符串類型 (接下來(lái)的例子都是使用 redis-cli)。

> set mykey somevalue  
OK  
> get mykey  
"somevalue"  

你可以看到,我們使用 SET 和 GET 命令設(shè)置和檢索字符串值。注意,如果鍵已經(jīng)存在,SET 會(huì)替換掉該鍵已經(jīng)存在的值,哪怕這個(gè)鍵關(guān)聯(lián)的是一個(gè)非字符串類型的值。SET 執(zhí)行的是賦值操作。

值可以是任何類型的字符串 (包括二進(jìn)制數(shù)據(jù)),例如,你可以存儲(chǔ)一個(gè) JPEG 圖像。值不能大于 512MB。

SET 命令還有一些以額外的參數(shù)形式提供有意思的選項(xiàng)。例如,如果我要求如果鍵存在 (或剛好相反) 則執(zhí)行失敗,也就是說(shuō)健存在才成功:

> set mykey newval nx  
(nil)  
> set mykey newval xx  
OK  

盡管字符串是 Redis 最基本的值類型,你仍可以執(zhí)行很多有趣的操作。例如,原子性增長(zhǎng):

> set counter 100  
OK  
> incr counter  
(integer) 101  
> incr counter  
(integer) 102  
> incrby counter 50  
(integer) 152  

INCR 命令將字符串值解析為整數(shù),并增加一,最后賦值后作為新值。還有一些類似的命令 INCRBY,DECR 和 DECRBY。它們以略微不同的方式執(zhí)行,但其內(nèi)部都是一樣的命令。

為什么說(shuō) INCR 命令是原子的?因?yàn)榧词苟鄠€(gè) 客戶端對(duì)同一個(gè)鍵發(fā)送 INCR 命令也不會(huì)造成競(jìng)爭(zhēng)條件 (race condition)。例如,一定不會(huì)發(fā)生客戶端 1 和客戶端 2 同時(shí)讀到”10”,都增加到 11,然后設(shè)置新值為 11。最后的結(jié)果將會(huì)一直是 12,讀 - 增加 - 寫操作在執(zhí)行時(shí),其他客戶端此時(shí)不會(huì)執(zhí)行相關(guān)命令。

有許多操作字符串的命令。例如,GETSET 命令給鍵設(shè)置一個(gè)新值,同時(shí)返回舊值。你可以使用這個(gè)命令,例如,如果你有一個(gè)系統(tǒng),每當(dāng)收到一個(gè)訪問(wèn)請(qǐng)求就使用 INRC 來(lái)增加一個(gè)鍵。你想每隔一個(gè)小時(shí)收集一次這個(gè)信息,而不想漏掉任何一個(gè)增長(zhǎng)。你可以使用 GETSET,將新值賦值為 0,人后讀取其舊值。

在一個(gè)命令中一次設(shè)置或者檢索多個(gè)鍵有利于減少延遲。為此有了 MSET 和 MGET 命令:

> mset a 10 b 20 c 30  
OK  
> mget a b c  
1) "10"  
2) "20"  
3) "30"  

當(dāng)使用 MSET 時(shí),Redis 返回一個(gè)值數(shù)組。

改變和查詢鍵空間 (key space)

有一些命令并不定義在特定的類型上,但是對(duì)鍵空間的交互很有用,因此他們能作用在任意鍵上。

例如,EXISTS 命令返回 1 或者 0,來(lái)表示鍵在數(shù)據(jù)庫(kù)中是否存在。另外,DEL 命令刪除鍵及其關(guān)聯(lián)的值,無(wú)論值是什么。

> set mykey hello  
OK  
> exists mykey  
(integer) 1  
> del mykey  
(integer) 1  
> exists mykey  
(integer) 0  

從上面的例子中我們還可以看到,DEL 命令本身也會(huì)返回 1 或者 0,無(wú)論鍵是(存在)否(不存在)刪除。

有許多鍵空間相關(guān)的命令,但是上面兩個(gè)命令與 TYPE 命令關(guān)系緊密,TYPE 命令返回某個(gè)鍵的值的類型。

> set mykey x  
OK  
> type mykey  
string  
> del mykey  
(integer) 1  
> type mykey  
none  

Redis 過(guò)期 (expires):有限生存時(shí)間的鍵

在我們繼續(xù)更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)之前,我們先拋出一個(gè)與類型無(wú)關(guān)的特性, 稱為 Redis 過(guò)期 。你可以給鍵設(shè)置超時(shí),也就是一個(gè)有限的生存時(shí)間。當(dāng)生存時(shí)間到了,鍵就會(huì)自動(dòng)被銷毀,就像用戶調(diào)用 DEL 命令一樣。

快速過(guò)一下 Redis 過(guò)期的信息:

  • 過(guò)期時(shí)間可以設(shè)置為秒或者毫秒精度。
  • 過(guò)期時(shí)間分辨率總是 1 毫秒。
  • 過(guò)期信息被復(fù)制和持久化到磁盤,當(dāng) Redis 停止時(shí)時(shí)間仍然在計(jì)算 (也就是說(shuō) Redis 保存了過(guò)期時(shí)間)。

設(shè)置過(guò)期非常簡(jiǎn)單:

> set key some-value  
OK  
> expire key 5  
(integer) 1  
> get key (immediately)  
"some-value"  
> get key (after some time)  
(nil)  

鍵在兩次 GET 調(diào)用期間消失了,因?yàn)榈诙握{(diào)用推遲了超過(guò) 5 秒。在上面的例子中,我們使用 EXPIRE 命令設(shè)置過(guò)期 (也可以為一個(gè)已經(jīng)設(shè)置過(guò)期時(shí)間的鍵設(shè)置不同的過(guò)期時(shí)間,就像 PERSIST 命令可以刪除過(guò)期時(shí)間使鍵永遠(yuǎn)存在)。當(dāng)然我們也可以使用其他 Redis 命令來(lái)創(chuàng)建帶過(guò)期時(shí)間的鍵。例如使用 SET 選項(xiàng):

> set key 100 ex 10  
OK  
> ttl key  
(integer) 9  

上面的例子中設(shè)置 10 秒過(guò)期的鍵,值為字符串 100。然后使用 TTL 命令檢查鍵的生存剩余時(shí)間。

為了使用毫秒來(lái)設(shè)置和檢查過(guò)期,請(qǐng)查看 PEXPIRE 和 PTTL 命令,以及 SET 命令的全部選項(xiàng)。