《Redis分享之你不可不知的Redis常用命令》要點(diǎn):
本文介紹了Redis分享之你不可不知的Redis常用命令,希望對(duì)您有用。如果有疑問,可以聯(lián)系我們。
本文對(duì)Redis最常用的一些命令進(jìn)行了介紹,其中包括各種不同數(shù)據(jù)類型的常用命令、PUBLISH命令和SUBSCRIBE命令、SORT命令、兩個(gè)事務(wù)命令MULTI和EXEC,以及與過(guò)期時(shí)間有關(guān)的幾個(gè)命令.
本文的第一個(gè)目標(biāo)是讓讀者知道—Redis為每種結(jié)構(gòu)都提供了大量的處理命令,本章只展示了其中最重要的70多個(gè)命令,其余的命令可以在http://redis.io/commands看到.
本文的第二個(gè)目標(biāo)是讓讀者知道—本書并非為每個(gè)問題都提供了完美的答案.通過(guò)在練習(xí)里面對(duì)第1章和第2章展示的示例進(jìn)行回顧(練習(xí)的答案在本書附帶的源碼里面),本書向讀者提供了一個(gè)機(jī)會(huì),讓讀者把已經(jīng)不錯(cuò)的代碼變得更好,或者變得更適合于讀者自己的問題.
在本文沒有介紹到的命令當(dāng)中,有一大部分都是與配置相關(guān)的,想學(xué)習(xí)更全面的Redis知識(shí),請(qǐng)看《Redis實(shí)戰(zhàn)》,這本書的下一章將向讀者介紹如何配置Redis以確保數(shù)據(jù)安全,以及如何確保Redis擁有良好的性能.
3.1 字符串
本書在第1章和第2章曾經(jīng)說(shuō)過(guò),Redis的字符串就是一個(gè)由字節(jié)組成的序列,它們和很多編程語(yǔ)言里面的字符串沒有什么顯著的不同,跟C或者C++風(fēng)格的字符數(shù)組也相去不遠(yuǎn).在Redis里面,字符串可以存儲(chǔ)以下3種類型的值.
字節(jié)串(byte string).
整數(shù).
浮點(diǎn)數(shù).
用戶可以通過(guò)給定一個(gè)任意的數(shù)值,對(duì)存儲(chǔ)著整數(shù)或者浮點(diǎn)數(shù)的字符串執(zhí)行自增(increment)或者自減(decrement)操作,在有需要的時(shí)候,Redis還會(huì)將整數(shù)轉(zhuǎn)換成浮點(diǎn)數(shù).整數(shù)的取值范圍和系統(tǒng)的長(zhǎng)整數(shù)(long integer)的取值范圍相同(在32位系統(tǒng)上,整數(shù)就是32位有符號(hào)整數(shù),在64位系統(tǒng)上,整數(shù)就是64位有符號(hào)整數(shù)),而浮點(diǎn)數(shù)的取值范圍和精度則與IEEE 754標(biāo)準(zhǔn)的雙精度浮點(diǎn)數(shù)(double)相同.Redis明確地區(qū)分字節(jié)串、整數(shù)和浮點(diǎn)數(shù)的做法是一種優(yōu)勢(shì),比起只能夠存儲(chǔ)字節(jié)串的做法,Redis的做法在數(shù)據(jù)表現(xiàn)方面具有更大的靈活性.
本節(jié)將對(duì)Redis里面最簡(jiǎn)單的結(jié)構(gòu)—字符串進(jìn)行討論,介紹基本的數(shù)值自增和自減操作,以及二進(jìn)制位(bit)和子串(substring)處理命令,讀者可能會(huì)驚訝地發(fā)現(xiàn),Redis里面最簡(jiǎn)單的結(jié)構(gòu)居然也有如此強(qiáng)大的作用.
表3-1展示了對(duì)Redis字符串執(zhí)行自增和自減操作的命令.
表3-1 Redis中的自增命令和自減命令
命令 | 用例和描述 |
---|---|
INCR | INCR key-name—將鍵存儲(chǔ)的值加上1 |
DECR | DECR key-name—將鍵存儲(chǔ)的值減去1 |
INCRBY | INCRBY key-name amount—將鍵存儲(chǔ)的值加上整數(shù)amount |
DECRBY | DECRBY key-name amount—將鍵存儲(chǔ)的值減去整數(shù)amount |
INCRBYFLOAT | INCRBYFLOAT key-name amount—將鍵存儲(chǔ)的值加上浮點(diǎn)數(shù)amount,這個(gè)命令在Redis 2.6或以上的版本可用 |
當(dāng)用戶將一個(gè)值存儲(chǔ)到Redis字符串里面的時(shí)候,如果這個(gè)值可以被解釋(interpret)為十進(jìn)制整數(shù)或者浮點(diǎn)數(shù),那么Redis會(huì)察覺到這一點(diǎn),并允許用戶對(duì)這個(gè)字符串執(zhí)行各種INCR*和DECR*操作.如果用戶對(duì)一個(gè)不存在的鍵或者一個(gè)保存了空串的鍵執(zhí)行自增或者自減操作,那么Redis在執(zhí)行操作時(shí)會(huì)將這個(gè)鍵的值當(dāng)作是0來(lái)處理.如果用戶嘗試對(duì)一個(gè)值無(wú)法被解釋為整數(shù)或者浮點(diǎn)數(shù)的字符串鍵執(zhí)行自增或者自減操作,那么Redis將向用戶返回一個(gè)錯(cuò)誤.代碼清單3-1展示了對(duì)字符串執(zhí)行自增操作和自減操作的一些例子.
代碼清單3-1 這個(gè)交互示例展示了Redis的INCR操作和DECR操作
在讀完本書其他章節(jié)之后,讀者可能會(huì)發(fā)現(xiàn)本書只調(diào)用了 incr(),這是因?yàn)?Python的Redis庫(kù)在內(nèi)部使用INCRBY命令來(lái)實(shí)現(xiàn)incr()方法,并且這個(gè)方法的第二個(gè)參數(shù)是可選的:如果用戶沒有為這個(gè)可選參數(shù)設(shè)置值,那么這個(gè)參數(shù)就會(huì)使用默認(rèn)值1.在編寫本書的時(shí)候,Python的Redis客戶端庫(kù)支持Redis 2.6的所有命令,這個(gè)庫(kù)通過(guò)incrbyfloat()方法來(lái)實(shí)現(xiàn)INCRBYFLOAT命令,并且incrbyfloat()方法也有類似于incr()方法的可選參數(shù)特性.
除了自增操作和自減操作之外,Redis還擁有對(duì)字節(jié)串的其中一部分內(nèi)容進(jìn)行讀取或者寫入的操作(這些操作也可以用于整數(shù)或者浮點(diǎn)數(shù),但這種用法并不常見),本書在第9章將展示如何使用這些操作來(lái)高效地將結(jié)構(gòu)化數(shù)據(jù)打包(pack)存儲(chǔ)到字符串鍵里面.表3-2展示了用來(lái)處理字符串子串和二進(jìn)制位的命令.
表3-2 供Redis處理子串和二進(jìn)制位的命令
命令 | 用例和描述 |
---|---|
APPEND | APPEND key-name value—將值value追加到給定鍵key-name當(dāng)前存儲(chǔ)的值的末尾 |
GETRANGE | GETRANGE key-name start end—獲取一個(gè)由偏移量start至偏移量end范圍內(nèi)所有字符組成的子串,包括start和end在內(nèi) |
SETRANGE | SETRANGE key-name offset value—將從start偏移量開始的子串設(shè)置為給定值 |
GETBIT | GETBIT key-name offset—將字節(jié)串看作是二進(jìn)制位串(bit string),并返回位串中偏移量為offset的二進(jìn)制位的值 |
SETBIT | SETBIT key-name offset value—將字節(jié)串看作是二進(jìn)制位串,并將位串中偏移量為offset的二進(jìn)制位的值設(shè)置為value |
BITCOUNT | BITCOUNT key-name [start end]—統(tǒng)計(jì)二進(jìn)制位串里面值為1的二進(jìn)制位的數(shù)量,如果給定了可選的start偏移量和end偏移量,那么只對(duì)偏移量指定范圍內(nèi)的二進(jìn)制位進(jìn)行統(tǒng)計(jì) |
BITOP | BITOP operation dest-key key-name [key-name …]—對(duì)一個(gè)或多個(gè)二進(jìn)制位串執(zhí)行包括并(AND)、或(OR)、異或(XOR)、非(NOT)在內(nèi)的任意一種按位運(yùn)算操作(bitwise operation),并將計(jì)算得出的結(jié)果保存在dest-key鍵里面 |
GETRANGE和SUBSTR Redis現(xiàn)在的GETRANGE命令是由以前的SUBSTR命令改名而來(lái)的,因此,Python客戶端至今仍然可以使用substr()方法來(lái)獲取子串,但如果讀者使用的是2.6或以上版本的Redis,那么最好還是使用getrange()方法來(lái)獲取子串.
在使用SETRANGE或者SETBIT命令對(duì)字符串進(jìn)行寫入的時(shí)候,如果字符串當(dāng)前的長(zhǎng)度不能滿足寫入的要求,那么Redis會(huì)自動(dòng)地使用空字節(jié)(null)來(lái)將字符串?dāng)U展至所需的長(zhǎng)度,然后才執(zhí)行寫入或者更新操作.在使用GETRANGE讀取字符串的時(shí)候,超出字符串末尾的數(shù)據(jù)會(huì)被視為是空串,而在使用GETBIT讀取二進(jìn)制位串的時(shí)候,超出字符串末尾的二進(jìn)制位會(huì)被視為是0.代碼清單3-2展示了一些字符串處理命令的使用示例.
代碼清單3-2 這個(gè)交互示例展示了Redis的子串操作和二進(jìn)制位操作
很多鍵值數(shù)據(jù)庫(kù)只能將數(shù)據(jù)存儲(chǔ)為普通的字符串,并且不提供任何字符串處理操作,有一些鍵值數(shù)據(jù)庫(kù)允許用戶將字節(jié)追加到字符串的前面或者后面,但是卻沒辦法像Redis一樣對(duì)字符串的子串進(jìn)行讀寫.從很多方面來(lái)講,即使Redis只支持字符串結(jié)構(gòu),并且只支持本節(jié)列出的字符串處理命令,Redis也比很多別的數(shù)據(jù)庫(kù)要強(qiáng)大得多;通過(guò)使用子串操作和二進(jìn)制位操作,配合WATCH命令、MULTI命令和EXEC命令(本書的3.7.2節(jié)將對(duì)這3個(gè)命令進(jìn)行初步的介紹,并在第4章對(duì)它們進(jìn)行更深入的講解),用戶甚至可以自己動(dòng)手去構(gòu)建任何他們想要的數(shù)據(jù)結(jié)構(gòu).第9章將介紹如何使用字符串去存儲(chǔ)一種簡(jiǎn)單的映射,這種映射可以在某些情況下節(jié)省大量?jī)?nèi)存.
只要花些心思,我們甚至可以將字符串當(dāng)作列表來(lái)使用,但這種做法能夠執(zhí)行的列表操作并不多,更好的辦法是直接使用下一節(jié)介紹的列表結(jié)構(gòu),Redis為這種結(jié)構(gòu)提供了豐富的列表操作命令.
3.2 列表
在第1章曾經(jīng)介紹過(guò),Redis的列表允許用戶從序列的兩端推入或者彈出元素,獲取列表元素,以及執(zhí)行各種常見的列表操作.除此之外,列表還可以用來(lái)存儲(chǔ)任務(wù)信息、最近瀏覽過(guò)的文章或者常用聯(lián)系人信息.
本節(jié)將對(duì)列表這個(gè)由多個(gè)字符串值組成的有序序列結(jié)構(gòu)進(jìn)行介紹,并展示一些最常用的列表處理命令,閱讀本節(jié)可以讓讀者學(xué)會(huì)如何使用這些命令來(lái)處理列表.表3-3展示了其中一部分最常用的列表命令.
表3-3 一些常用的列表命令
命令 | 用例和描述 |
---|---|
RPUSH | RPUSH key-name value [value …]—將一個(gè)或多個(gè)值推入列表的右端 |
LPUSH | LPUSH key-name value [value …]—將一個(gè)或多個(gè)值推入列表的左端 |
RPOP | RPOP key-name—移除并返回列表最右端的元素 |
LPOP | LPOP key-name—移除并返回列表最左端的元素 |
LINDEX | LINDEX key-name offset—返回列表中偏移量為offset的元素 |
LRANGE | LRANGE key-name start end—返回列表從start偏移量到end偏移量范圍內(nèi)的所有元素,其中偏移量為start和偏移量為end的元素也會(huì)包含在被返回的元素之內(nèi) |
LTRIM | LTRIM key-name start end—對(duì)列表進(jìn)行修剪,只保留從start偏移量到end偏移量范圍內(nèi)的元素,其中偏移量為start和偏移量為end的元素也會(huì)被保留 |
因?yàn)楸緯诘?章已經(jīng)對(duì)列表的幾個(gè)推入和彈出操作進(jìn)行了簡(jiǎn)單的介紹,所以讀者應(yīng)該不會(huì)對(duì)上面列出的推入和彈出操作感到陌生,代碼清單3-3展示了這些操作的用法.
代碼清單3-3 這個(gè)交互示例展示了Redis列表的推入操作和彈出操作
這個(gè)示例里面第一次用到了LTRIM命令,組合使用LTRIM和LRANGE可以構(gòu)建出一個(gè)在功能上類似于LPOP或者RPOP的操作,它能夠一次返回并彈出多個(gè)元素.本章稍后將會(huì)介紹原子地執(zhí)行多個(gè)命令的方法,而更高級(jí)的Redis事務(wù)特性則會(huì)在第4章介紹.
有幾個(gè)列表命令可以將元素從一個(gè)列表移動(dòng)到另一個(gè)列表,或者阻塞(block)執(zhí)行命令的客戶端直到有其他客戶端給列表添加元素為止,這些命令在第1章都沒有介紹過(guò),表3-4列出了這些阻塞彈出命令和元素移動(dòng)命令.
表3-4 阻塞式的列表彈出命令以及在列表之間移動(dòng)元素的命令
命令 | 用例和描述 |
---|---|
BLPOP | BLPOP key-name [key-name …] timeout—從第一個(gè)非空列表中彈出位于最左端的元素,或者在timeout秒之內(nèi)阻塞并等待可彈出的元素出現(xiàn) |
BRPOP | BRPOP key-name [key-name …] timeout—從第一個(gè)非空列表中彈出位于最右端的元素,或者在timeout秒之內(nèi)阻塞并等待可彈出的元素出現(xiàn) |
RPOPLPUSH | RPOPLPUSH source-key dest-key—從source-key列表中彈出位于最右端的元素,然后將這個(gè)元素推入dest-key列表的最左端,并向用戶返回這個(gè)元素 |
BRPOPLPUSH | BRPOPLPUSH source-key dest-key timeout—從source-key列表中彈出位于最右端的元素,然后將這個(gè)元素推入dest-key列表的最左端,并向用戶返回這個(gè)元素;如果source-key為空,那么在timeout秒之內(nèi)阻塞并等待可彈出的元素出現(xiàn) |
在第6章討論隊(duì)列時(shí),這組命令將會(huì)非常有用.代碼清單3-4展示了幾個(gè)使用BRPOPLPUSH移動(dòng)列表元素的例子以及使用BLPOP從列表里面彈出多個(gè)元素的例子.
代碼清單3-4 這個(gè)交互示例展示了Redis列表的阻塞彈出命令以及元素移動(dòng)命令
對(duì)于阻塞彈出命令和彈出并推入命令,最常見的用例就是消息傳遞(messaging)和任務(wù)隊(duì)列(task queue),本書將在第6章對(duì)這兩個(gè)主題進(jìn)行介紹.
練習(xí):通過(guò)列表來(lái)降低內(nèi)存占用 在2.1節(jié)和2.5節(jié)中,我們使用了有序集合來(lái)記錄用戶最近瀏覽過(guò)的商品,并把用戶瀏覽這些商品時(shí)的時(shí)間戳設(shè)置為分值,從而使得程序可以在清理舊會(huì)話的過(guò)程中或是執(zhí)行完購(gòu)買操作之后,進(jìn)行相應(yīng)的數(shù)據(jù)分析.但由于保存時(shí)間戳需要占用相應(yīng)的空間,所以如果分析操作并不需要用到時(shí)間戳的話,那么就沒有必要使用有序集合來(lái)保存用戶最近瀏覽過(guò)的商品了.為此,請(qǐng)?jiān)诒WC語(yǔ)義不變的情況下,將update_token()函數(shù)里面使用的有序集合替換成列表.提示:如果讀者在解答這個(gè)問題時(shí)遇上困難的話,可以到6.1.1節(jié)中找找靈感.
列表的一個(gè)主要優(yōu)點(diǎn)在于它可以包含多個(gè)字符串值,這使得用戶可以將數(shù)據(jù)集中在同一個(gè)地方.Redis的集合也提供了與列表類似的特性,但集合只能保存各不相同的元素.接下來(lái)的一節(jié)中就讓我們來(lái)看看不能保存相同元素的集合都能做些什么.
3.3 集合
Redis的集合以無(wú)序的方式來(lái)存儲(chǔ)多個(gè)各不相同的元素,用戶可以快速地對(duì)集合執(zhí)行添加元素操作、移除元素操作以及檢查一個(gè)元素是否存在于集合里.第1章曾經(jīng)對(duì)集合進(jìn)行過(guò)簡(jiǎn)單的介紹,并在構(gòu)建文章投票網(wǎng)站時(shí),使用集合記錄文章已投票用戶名單以及群組屬下的所有文章.
本節(jié)將對(duì)最常用的集合命令進(jìn)行介紹,包括插入命令、移除命令、將元素從一個(gè)集合移動(dòng)到另一個(gè)集合的命令,以及對(duì)多個(gè)集合執(zhí)行交集運(yùn)算、并集運(yùn)算和差集運(yùn)算的命令.閱讀本節(jié)也有助于讀者更好地理解本書在第7章介紹的搜索示例.
表3-5展示了其中一部分最常用的集合命令.
表3-5 一些常用的集合命令
命令 | 用例和描述 |
---|---|
SADD | SADD key-name item [item …]—將一個(gè)或多個(gè)元素添加到集合里面,并返回被添加元素當(dāng)中原本并不存在于集合里面的元素?cái)?shù)量 |
SREM | SREM key-name item [item …]—從集合里面移除一個(gè)或多個(gè)元素,并返回被移除元素的數(shù)量 |
SISMEMBER | SISMEMBER key-name item—檢查元素item是否存在于集合key-name 里 |
SCARD | SCARD key-name—返回集合包含的元素的數(shù)量 |
SMEMBERS | SMEMBERS key-name—返回集合包含的所有元素 |
SRANDMEMBER | SRANDMEMBER key-name [count]—從集合里面隨機(jī)地返回一個(gè)或多個(gè)元素.當(dāng)count為正數(shù)時(shí),命令返回的隨機(jī)元素不會(huì)重復(fù);當(dāng)count為負(fù)數(shù)時(shí),命令返回的隨機(jī)元素可能會(huì)出現(xiàn)重復(fù) |
SPOP | SPOP key-name—隨機(jī)地移除集合中的一個(gè)元素,并返回被移除的元素 |
SMOVE | SMOVE source-key dest-key item—如果集合source-key包含元素item,那么從集合source-key里面移除元素item,并將元素item添加到集合dest-key中;如果item被成功移除,那么命令返回1,否則返回0 |
表3-5里面的不少命令都已經(jīng)在第1章介紹過(guò)了,代碼清單3-5展示了這些命令的使用示例.
代碼清單3-5 這個(gè)交互示例展示了Redis中的一些常用的集合命令
通過(guò)使用上面展示的命令,我們可以將各不相同的多個(gè)元素添加到集合里面,比如第1章就使用集合記錄了文章已投票用戶名單,以及文章屬于哪個(gè)群組.但集合真正厲害的地方在于組合和關(guān)聯(lián)多個(gè)集合,表3-6展示了相關(guān)的命令.
表3-6 用于組合和處理多個(gè)集合的Redis命令
命令 | 用例和描述 |
---|---|
SDIFF | SDIFF key-name [key-name …]—返回那些存在于第一個(gè)集合、但不存在于其他集合中的元素(數(shù)學(xué)上的差集運(yùn)算) |
{–:}續(xù)表
命令 | 用例和描述 |
---|---|
SDIFFSTORE | SDIFFSTORE dest-key key-name [key-name …]—將那些存在于第一個(gè)集合但并不存在于其他集合中的元素(數(shù)學(xué)上的差集運(yùn)算)存儲(chǔ)到dest-key鍵里面 |
SINTER | SINTER key-name [key-name …]—返回那些同時(shí)存在于所有集合中的元素(數(shù)學(xué)上的交集運(yùn)算) |
SINTERSTORE | SINTERSTORE dest-key key-name [key-name …]—將那些同時(shí)存在于所有集合的元素(數(shù)學(xué)上的交集運(yùn)算)存儲(chǔ)到dest-key鍵里面 |
SUNION | SUNION key-name [key-name …]—返回那些至少存在于一個(gè)集合中的元素(數(shù)學(xué)上的并集計(jì)算) |
SUNIONSTORE | SUNIONSTORE dest-key key-name [key-name …]—將那些至少存在于一個(gè)集合中的元素(數(shù)學(xué)上的并集計(jì)算)存儲(chǔ)到dest-key鍵里面 |
這些命令分別是并集運(yùn)算、交集運(yùn)算和差集運(yùn)算這3個(gè)基本集合操作的“返回結(jié)果”版本和“存儲(chǔ)結(jié)果”版本,代碼清單3-6展示了這些命令的使用示例.
代碼清單3-6 這個(gè)交互示例展示了Redis的差集運(yùn)算、交集運(yùn)算以及并集運(yùn)算
和Python的集合相比,Redis的集合除了可以被多個(gè)客戶端遠(yuǎn)程地進(jìn)行訪問之外,其他的語(yǔ)義和功能基本都是相同的.
接下來(lái)的一節(jié)將對(duì)Redis的散列處理命令進(jìn)行介紹,這些命令允許用戶將多個(gè)相關(guān)的鍵值對(duì)存儲(chǔ)在一起,以便執(zhí)行獲取操作和更新操作.
3.4 散列
第1章提到過(guò),Redis的散列可以讓用戶將多個(gè)鍵值對(duì)存儲(chǔ)到一個(gè)Redis鍵里面.從功能上來(lái)說(shuō),Redis為散列值提供了一些與字符串值相同的特性,使得散列非常適用于將一些相關(guān)的數(shù)據(jù)存儲(chǔ)在一起.我們可以把這種數(shù)據(jù)聚集看作是關(guān)系數(shù)據(jù)庫(kù)中的行,或者文檔數(shù)據(jù)庫(kù)中的文檔.
本節(jié)將對(duì)最常用的散列命令進(jìn)行介紹:其中包括添加和刪除鍵值對(duì)的命令、獲取所有鍵值對(duì)的命令,以及對(duì)鍵值對(duì)的值進(jìn)行自增或者自減操作的命令.閱讀這一節(jié)可以讓讀者學(xué)習(xí)到如何將數(shù)據(jù)存儲(chǔ)到散列里面,以及這樣做的好處是什么.表3-7展示了一部分常用的散列命令.
表3-7 用于添加和刪除鍵值對(duì)的散列操作
命令 | 用例和描述 |
---|---|
HMGET | HMGET key-name key [key …]—從散列里面獲取一個(gè)或多個(gè)鍵的值 |
HMSET | HMSET key-name key value [key value …]—為散列里面的一個(gè)或多個(gè)鍵設(shè)置值 |
HDEL | HDEL key-name key [key …]—?jiǎng)h除散列里面的一個(gè)或多個(gè)鍵值對(duì),返回成功找到并刪除的鍵值對(duì)數(shù)量 |
HLEN | HLEN key-name—返回散列包含的鍵值對(duì)數(shù)量 |
在表3-7列出的命令當(dāng)中,HDEL命令已經(jīng)在第1章中介紹過(guò)了,而HLEN命令以及用于一次讀取或者設(shè)置多個(gè)鍵的HMGET和HMSET則是新出現(xiàn)的命令.像HMGET和HMSET這種批量處理多個(gè)鍵的命令既可以給用戶帶來(lái)方便,又可以通過(guò)減少命令的調(diào)用次數(shù)以及客戶端與Redis之間的通信往返次數(shù)來(lái)提升Redis的性能.代碼清單3-7展示了這些命令的使用方法.
代碼清單3-7 這個(gè)交互示例展示了Redis中的一些常用的散列命令
第1章介紹的HGET命令和HSET命令分別是HMGET命令和HMSET命令的單參數(shù)版本,這些命令的唯一區(qū)別在于單參數(shù)版本每次執(zhí)行只能處理一個(gè)鍵值對(duì),而多參數(shù)版本每次執(zhí)行可以處理多個(gè)鍵值對(duì).
表3-8列出了散列的其他幾個(gè)批量操作命令,以及一些和字符串操作類似的散列命令.
表3-8 展示Redis散列的更高級(jí)特性
命令 | 用例和描述 |
---|---|
HEXISTS | HEXISTS key-name key—檢查給定鍵是否存在于散列中 |
HKEYS | HKEYS key-name—獲取散列包含的所有鍵 |
HVALS | HVALS key-name—獲取散列包含的所有值 |
HGETALL | HGETALL key-name—獲取散列包含的所有鍵值對(duì) |
HINCRBY | HINCRBY key-name key increment—將鍵key保存的值加上整數(shù)increment |
HINCRBYFLOAT | HINCRBYFLOAT key-name key increment—將鍵key保存的值加上浮點(diǎn)數(shù)increment |
盡管有HGETALL存在,但HKEYS和HVALUES也是非常有用的:如果散列包含的值非常大,那么用戶可以先使用HKEYS取出散列包含的所有鍵,然后再使用HGET一個(gè)接一個(gè)地取出鍵的值,從而避免因?yàn)橐淮潍@取多個(gè)大體積的值而導(dǎo)致服務(wù)器阻塞.
HINCRBY和HINCRBYFLOAT可能會(huì)讓讀者回想起用于處理字符串的INCRBY和INCRBYFLOAT,這兩對(duì)命令擁有相同的語(yǔ)義,它們的不同在于HINCRBY和HINCRBYFLOAT處理的是散列,而不是字符串.代碼清單3-8展示了這些命令的使用方法.
代碼清單3-8 這個(gè)交互示例展示了Redis散列的一些更高級(jí)的特性
正如前面所說(shuō),在對(duì)散列進(jìn)行處理的時(shí)候,如果鍵值對(duì)的值的體積非常龐大,那么用戶可以先使用HKEYS獲取散列的所有鍵,然后通過(guò)只獲取必要的值來(lái)減少需要傳輸?shù)臄?shù)據(jù)量.除此之外,用戶還可以像使用SISMEMBER檢查一個(gè)元素是否存在于集合里面一樣,使用HEXISTS檢查一個(gè)鍵是否存在于散列里面.另外第1章也用到了本節(jié)剛剛回顧過(guò)的HINCRBY來(lái)記錄文章被投票的次數(shù).
在接下來(lái)的一節(jié)中,我們要了解的是之后的章節(jié)里面會(huì)經(jīng)常用到的有序集合結(jié)構(gòu).
3.5 有序集合
和散列存儲(chǔ)著鍵與值之間的映射類似,有序集合也存儲(chǔ)著成員與分值之間的映射,并且提供了分值處理命令,以及根據(jù)分值大小有序地獲取(fetch)或掃描(scan)成員和分值的命令.本書曾在第1章使用有序集合實(shí)現(xiàn)過(guò)基于發(fā)表時(shí)間排序的文章列表和基于投票數(shù)量排序的文章列表,還在第2章使用有序集合存儲(chǔ)過(guò)cookie的過(guò)期時(shí)間.
本節(jié)將對(duì)操作有序集合的命令進(jìn)行介紹,其中包括向有序集合添加新元素的命令、更新已有元素的命令,以及對(duì)有序集合進(jìn)行交集運(yùn)算和并集運(yùn)算的命令.閱讀本節(jié)可以加深讀者對(duì)有序集合的認(rèn)識(shí),從而幫助讀者更好地理解本書在第1章、第5章、第6章和第7章展示的有序集合示例.
表3-9展示了一部分常用的有序集合命令.
表3-9 一些常用的有序集合命令
命令 | 用例和描述 |
---|---|
ZADD | ZADD key-name score member [score member …]—將帶有給定分值的成員添加到有序集合里面 |
ZREM | ZREM key-name member [member …]—從有序集合里面移除給定的成員,并返回被移除成員的數(shù)量 |
ZCARD | ZCARD key-name—返回有序集合包含的成員數(shù)量 |
ZINCRBY | ZINCRBY key-name increment member—將member成員的分值加上increment |
ZCOUNT | ZCOUNT key-name min max—返回分值介于min和max之間的成員數(shù)量 |
ZRANK | ZRANK key-name member—返回成員member在有序集合中的排名 |
ZSCORE | ZSCORE key-name member—返回成員member的分值 |
ZRANGE | ZRANGE key-name start stop [WITHSCORES]—返回有序集合中排名介于start和stop之間的成員,如果給定了可選的WITHSCORES選項(xiàng),那么命令會(huì)將成員的分值也一并返回 |
在上面列出的命令當(dāng)中,有一部分命令已經(jīng)在第1章和第2章使用過(guò)了,所以讀者應(yīng)該不會(huì)對(duì)它們感到陌生,代碼清單3-9回顧了這些命令的用法.
代碼清單3-9 這個(gè)交互示例展示了Redis中的一些常用的有序集合命令
因?yàn)閆ADD、ZREM、ZINCRBY、ZSCORE和ZRANGE都已經(jīng)在第1章和第2章介紹過(guò)了,所以讀者應(yīng)該不會(huì)對(duì)它們感到陌生.ZCOUNT命令和其他命令不太相同,它主要用于計(jì)算分值在給定范圍內(nèi)的成員數(shù)量.
表3-10展示了另外一些非常有用的有序集合命令.
表3-10 有序集合的范圍型數(shù)據(jù)獲取命令和范圍型數(shù)據(jù)刪除命令,以及并集命令和交集命令
在表3-10展示的命令里面,有幾個(gè)是之前沒介紹過(guò)的新命令.除了使用逆序來(lái)處理有序集合之外,ZREV*命令的工作方式和相對(duì)應(yīng)的非逆序命令的工作方式完全一樣(逆序就是指元素按照分值從大到小地排列).代碼清單3-10展示了ZINTERSTORE和ZUNIONSTORE的用法.
代碼清單3-10 這個(gè)交互示例展示了ZINTERSTORE命令和ZUNIONSTORE命令的用法
有序集合的并集運(yùn)算和交集運(yùn)算在剛開始接觸時(shí)可能會(huì)比較難懂,所以本節(jié)將使用圖片來(lái)展示交集運(yùn)算和并集運(yùn)算的執(zhí)行過(guò)程.圖3-1展示了對(duì)兩個(gè)輸入有序集合執(zhí)行交集運(yùn)算并得到輸出有序集合的過(guò)程,這次交集運(yùn)算使用的是默認(rèn)的聚合函數(shù)sum,所以輸出有序集合成員的分值都是通過(guò)加法計(jì)算得出的.
圖3-1 執(zhí)行conn.zinterstore(‘zset-i’, [‘zset-1’, ‘zset-2’])
將使得同時(shí)存在于zset-1和zset-2里面的元素被添加到zset-i里面
并集運(yùn)算和交集運(yùn)算不同,只要某個(gè)成員存在于至少一個(gè)輸入有序集合里面,那么這個(gè)成員就會(huì)被包含在輸出有序集合里面.圖3-2展示了使用聚合函數(shù)min執(zhí)行并集運(yùn)算的過(guò)程,min函數(shù)在多個(gè)輸入有序集合都包含同一個(gè)成員的情況下,會(huì)將最小的那個(gè)分值設(shè)置為這個(gè)成員在輸出有序集合的分值.
圖3-2 執(zhí)行conn.zunionstore(‘zset-u’, [‘zset-1’, ‘zset-2’], aggregate=’min’)
會(huì)將存在于zset-1或者zset-2里面的元素通過(guò)min函數(shù)組合到zset-u里面
在第1章中,我們就基于“集合可以作為ZUNIONSTORE操作和ZINTERSTORE操作的輸入”這個(gè)事實(shí),在沒有使用額外的有序集合來(lái)存儲(chǔ)群組文章的評(píng)分和發(fā)布時(shí)間的情況下,實(shí)現(xiàn)了群組文章的添加和刪除操作.圖3-3展示了如何使用ZUNIONSTORE命令來(lái)將兩個(gè)有序集合和一個(gè)集合組合成一個(gè)有序集合.
圖3-3 執(zhí)行conn.zunionstore(‘zset-u2’, [‘zset-1’, ‘zset-2’, ‘set-1’])
將使得所有存在于zset-1、zset-2或者set-1里面的元素都被添加到zset-u2里面
第7章將使用ZINTERSTORE和ZUNIONSTORE來(lái)構(gòu)建幾個(gè)不同類型的搜索系統(tǒng),并說(shuō)明如何通過(guò)可選的WEIGHTS參數(shù)來(lái)以幾種不同的方式組合有序集合的分值,從而使得集合和有序集合可以用于解決更多問題.
讀者在開發(fā)應(yīng)用的過(guò)程中,也許曾經(jīng)聽說(shuō)過(guò)發(fā)布與訂閱(publish/subscribe)模式,又稱pub/sub模式,Redis也實(shí)現(xiàn)了這種模式,接下來(lái)的一節(jié)將對(duì)其進(jìn)行介紹.
3.6 發(fā)布與訂閱
如果你因?yàn)橄氩黄饋?lái)本書在前面的哪個(gè)章節(jié)里面介紹過(guò)發(fā)布與訂閱而困惑,那么大可不必—這是本書目前為止第一次介紹發(fā)布與訂閱.一般來(lái)說(shuō),發(fā)布與訂閱(又稱pub/sub)的特點(diǎn)是訂閱者(listener)負(fù)責(zé)訂閱頻道(channel),發(fā)送者(publisher)負(fù)責(zé)向頻道發(fā)送二進(jìn)制字符串消息(binary string message).每當(dāng)有消息被發(fā)送至給定頻道時(shí),頻道的所有訂閱者都會(huì)收到消息.我們也可以把頻道看作是電臺(tái),其中訂閱者可以同時(shí)收聽多個(gè)電臺(tái),而發(fā)送者則可以在任何電臺(tái)發(fā)送消息.
本節(jié)將對(duì)發(fā)布與訂閱的相關(guān)操作進(jìn)行介紹,閱讀這一節(jié)可以讓讀者學(xué)會(huì)怎樣使用發(fā)布與訂閱的相關(guān)命令,并了解到為什么本書在之后的章節(jié)里面會(huì)使用其他相似的解決方案來(lái)代替Redis提供的發(fā)布與訂閱.
表3-11展示了Redis提供的5個(gè)發(fā)布與訂閱命令.
表3-11 Redis提供的發(fā)布與訂閱命令
命令 | 用例和描述 |
---|---|
SUBSCRIBE | SUBSCRIBE channel [channel …]—訂閱給定的一個(gè)或多個(gè)頻道 |
UNSUBSCRIBE | UNSUBSCRIBE [channel [channel …]]—退訂給定的一個(gè)或多個(gè)頻道,如果執(zhí)行時(shí)沒有給定任何頻道,那么退訂所有頻道 |
PUBLISH | PUBLISH channel message—向給定頻道發(fā)送消息 |
PSUBSCRIBE | PSUBSCRIBE pattern [pattern …]—訂閱與給定模式相匹配的所有頻道 |
PUNSUBSCRIBE | PUNSUBSCRIBE [pattern [pattern …]]—退訂給定的模式,如果執(zhí)行時(shí)沒有給定任何模式,那么退訂所有模式 |
考慮到PUBLISH命令和SUBSCRIBE命令在Python客戶端的實(shí)現(xiàn)方式,一個(gè)比較簡(jiǎn)單的演示發(fā)布與訂閱的方法,就是像代碼清單3-11那樣使用輔助線程(helper thread)來(lái)執(zhí)行PUBLISH命令.
代碼清單3-11 這個(gè)交互示例展示了如何使用Redis中的PUBLISH命令以及SUBSCRIBE命令
雖然Redis的發(fā)布與訂閱模式非常有用,但本書只在這一節(jié)和8.5節(jié)中使用了這個(gè)模式,這樣做的原因有以下兩個(gè).
第一個(gè)原因和Redis系統(tǒng)的穩(wěn)定性有關(guān).對(duì)于舊版Redis來(lái)說(shuō),如果一個(gè)客戶端訂閱了某個(gè)或某些頻道,但它讀取消息的速度卻不夠快的話,那么不斷積壓的消息就會(huì)使得Redis輸出緩沖區(qū)的體積變得越來(lái)越大,這可能會(huì)導(dǎo)致Redis的速度變慢,甚至直接崩潰.也可能會(huì)導(dǎo)致Redis被操作系統(tǒng)強(qiáng)制殺死,甚至導(dǎo)致操作系統(tǒng)本身不可用.新版的Redis不會(huì)出現(xiàn)這種問題,因?yàn)樗鼤?huì)自動(dòng)斷開不符合client-output-buffer-limit pubsub配置選項(xiàng)要求的訂閱客戶端(本書第8章將對(duì)這個(gè)選項(xiàng)做更詳細(xì)的介紹).
第二個(gè)原因和數(shù)據(jù)傳輸?shù)目煽啃杂嘘P(guān).任何網(wǎng)絡(luò)系統(tǒng)在執(zhí)行操作時(shí)都可能會(huì)遇上斷線情況,而斷線產(chǎn)生的連接錯(cuò)誤通常會(huì)使得網(wǎng)絡(luò)連接兩端中的其中一端進(jìn)行重新連接.本書使用的Python語(yǔ)言的Redis客戶端會(huì)在連接失效時(shí)自動(dòng)進(jìn)行重新連接,也會(huì)自動(dòng)處理連接池(connection pool,具體信息將在第4章介紹),諸如此類.但是,如果客戶端在執(zhí)行訂閱操作的過(guò)程中斷線,那么客戶端將丟失在斷線期間發(fā)送的所有消息,因此依靠頻道來(lái)接收消息的用戶可能會(huì)對(duì)Redis提供的PUBLISH命令和SUBSCRIBE命令的語(yǔ)義感到失望.
基于以上兩個(gè)原因,本書在第6章編寫了兩個(gè)不同的方法來(lái)實(shí)現(xiàn)可靠的消息傳遞操作,這兩個(gè)方法除了可以處理網(wǎng)絡(luò)斷線之外,還可以防止Redis因?yàn)橄⒎e壓而耗費(fèi)過(guò)多內(nèi)存(這個(gè)方法即使對(duì)于舊版Redis也是有效的).
如果你喜歡簡(jiǎn)單易用的PUBLISH命令和SUBSCRIBE命令,并且能夠承擔(dān)可能會(huì)丟失一小部分?jǐn)?shù)據(jù)的風(fēng)險(xiǎn),那么你也可以繼續(xù)使用Redis提供的發(fā)布與訂閱特性,而不是8.5節(jié)中提供的實(shí)現(xiàn),只要記得先把client-output-buffer-limit pubsub選項(xiàng)設(shè)置好就行了.
到目前為止,本書介紹的大多數(shù)命令都是與特定數(shù)據(jù)類型相關(guān)的.接下來(lái)的一節(jié)要介紹的命令你可能也會(huì)用到,但它們既不屬于Redis提供的5種數(shù)據(jù)結(jié)構(gòu),也不屬于發(fā)布與訂閱特性.
3.7 其他命令
到目前為止,本章介紹了Redis提供的5種結(jié)構(gòu)以及Redis的發(fā)布與訂閱模式.本節(jié)將要介紹的命令則可以用于處理多種類型的數(shù)據(jù):首先要介紹的是可以同時(shí)處理字符串、集合、列表和散列的SORT命令;之后要介紹是用于實(shí)現(xiàn)基本事務(wù)特性的MULTI命令和EXEC命令,這兩個(gè)命令可以讓用戶將多個(gè)命令當(dāng)作一個(gè)命令來(lái)執(zhí)行;最后要介紹的是幾個(gè)不同的自動(dòng)過(guò)期命令,它們可以自動(dòng)刪除無(wú)用數(shù)據(jù).
閱讀本節(jié)有助于讀者更好地理解如何同時(shí)組合和操作多種數(shù)據(jù)類型.
3.7.1 排序
Redis的排序操作和其他編程語(yǔ)言的排序操作一樣,都可以根據(jù)某種比較規(guī)則對(duì)一系列元素進(jìn)行有序的排列.負(fù)責(zé)執(zhí)行排序操作的SORT命令可以根據(jù)字符串、列表、集合、有序集合、散列這5種鍵里面存儲(chǔ)著的數(shù)據(jù),對(duì)列表、集合以及有序集合進(jìn)行排序.如果讀者之前曾經(jīng)使用過(guò)關(guān)系數(shù)據(jù)庫(kù)的話,那么可以將SORT命令看作是SQL語(yǔ)言里的order by子句.表3-12展示了SORT命令的定義.
表3-12 SORT命令的定義
使用SORT命令提供的選項(xiàng)可以實(shí)現(xiàn)以下功能:根據(jù)降序而不是默認(rèn)的升序來(lái)排序元素;將元素看作是數(shù)字來(lái)進(jìn)行排序,或者將元素看作是二進(jìn)制字符串來(lái)進(jìn)行排序(比如排序字符串’110’和’12’的結(jié)果就跟排序數(shù)字110和12的結(jié)果不一樣);使用被排序元素之外的其他值作為權(quán)重來(lái)進(jìn)行排序,甚至還可以從輸入的列表、集合、有序集合以外的其他地方進(jìn)行取值.
代碼清單3-12展示了一些SORT命令的使用示例.其中,最開頭的幾行代碼設(shè)置了一些初始數(shù)據(jù),然后對(duì)這些數(shù)據(jù)進(jìn)行了數(shù)值排序和字符串排序,最后的代碼演示了如何通過(guò)SORT命令的特殊語(yǔ)法來(lái)將散列存儲(chǔ)的數(shù)據(jù)作為權(quán)重進(jìn)行排序,以及怎樣獲取并返回散列存儲(chǔ)的數(shù)據(jù).
代碼清單3-12 這個(gè)交互示例展示了SORT命令的一些簡(jiǎn)單的用法
SORT命令不僅可以對(duì)列表進(jìn)行排序,還可以對(duì)集合進(jìn)行排序,然后返回一個(gè)列表形式的排序結(jié)果.代碼清單3-12除了展示如何使用alpha關(guān)鍵字參數(shù)對(duì)元素進(jìn)行字符串排序之外,還展示了如何基于外部數(shù)據(jù)對(duì)元素進(jìn)行排序,以及如何獲取并返回外部數(shù)據(jù).第7章將介紹如何組合使用集合操作和SORT命令:當(dāng)集合結(jié)構(gòu)計(jì)算交集、并集和差集的能力,與SORT命令獲取散列存儲(chǔ)的外部數(shù)據(jù)的能力相結(jié)合時(shí),SORT命令將變得非常強(qiáng)大.
盡管SORT是Redis中唯一一個(gè)可以同時(shí)處理3種不同類型的數(shù)據(jù)的命令,但基本的Redis事務(wù)同樣可以讓我們?cè)谝贿B串不間斷執(zhí)行的命令里面操作多種不同類型的數(shù)據(jù).
3.7.2 基本的Redis事務(wù)
有時(shí)候?yàn)榱送瑫r(shí)處理多個(gè)結(jié)構(gòu),我們需要向Redis發(fā)送多個(gè)命令.盡管Redis有幾個(gè)可以在兩個(gè)鍵之間復(fù)制或者移動(dòng)元素的命令,但卻沒有那種可以在兩個(gè)不同類型之間移動(dòng)元素的命令(雖然可以使用ZUNIONSTORE命令將元素從一個(gè)集合復(fù)制到一個(gè)有序集合).為了對(duì)相同或者不同類型的多個(gè)鍵執(zhí)行操作,Redis有5個(gè)命令可以讓用戶在不被打斷(interruption)的情況下對(duì)多個(gè)鍵執(zhí)行操作,它們分別是WATCH、MULTI、EXEC、UNWATCH和DISCARD.
這一節(jié)只介紹最基本的Redis事務(wù)用法,即使用MULTI命令和EXEC命令.如果讀者想看看使用WATCH、MULTI、EXEC和UNWATCH等多個(gè)命令的事務(wù)是什么樣子的,可以閱讀4.4節(jié),其中解釋了為什么需要在使用MULTI和EXEC的同時(shí)使用WATCH和UNWATCH.
什么是Redis的基本事務(wù)
Redis的基本事務(wù)(basic transaction)需要用到MULTI命令和EXEC命令,這種事務(wù)可以讓一個(gè)客戶端在不被其他客戶端打斷的情況下執(zhí)行多個(gè)命令.和關(guān)系數(shù)據(jù)庫(kù)那種可以在執(zhí)行的過(guò)程中進(jìn)行回滾(rollback)的事務(wù)不同,在Redis里面,被MULTI命令和EXEC命令包圍的所有命令會(huì)一個(gè)接一個(gè)地執(zhí)行,直到所有命令都執(zhí)行完畢為止.當(dāng)一個(gè)事務(wù)執(zhí)行完畢之后,Redis才會(huì)處理其他客戶端的命令.
要在Redis里面執(zhí)行事務(wù),我們首先需要執(zhí)行MULTI命令,然后輸入那些我們想要在事務(wù)里面執(zhí)行的命令,最后再執(zhí)行EXEC命令.當(dāng)Redis從一個(gè)客戶端那里接收到MULTI命令時(shí),Redis會(huì)將這個(gè)客戶端之后發(fā)送的所有命令都放入到一個(gè)隊(duì)列里面,直到這個(gè)客戶端發(fā)送EXEC命令為止,然后Redis就會(huì)在不被打斷的情況下,一個(gè)接一個(gè)地執(zhí)行存儲(chǔ)在隊(duì)列里面的命令.從語(yǔ)義上來(lái)說(shuō),Redis事務(wù)在Python客戶端上面是由流水線(pipeline)實(shí)現(xiàn)的:對(duì)連接對(duì)象調(diào)用piepline()方法將創(chuàng)建一個(gè)事務(wù),在一切正常的情況下,客戶端會(huì)自動(dòng)地使用MULTI和EXEC包裹起用戶輸入的多個(gè)命令.此外,為了減少Redis與客戶端之間的通信往返次數(shù),提升執(zhí)行多個(gè)命令時(shí)的性能,Python的Redis客戶端會(huì)存儲(chǔ)起事務(wù)包含的多個(gè)命令,然后在事務(wù)執(zhí)行時(shí)一次性地將所有命令都發(fā)送給Redis.
跟介紹PUBLISH命令和SUBSCRIBE命令時(shí)的情況一樣,要展示事務(wù)執(zhí)行結(jié)果,最簡(jiǎn)單的方法就是將事務(wù)放到線程里面執(zhí)行.代碼清單3-13展示了在沒有使用事務(wù)的情況下,執(zhí)行并行(parallel)自增操作的結(jié)果.
代碼清單3-13 在并行執(zhí)行命令時(shí),缺少事務(wù)可能會(huì)引發(fā)的問題
因?yàn)闆]有使用事務(wù),所以3個(gè)線程都可以在執(zhí)行自減操作之前,對(duì)notrans:計(jì)數(shù)器執(zhí)行自增操作.雖然代碼清單里面通過(guò)休眠100毫秒的方式來(lái)放大了潛在的問題,但如果我們確實(shí)需要在不受其他命令干擾的情況下,對(duì)計(jì)數(shù)器執(zhí)行自增操作和自減操作,那么我們就不得不解決這個(gè)潛在的問題.代碼清單3-14展示了如何使用事務(wù)來(lái)執(zhí)行相同的操作.
代碼清單3-14 使用事務(wù)來(lái)處理命令的并行執(zhí)行問題
可以看到,盡管自增操作和自減操作之間有一段延遲時(shí)間,但通過(guò)使用事務(wù),各個(gè)線程都可以在不被其他線程打斷的情況下,執(zhí)行各自隊(duì)列里面的命令.記住,Redis要在接收到EXEC命令之后,才會(huì)執(zhí)行那些位于MULTI和EXEC之間的入隊(duì)命令.
使用事務(wù)既有利也有弊,本書的4.4節(jié)將對(duì)這個(gè)問題進(jìn)行討論.
練習(xí):移除競(jìng)爭(zhēng)條件 正如前面的代碼清單3-13所示,MULTI和EXEC事務(wù)的一個(gè)主要作用是移除競(jìng)爭(zhēng)條件.第1章展示的article_vote()函數(shù)包含一個(gè)競(jìng)爭(zhēng)條件以及一個(gè)因?yàn)楦?jìng)爭(zhēng)條件而出現(xiàn)的bug.函數(shù)的競(jìng)爭(zhēng)條件可能會(huì)造成內(nèi)存泄漏,而函數(shù)的bug則可能會(huì)導(dǎo)致不正確的投票結(jié)果出現(xiàn).盡管article_ vote()函數(shù)的競(jìng)爭(zhēng)條件和bug出現(xiàn)的機(jī)會(huì)都非常少,但為了防范于未然,你能想個(gè)辦法修復(fù)它們么?提示:如果你覺得很難理解競(jìng)爭(zhēng)條件為什么會(huì)導(dǎo)致內(nèi)存泄漏,那么可以在分析第1章的post_article()函數(shù)的同時(shí),閱讀一下6.2.5節(jié).
練習(xí):提高性能 在Redis里面使用流水線的另一個(gè)目的是提高性能(詳細(xì)的信息會(huì)在之后的4.4節(jié)至4.6節(jié)中介紹).在執(zhí)行一連串命令時(shí),減少Redis與客戶端之間的通信往返次數(shù)可以大幅降低客戶端等待回復(fù)所需的時(shí)間.第1章的get_articles()函數(shù)在獲取整個(gè)頁(yè)面的文章時(shí),需要在Redis與客戶端之間進(jìn)行26次通信往返,這種做法簡(jiǎn)直低效得令人發(fā)指,你能否想個(gè)辦法將get_articles()函數(shù)的往返次數(shù)從26次降低為2次呢?
在使用Redis存儲(chǔ)數(shù)據(jù)的時(shí)候,有些數(shù)據(jù)僅在一段很短的時(shí)間內(nèi)有用,雖然我們可以在數(shù)據(jù)的有效期過(guò)了之后手動(dòng)刪除無(wú)用的數(shù)據(jù),但更好的辦法是使用Redis提供的鍵過(guò)期操作來(lái)自動(dòng)刪除無(wú)用數(shù)據(jù).
3.7.3 鍵的過(guò)期時(shí)間
在使用Redis存儲(chǔ)數(shù)據(jù)的時(shí)候,有些數(shù)據(jù)可能在某個(gè)時(shí)間點(diǎn)之后就不再有用了,用戶可以使用DEL命令顯式地刪除這些無(wú)用數(shù)據(jù),也可以通過(guò)Redis的過(guò)期時(shí)間(expiration)特性來(lái)讓一個(gè)鍵在給定的時(shí)限(timeout)之后自動(dòng)被刪除.當(dāng)我們說(shuō)一個(gè)鍵“帶有生存時(shí)間(time to live)”或者一個(gè)鍵“會(huì)在特定時(shí)間之后過(guò)期(expire)”時(shí),我們指的是Redis會(huì)在這個(gè)鍵的過(guò)期時(shí)間到達(dá)時(shí)自動(dòng)刪除該鍵.
雖然過(guò)期時(shí)間特性對(duì)于清理緩存數(shù)據(jù)非常有用,不過(guò)如果讀者翻一下本書的其他章節(jié),就會(huì)發(fā)現(xiàn)除了6.2節(jié)、7.1節(jié)和7.2節(jié)之外,本書使用過(guò)期時(shí)間特性的情況并不多,這主要和本書使用的結(jié)構(gòu)類型有關(guān).在本書常用的命令當(dāng)中,只有少數(shù)幾個(gè)命令可以原子地為鍵設(shè)置過(guò)期時(shí)間,并且對(duì)于列表、集合、散列和有序集合這樣的容器(container)來(lái)說(shuō),鍵過(guò)期命令只能為整個(gè)鍵設(shè)置過(guò)期時(shí)間,而沒辦法為鍵里面的單個(gè)元素設(shè)置過(guò)期時(shí)間(為了解決這個(gè)問題,本書在好幾個(gè)地方都使用了存儲(chǔ)時(shí)間戳的有序集合來(lái)實(shí)現(xiàn)針對(duì)單個(gè)元素的過(guò)期操作).
本節(jié)將對(duì)那些可以在給定時(shí)限之后或者給定時(shí)間之后自動(dòng)刪除過(guò)期鍵的Redis命令進(jìn)行介紹,閱讀本節(jié)可以讓讀者學(xué)習(xí)到使用過(guò)期操作來(lái)自動(dòng)刪除過(guò)期數(shù)據(jù)并降低Redis內(nèi)存占用的方法.
表3-13列出了Redis提供的用于為鍵設(shè)置過(guò)期時(shí)間的命令,以及查看鍵的過(guò)期時(shí)間的命令.
表3-13 用于處理過(guò)期時(shí)間的Redis命令
命令 | 示例和描述 |
---|---|
PERSIST | PERSIST key-name—移除鍵的過(guò)期時(shí)間 |
TTL | TTL key-name—查看給定鍵距離過(guò)期還有多少秒 |
EXPIRE | EXPIRE key-name seconds—讓給定鍵在指定的秒數(shù)之后過(guò)期 |
EXPIREAT | EXPIREAT key-name timestamp—將給定鍵的過(guò)期時(shí)間設(shè)置為給定的UNIX時(shí)間戳 |
PTTL | PTTL key-name—查看給定鍵距離過(guò)期時(shí)間還有多少毫秒,這個(gè)命令在Redis 2.6或以上版本可用 |
PEXPIRE | PEXPIRE key-name milliseconds—讓鍵給定鍵在指定的毫秒數(shù)之后過(guò)期,這個(gè)命令在Redis 2.6或以上版本可用 |
PEXPIREAT | PEXPIREAT key-name timestamp-milliseconds—將一個(gè)毫秒級(jí)精度的UNIX時(shí)間戳設(shè)置為給定鍵的過(guò)期時(shí)間,這個(gè)命令在Redis 2.6或以上版本可用 |
代碼清單3-15展示了幾個(gè)對(duì)鍵執(zhí)行過(guò)期時(shí)間操作的例子.
代碼清單3-15 展示Redis中過(guò)期時(shí)間相關(guān)的命令的使用方法
練習(xí):使用EXPIRE命令代替時(shí)間戳有序集合 2.1節(jié)、2.2節(jié)和2.5節(jié)中使用了一個(gè)根據(jù)時(shí)間戳進(jìn)行排序、用于清除會(huì)話ID的有序集合,通過(guò)這個(gè)有序集合,程序可以在清理會(huì)話的時(shí)候,對(duì)用戶瀏覽過(guò)的商品以及用戶購(gòu)物車?yán)锩娴纳唐愤M(jìn)行分析.但是,如果我們決定不對(duì)商品進(jìn)行分析的話,那么就可以使用Redis提供的過(guò)期時(shí)間操作來(lái)自動(dòng)清理過(guò)期的會(huì)話ID,而無(wú)須使用清理函數(shù).那么,你能否想辦法修改在第2章定義的update_token()函數(shù)和add_to_cart()函數(shù),讓它們使用過(guò)期時(shí)間操作來(lái)刪除會(huì)話ID,從而代替目前使用有序集合來(lái)記錄并清除會(huì)話ID的做法呢?
本文來(lái)自《Redis實(shí)戰(zhàn)》
維易PHP培訓(xùn)學(xué)院每天發(fā)布《Redis分享之你不可不知的Redis常用命令》等實(shí)戰(zhàn)技能,PHP、MYSQL、LINUX、APP、JS,CSS全面培養(yǎng)人才。
轉(zhuǎn)載請(qǐng)注明本頁(yè)網(wǎng)址:
http://www.fzlkiss.com/jiaocheng/9607.html