一沿猜、簡(jiǎn)介
本節(jié)將按照單個(gè)鍵枚荣、遍歷鍵、數(shù)據(jù)庫(kù)管理三個(gè)維度對(duì)一些通用命令進(jìn)行介紹啼肩。
二棍弄、單個(gè)鍵管理
針對(duì)單個(gè)鍵的命令,前面幾節(jié)已經(jīng)介紹過(guò)一部分了疟游,例如:type、del痕支、object颁虐、exists、expire等卧须,下面將介紹剩余的幾個(gè)重要命令另绩。
1、鍵重命名
rename key newkey
如:
127.0.0.1:6379> set python jedis
OK
127.0.0.1:6379> rename python java
OK
127.0.0.1:6379> get python
(nil)
127.0.0.1:6379> get java
"jedis"
Tip:如果在rename之前花嘶,鍵java已經(jīng)存在笋籽,那么它的值也將被覆蓋,如:
127.0.0.1:6379> set a b
OK
127.0.0.1:6379> set c d
OK
127.0.0.1:6379> rename a c
OK
127.0.0.1:6379> get a
(nil)
127.0.0.1:6379> get c
"b"
為了防止被強(qiáng)行rename椭员,Redis提供民renamenx命令车海,確保只有newKey不存在時(shí)才被覆蓋,如:
127.0.0.1:6379> set a b
OK
127.0.0.1:6379> set c d
OK
127.0.0.1:6379> renamenx a c
(integer) 0
127.0.0.1:6379> get a
"b"
127.0.0.1:6379> get c
"d"
在使用重命名命令時(shí)隘击,有兩點(diǎn)需要注意:
- 由于重命名鍵期間會(huì)執(zhí)行del命令刪除舊的鍵侍芝,如果鍵對(duì)應(yīng)的值比較大研铆,會(huì)存在阻塞Redis的可能性,這點(diǎn)不要忽視州叠。
- 如果rename和renamenx中的key和newkey如果是相同的棵红,在Redis3.2和之前的版本返回結(jié)果略有不同。Redis3.2中會(huì)返回OK咧栗,而之前的版本會(huì)提示錯(cuò)誤逆甜。
2、隨機(jī)返回一個(gè)鍵
randomkey
如:
127.0.0.1:6379> dbsize
(integer) 21
127.0.0.1:6379> randomkey
"user:1:follow"
127.0.0.1:6379> randomkey
"d"
3致板、鍵過(guò)期
前面章節(jié)有簡(jiǎn)單介紹鍵過(guò)期功能交煞,它可以自動(dòng)將帶有過(guò)期時(shí)間的鍵刪除,在許多應(yīng)用場(chǎng)景都非常幫助可岂。除了expire错敢、ttl命令外,Redis還提供了expireat缕粹、pexpire稚茅、pexpireat、pttl平斩、persist等一系列命令亚享,下面分別進(jìn)行說(shuō)明:
- expire key seconds:鍵在seconds秒后過(guò)期。
- expireat key timestamp:鍵在秒級(jí)時(shí)間戳timestamp后過(guò)期绘面。
如:
127.0.0.1:6379> set hi hhhhhhhhhha
OK
127.0.0.1:6379> expire hi 10
(integer) 1
127.0.0.1:6379> ttl hi
(integer) 8
127.0.0.1:6379> pttl hi
(integer) 6104
127.0.0.1:6379> ttl hi
(integer) 3
127.0.0.1:6379> pttl hi
(integer) 2241
127.0.0.1:6379> ttl hi
(integer) -2
127.0.0.1:6379> pttl hi
(integer) -2
ttl命令和pttl都可以查詢鍵的剩余時(shí)間欺税,但是pttl精度更高可以達(dá)到毫秒級(jí)別,有3種返回結(jié)果:
- 大于等于0的整數(shù):鍵剩余的過(guò)期時(shí)間(ttl是秒揭璃,pttl是毫秒)晚凿。
- -1:鍵沒(méi)有設(shè)置過(guò)期時(shí)。
- -2:鍵不存在瘦馍。
expireat命令可以設(shè)置鍵的秒級(jí)過(guò)期時(shí)間戳歼秽,例如需要將鍵hello在2018-09-01 00:00:00(秒級(jí)時(shí)間戳為1535731200)過(guò)期拉岁,可以執(zhí)行如下操作:
127.0.0.1:6379> expireat hello 1535731200
(integer) 1
此外罗标,Redis2.6版本后提供了毫秒級(jí)的過(guò)期方案:
- pexpire key milliseconds:鍵在milliseconds毫秒后過(guò)期。
- pexpireat key milliseconds-timestamp:鍵在毫秒級(jí)時(shí)間戳timestamp后過(guò)期锈锤。
但無(wú)論使用過(guò)期時(shí)間還是時(shí)間戳院崇,秒級(jí)還是毫秒級(jí)肆氓,有Redis內(nèi)部最終使用的都是pexpireat。
在會(huì)用Redis相關(guān)過(guò)期命令時(shí)底瓣,需要注意以下幾點(diǎn):
1)如果expire key的鍵不存在谢揪,返回結(jié)果為0
2)如果過(guò)期時(shí)間為負(fù)值,鍵會(huì)立即被刪除,猶如使用del命令一樣
3)persist命令可以將鍵的過(guò)期時(shí)間清除
127.0.0.1:6379> hset hkey a b
(integer) 1
127.0.0.1:6379> expire hkey 50
(integer) 1
127.0.0.1:6379> ttl hkey
(integer) 45
127.0.0.1:6379> persist hkey
(integer) 1
127.0.0.1:6379> ttl hkey
(integer) -1
4)對(duì)于字符串型鍵键耕,執(zhí)行set命令會(huì)去掉過(guò)期時(shí)間寺滚,這個(gè)問(wèn)題很容易在開(kāi)發(fā)中被忽視。
127.0.0.1:6379> expire hello 60
(integer) 1
127.0.0.1:6379> ttl hello
(integer) 51
127.0.0.1:6379> set hello seeeeeeeeee
OK
127.0.0.1:6379> ttl hello
(integer) -1
5)Redis不支持二級(jí)數(shù)據(jù)結(jié)構(gòu)(例如哈希屈雄、列表)內(nèi)部元素的過(guò)期功能村视,例如不能對(duì)列表類型的一個(gè)元素做過(guò)期時(shí)間設(shè)置。
6)setex命令作為 set + expire 的組合酒奶,但不是原子執(zhí)行蚁孔,同時(shí)減少了一次網(wǎng)絡(luò)通訊的時(shí)間。
4惋嚎、遷移鍵
遷移鍵功能非常重要杠氢,因?yàn)橛袝r(shí)候我們只想把部分?jǐn)?shù)據(jù)由一個(gè)Redis遷移到另一個(gè)Redis(例如從生產(chǎn)環(huán)境遷移到測(cè)試環(huán)境),Redis發(fā)展歷程中提供了move另伍、dump+restore鼻百、migrate三組遷移方法,它們的實(shí)現(xiàn)方式以及使用場(chǎng)景不太相同摆尝,下面分別介紹温艇。
1)move
如上圖所示,move命令用于在Redis內(nèi)部進(jìn)行數(shù)據(jù)遷移堕汞,Redis內(nèi)部可以有多個(gè)數(shù)據(jù)庫(kù)勺爱,彼此在數(shù)據(jù)上是相互隔離的,move key db就是把指定的鍵從源數(shù)據(jù)庫(kù)移動(dòng)到目標(biāo)數(shù)據(jù)庫(kù)中讯检。但筆者認(rèn)為多數(shù)據(jù)庫(kù)功能不建議在生產(chǎn)環(huán)境使用琐鲁,所以這個(gè)命令讀者知道即可。
2)dump+restore
dump key
restore key ttl value
dump+restore可以實(shí)現(xiàn)在不同的Redis實(shí)例之間進(jìn)行數(shù)據(jù)遷移功能人灼,整個(gè)遷移的過(guò)程分為兩步:
a) 在源Redis上围段,dump命令會(huì)將鍵值序列化,格式采用的是RDB格式投放。
b) 在目標(biāo)Redis上奈泪,restore命令將上面序列化的值進(jìn)行還原,其中ttl參數(shù)代表過(guò)期時(shí)間跪呈,如果ttl=0代表沒(méi)有過(guò)期時(shí)間。
注意:
第一取逾,整個(gè)遷移過(guò)程并非原子性的耗绿,而是通過(guò)客戶端分步完成的。第二砾隅,遷移過(guò)程是開(kāi)啟了兩個(gè)客戶端連接误阻,所以dump的結(jié)果不是在源Redis和目標(biāo)Redis之間進(jìn)行傳輸。
例子演示:
// 1、在源Redis上執(zhí)行dump
127.0.0.1:6379> set hello 'hi, I am nosee.'
OK
127.0.0.1:6379> dump hello
"\x00\x0fhi, I am nosee.\a\x00\xd8Z\xbbCd=\x8b\xda"
127.0.0.1:6379>
// 2究反、在目標(biāo)Redis上執(zhí)行restore
127.0.0.1:6380> get hello
(nil)
127.0.0.1:6380> restore hello 0 "\x00\x0fhi, I am nosee.\a\x00\xd8Z\xbbCd=\x8b\xda"
OK
127.0.0.1:6380> get hello
"hi, I am nosee."
上面兩步對(duì)應(yīng)的偽代碼如下:
Redis sourceRedis = new Redis("sourceMachine", 6379);
Redis targetRedis = new Redis("targetMachine", 6380);
targetRedis.restore("hello", 0, sourceRedis.dump(key));
3)migrate
migrate host port key|"" destination-db timeout [copy] [replace] [keys key [key ...]]
migrate命令也是用戶在Redis實(shí)例間進(jìn)行數(shù)據(jù)遷移的寻定,實(shí)際上migrate命令就是將dump、restore精耐、del三個(gè)命令進(jìn)行組合狼速,從而簡(jiǎn)化了操作流程。
整個(gè)過(guò)程如下圖所示卦停,實(shí)現(xiàn)過(guò)程和dump+restore基本類似向胡,但是有3點(diǎn)不太相同:第一,整個(gè)過(guò)程是原子執(zhí)行的惊完,不需要在多個(gè)Redis實(shí)例上開(kāi)啟客戶端的僵芹,只需要在源Redis上執(zhí)行migrate命令即可。第二小槐,migrate命令數(shù)據(jù)傳輸直接在源Redis和目標(biāo)Redis上完成的拇派。第三,目標(biāo)Redis完成restore后會(huì)發(fā)送OK給源Redis凿跳,源Redis接收后會(huì)根據(jù)migrate對(duì)應(yīng)的選項(xiàng)來(lái)決定是否在源Redis上刪除對(duì)應(yīng)的鍵件豌。
下面對(duì)migrate參數(shù)逐個(gè)說(shuō)明:
- host:目標(biāo)Redis的IP地址。
- port:目標(biāo)Redis的端口拄显。
- key|"":在Redis 3.0.6版本之前苟径,migrate只支持遷移一個(gè)鍵,所以此處是要遷移的鍵躬审,但Redis 3.0.6版本之后支持遷移多個(gè)鍵棘街,如果當(dāng)前需要遷移多個(gè)鍵,此處為空字符串""承边。
- destination-db:目標(biāo)Redis的數(shù)據(jù)庫(kù)索引遭殉,例如要遷移到0號(hào)數(shù)據(jù)庫(kù),這里就寫(xiě)0博助。
- timeout:遷移的超時(shí)時(shí)間(單位為毫秒)险污。
- [copy]:如果添加此選項(xiàng),遷移后不刪除源鍵富岳。
- [replace]:如果添加此選項(xiàng)蛔糯,migrate不管目標(biāo)Redis是否存在該鍵都會(huì)正常遷移進(jìn)行數(shù)據(jù)覆蓋。
- [keys key [key ...]]:遷移多個(gè)鍵窖式,例如要遷移key1蚁飒、key2、key3萝喘,此處趕寫(xiě)“keys key1 key2 key3”淮逻。
示例情況1:源Redis有鍵hello琼懊,目標(biāo)Redis沒(méi)有:
//Redis實(shí)例6379上:
127.0.0.1:6379> migrate 127.0.0.1 6380 hello 0 1000
OK
127.0.0.1:6379> get hello
(nil)
//Redis實(shí)例6380上:
127.0.0.1:6380> get hello
"hi, I am nosee."
示例情況2:源Redis和目標(biāo)Redis都有鍵hello:
//Redis實(shí)例6379上:
127.0.0.1:6379> set hello 'I am here.'
OK
127.0.0.1:6379> migrate 127.0.0.1 6380 hello 0 1000
(error) ERR Target instance replied with error: BUSYKEY Target key name already exists.
127.0.0.1:6379> migrate 127.0.0.1 6380 hello 0 1000 replace
OK
//Redis實(shí)例6380上:
127.0.0.1:6380> get hello
"I am here."
示例情況3:源Redis沒(méi)有鍵hello:
127.0.0.1:6379> migrate 127.0.0.1 6380 hello 0 1000
NOKEY
多個(gè)鍵遷移示例:
//Redis實(shí)例6379上:
127.0.0.1:6379> mset key1 aaa key2 bbb key3 ccc
OK
127.0.0.1:6379> migrate 127.0.0.1 6380 "" 0 1000 keys key1 key2 key3
OK
127.0.0.1:6379> mget key1 key2 key3
1) (nil)
2) (nil)
3) (nil)
//Redis實(shí)例6380上:
127.0.0.1:6380> mget key1 key2 key3
1) "aaa"
2) "bbb"
3) "ccc"
三、遍歷鍵
1爬早、全量遍歷鍵
keys pattern
如哼丈,獲取所有的鍵:
127.0.0.1:6380> keys *
1) "key2"
2) "key3"
3) "key1"
4) "hello"
上面例子為了遍歷所有的鍵,pattern直接使用星號(hào)筛严,這是因?yàn)閜attern使用的是glob風(fēng)格的通配符:
- *代表匹配任意字符醉旦。
- ?代表匹配一個(gè)字符。
- []代表匹配部分字符脑漫,例如[1,3]代表匹配1,3髓抑,[1-10]代表匹配1到10的任意數(shù)字。
- \x用來(lái)做轉(zhuǎn)義优幸,例如要匹配星號(hào)吨拍、問(wèn)題需要進(jìn)行轉(zhuǎn)義。
如:
127.0.0.1:6380> keys key?
1) "key2"
2) "key3"
3) "key1"
127.0.0.1:6380> keys key[1,3]
1) "key3"
2) "key1"
當(dāng)需要遍歷所有鍵時(shí)(例如檢測(cè)過(guò)期或閑置時(shí)間网杆、尋找大對(duì)象等)羹饰,keys是一個(gè)不很有幫助的命令,例如想刪除所有video字符串開(kāi)頭的鍵碳却,可以執(zhí)行如下操作:
redis-cli keys video* | xargs redis del
但是如果考慮到Redis的單線程架構(gòu)就不那么美妙了队秩,如果Redis包含了大量的鍵,執(zhí)行keys命令很可能會(huì)造成Redis阻塞昼浦,所以在一般不建議在生產(chǎn)環(huán)境下使用keys命令馍资。但有時(shí)確實(shí)有遍歷鍵的需求該怎么辦,可以在以下三種情況使用:
- 在一個(gè)不對(duì)外提供服務(wù)的Redis從節(jié)點(diǎn)上執(zhí)行关噪,這樣不會(huì)阻塞到客戶端的請(qǐng)求鸟蟹,但是會(huì)影響到主從復(fù)制。
- 如果確認(rèn)鍵值總數(shù)確實(shí)比較少使兔,可以執(zhí)行該命令建钥。
- 使用下面要介紹的scan命令漸進(jìn)式的遍歷所有鍵,可以有效防止阻塞虐沥。
2熊经、漸進(jìn)式遍歷
scan cursor [MATCH pattern] [COUNT count]
- cursor是必需參數(shù),實(shí)際上cursor是個(gè)游標(biāo)欲险,第一次遍歷從0開(kāi)始镐依,每次scan遍歷完都會(huì)返回當(dāng)前游標(biāo)的值,直到游標(biāo)值為0天试,表示遍歷結(jié)束槐壳。
- match pattern是可靠參數(shù),它的作用是做模式的匹配秋秤,這點(diǎn)和keys的模式匹配很像宏粤。
- count number是可選參數(shù),它我作用是要表明每次要遍歷的鍵個(gè)數(shù)灼卢,默認(rèn)值為10绍哎,此參數(shù)可以適當(dāng)增大。
現(xiàn)有一個(gè)Redis有26個(gè)鍵鞋真,現(xiàn)在要遍歷所有鍵崇堰,使用scan命令效果的操作如下。第一次執(zhí)行scan 0
涩咖,返回結(jié)果分為兩個(gè)部分:第一個(gè)部分5是下次scan需要的cursor海诲,第二個(gè)部分是10個(gè)鍵:
127.0.0.1:6380> keys *
1) "key5"
2) "key7"
3) "keyd"
.
.
.
22) "hello" //共22個(gè)鍵
127.0.0.1:6380> scan 0
1) "5"
2) 1) "key5"
2) "key9"
3) "key6"
4) "key2"
5) "key7"
6) "keye"
7) "a1"
8) "keyb"
9) "a4"
10) "key3"
使用新的cursor=5,執(zhí)行scan 5
:
127.0.0.1:6380> scan 5
1) "31"
2) 1) "keyd"
2) "a6"
3) "key1"
4) "a7"
5) "keya"
6) "keyc"
7) "key4"
8) "a2"
9) "a3"
10) "a5"
這次得到的cursor=31檩互,繼續(xù)執(zhí)行scan 31
得到結(jié)果corsor變?yōu)?特幔,說(shuō)明所有的鍵已經(jīng)被遍歷過(guò)了:
127.0.0.1:6380> scan 31
1) "0"
2) 1) "key8"
2) "hello"
除了scan以外,Redis提供了面向哈希類型闸昨、集合類型蚯斯、有序集合的掃描遍歷命令,解決諸如hgetall饵较、smembers拍嵌、zrange可能產(chǎn)生阻塞問(wèn)題,對(duì)應(yīng)的命令分別是hscan循诉、sscan横辆、zscan,它們的用法和scan基本類似茄猫。
四狈蚤、數(shù)據(jù)庫(kù)管理
Redis提供了幾個(gè)面向Redis數(shù)據(jù)庫(kù)的操作,它們分別是dbsize募疮、select炫惩、flushdb/flushall命令。
1阿浓、切換數(shù)據(jù)庫(kù)
select dbIndex
許多關(guān)系型數(shù)據(jù)庫(kù)他嚷,例如MySQL支持在一個(gè)實(shí)例下有多個(gè)數(shù)據(jù)庫(kù)存在的,但是與關(guān)系型數(shù)據(jù)庫(kù)用字符來(lái)區(qū)分不同數(shù)據(jù)庫(kù)名不同芭毙,Redis只是用數(shù)字作為多個(gè)數(shù)據(jù)庫(kù)的實(shí)現(xiàn)筋蓖。Redis默認(rèn)配置中是有16個(gè)數(shù)據(jù)庫(kù)的,不同數(shù)據(jù)庫(kù)之間的數(shù)據(jù)沒(méi)有任何關(guān)聯(lián)退敦,甚至可以存在相同的鍵粘咖。
127.0.0.1:6380> get hello # 默認(rèn)進(jìn)到的是0號(hào)數(shù)據(jù)庫(kù)
"I am here."
127.0.0.1:6380> select 15 # 切換到15號(hào)數(shù)據(jù)庫(kù)
OK
127.0.0.1:6380[15]> get hello # 15號(hào)數(shù)據(jù)庫(kù)沒(méi)有設(shè)置hello
(nil)
Redis默認(rèn)使用的就是0號(hào)數(shù)據(jù)庫(kù),當(dāng)選擇其它數(shù)據(jù)庫(kù)時(shí)會(huì)有[index]的前綴標(biāo)識(shí)侈百,其中index就是數(shù)據(jù)庫(kù)的索引下標(biāo)瓮下。
注意:該功能目前版本已經(jīng)被逐漸弱化翰铡。
2、flushdb/flushall
flushdb/flushall命令用于清除數(shù)據(jù)庫(kù)讽坏,兩者的區(qū)別是flushdb只清除當(dāng)前數(shù)據(jù)庫(kù)锭魔,flushall會(huì)清除所有數(shù)據(jù)庫(kù)。
flushdb/flushall命令可以非常方便的清除數(shù)據(jù)路呜,但是也帶來(lái)兩個(gè)問(wèn)題:
- flushdb/flushall命令會(huì)將所有數(shù)據(jù)清除迷捧,一旦誤操作后果不堪設(shè)想,后面會(huì)介紹rename-command配置規(guī)避這個(gè)問(wèn)題胀葱,以及如何在誤操作后快速恢復(fù)數(shù)據(jù)漠秋。
- 如果當(dāng)前數(shù)據(jù)鍵值數(shù)量比較多,flushdb/flushall存在阻塞Redis的可能性抵屿。
所以在使用flushdb/flushall 時(shí)一定要小心謹(jǐn)慎庆锦。
參考:
《Redis開(kāi)發(fā)與運(yùn)維》 付磊 & 張益軍