筆記來(lái)自:《redis開(kāi)發(fā)與維護(hù)》第二章 API的理解和使用
主要內(nèi)容:全局命令、鍵管理涧团、遍歷鍵、數(shù)據(jù)庫(kù)管理
全局命令
操作 | 命令 |
---|---|
查看所有鍵 | keys * |
鍵總數(shù) | dbsize |
檢查鍵是否存在 | exists key |
刪除建 | del key [key ...] |
鍵過(guò)期 | expire key seconds |
鍵的數(shù)據(jù)結(jié)構(gòu)類(lèi)型 | type key |
1. 查看所有鍵 -- keys *
H:\Redis>redis-cli.exe -h 127.0.0.1 -p 6379
127.0.0.1:6379> get hell
(nil)
127.0.0.1:6379> get hello
"world"
127.0.0.1:6379> set java jedis
OK
127.0.0.1:6379> set python redis-py
OK
127.0.0.1:6379> keys *
1) "python"
2) "java"
3) "hello"
2. 鍵總數(shù) -- dbsize
127.0.0.1:6379> rpush mylist a b c d e f g
(integer) 7
127.0.0.1:6379> dbsize
(integer) 4
3. 檢查鍵是否存在 -- exists key
存在掐隐,返回1窥淆,不存,返回0
127.0.0.1:6379> exists java
(integer) 1
127.0.0.1:6379> exists no_exits_key
(integer) 0
4. 刪除鍵 -- del key [key ...]
刪除成功后滤灯,返回刪除個(gè)數(shù)
127.0.0.1:6379> keys *
1) "python"
2) "mylist"
3) "java"
4) "hello"
127.0.0.1:6379> del python java
(integer) 2
127.0.0.1:6379> keys *
1) "mylist"
2) "hello"
5. 鍵過(guò)期 -- expire key seconds
127.0.0.1:6379> expire mylist 10
(integer) 1
127.0.0.1:6379> ttl mylist
(integer) 3
127.0.0.1:6379> ttl mylist
(integer) -2
127.0.0.1:6379> exists mylist
(integer) 0
ttl 命令返回鍵剩余的過(guò)期時(shí)間坪稽,有三種返回值:
- 大于等于0的整數(shù):鍵剩余的過(guò)期時(shí)間
- -1: 鍵設(shè)置過(guò)期時(shí)間
- -2: 鍵不存在
6. 鍵的數(shù)據(jù)結(jié)構(gòu)類(lèi)型 -- type key
127.0.0.1:6379> set a b
OK
127.0.0.1:6379> rpush mylist a b c d e f g
(integer) 7
127.0.0.1:6379> type mylist
list
127.0.0.1:6379> type a
string
2. 數(shù)據(jù)結(jié)構(gòu)和內(nèi)部編碼
redis每種數(shù)據(jù)結(jié)構(gòu)都有兩種以上自己底層的內(nèi)部編碼實(shí)現(xiàn)
查詢(xún)內(nèi)部編碼命令:object encoding
127.0.0.1:6379> object encoding hello
"embstr"
127.0.0.1:6379> rpush mylist a b c d e f g
(integer) 7
127.0.0.1:6379> object encoding mylist
"quicklist"
優(yōu)點(diǎn):
1. 改進(jìn)內(nèi)部編碼,對(duì)外部的數(shù)據(jù)結(jié)構(gòu)命令沒(méi)影響
2. 多種內(nèi)部編碼實(shí)現(xiàn)可以在不同場(chǎng)景下各自發(fā)揮
3.單線程架構(gòu);
redis 使用單線程架構(gòu)
和I/O多路復(fù)用模型
來(lái)實(shí)現(xiàn)高性能的內(nèi)存數(shù)據(jù)庫(kù)服務(wù)鳞骤。
引出 單線程模型
開(kāi)啟3個(gè)redis-cli客戶端同時(shí)執(zhí)行命令窒百,每個(gè)客戶端都會(huì)執(zhí)行3個(gè)步驟:發(fā)送命令、執(zhí)行命令豫尽、返回結(jié)果三個(gè)過(guò)程
所有命令到服務(wù)端會(huì)進(jìn)入一個(gè)隊(duì)列篙梢,然后被執(zhí)行
為什么單線程還能這么快
存內(nèi)存訪問(wèn),redis將所有數(shù)據(jù)存放內(nèi)存中
非阻塞I/O,
避免切換和競(jìng)爭(zhēng)產(chǎn)生的消耗
鍵管理
一美旧、單個(gè)鍵管理
1. 鍵重命名 -- rename key newkey
127.0.0.1:6379> get a
"1"
127.0.0.1:6379> rename a keya
OK
127.0.0.1:6379> get keya
"1"
127.0.0.1:6379> get a
(nil)
情況1: 如果b存在渤滞,則b鍵的值也會(huì)被覆蓋
127.0.0.1:6379> rename keya b
OK
127.0.0.1:6379> get b
"1"
127.0.0.1:6379> get keya
(nil)
情況2: 重命名不存鍵 b ,鍵返回錯(cuò)誤
127.0.0.1:6379> get b
(nil)
127.0.0.1:6379> get keya
"1"
127.0.0.1:6379> renamenx b keya
(error) ERR no such key
注意:
重命名鍵期間會(huì)執(zhí)行del命令刪除舊的鍵贬墩,如果鍵對(duì)應(yīng)的值比較大,會(huì)存在阻塞的可能性
-
rename和renamenx 的key 和 value 一樣妄呕,redis 3.2 和之前的版本返回結(jié)果不同
redis3.2版本返回ok,之前的會(huì)報(bào)錯(cuò) 127.0.0.1:6379> rename keya keya OK 127.0.0.1:6379> get keya "1"
2.隨機(jī)返回一個(gè)鍵 -- randomkey
127.0.0.1:6379> dbsize
(integer) 36
127.0.0.1:6379> randomkey
"user:1_2:tags"
127.0.0.1:6379> randomkey
"mylist"
3.鍵過(guò)期 -- expire key seconds/expireat key timestamp
ttl 返回 -1 鍵沒(méi)有設(shè)置過(guò)期時(shí)間
返回-2 鍵不存
127.0.0.1:6379> expire d 10
(integer) 1
127.0.0.1:6379> ttl d
(integer) 7
127.0.0.1:6379> ttl d
(integer) 3
127.0.0.1:6379> ttl d
(integer) 0
127.0.0.1:6379> ttl d
(integer) -2
127.0.0.1:6379> get d
(nil)
expireat key timestamp 鍵在秒級(jí)時(shí)間錯(cuò)過(guò)期
2019-02-13 23:43:30 時(shí)間戳 1550072610
127.0.0.1:6379> expireat c 1550072610
(integer) 1
127.0.0.1:6379> ttl c
(integer) 23
127.0.0.1:6379> ttl c
(integer) 21
127.0.0.1:6379> ttl c
(integer) -2
127.0.0.1:6379> get c
(nil)
注意:
- expire key不存在陶舞,返回0
127.0.0.1:6379> expire no_exist_key 10
(integer) 0
127.0.0.1:6379> get no_exist_key
(nil)
- 過(guò)期時(shí)間負(fù)值,鍵立即被刪除
127.0.0.1:6379> expire keya -5
(integer) 1
127.0.0.1:6379> get keya
(nil)
- persist 命名可以將過(guò)期時(shí)間清除
127.0.0.1:6379> expire keya 30
(integer) 1
127.0.0.1:6379> ttl keya
(integer) 25
127.0.0.1:6379> persist keya
(integer) 1
127.0.0.1:6379> ttl keya
(integer) -1
- set 命令會(huì)將設(shè)置的過(guò)期時(shí)間清除掉
127.0.0.1:6379> set hi world
OK
127.0.0.1:6379> expire hi 30
(integer) 1
127.0.0.1:6379> ttl hi
(integer) 24
127.0.0.1:6379> set hi 10
OK
127.0.0.1:6379
- redis 不支持二級(jí)數(shù)據(jù)結(jié)構(gòu)的過(guò)期時(shí)間設(shè)置绪励,比如哈希肿孵、列表內(nèi)元素的過(guò)期設(shè)置
- setex命令 為set + expire 組合,具有原子性疏魏,同時(shí)減少一次網(wǎng)絡(luò)時(shí)間
4. 遷移鍵 -- move\dump + restore\migrate
三個(gè)命令比較
命令 | 作用域 | 原子性 | 支持多個(gè)建 |
---|---|---|---|
move | redis示例內(nèi)部 | 是 | 否 |
dump + restore | redis示例之間 | 否 | 否 |
migrate (推薦) | redis示例之間 | 是 | 是 |
(1)nove key db
指定的鍵從源數(shù)據(jù)庫(kù)遷移到目標(biāo)數(shù)據(jù)庫(kù)中停做,但多數(shù)據(jù)庫(kù)功能不建議在生產(chǎn)環(huán)境中使用,所以這個(gè)命令知道就可以
(2)dump + restore
dump key
restore key ttl value
實(shí)現(xiàn)redis實(shí)例之間遷移功能蠢护,分2步驟:
- 在源redis上dump命令雅宾,將鍵值序列化,格式:RDB格式
- 在目標(biāo)redis上葵硕,restore命令將上面序列化的值進(jìn)行復(fù)原眉抬,其中ttl參數(shù)代表過(guò)期時(shí)間,ttl=0表示沒(méi)有過(guò)期時(shí)間
示例:
- redis-6380 新添key6380 , redis-6379 并不存該key
127.0.0.1:6380> set key6380 hi6380
OK
127.0.0.1:6379> get key6380
(nil)
- redis-6380 執(zhí)行dump命令懈凹,將key6380的值進(jìn)行序列化
127.0.0.1:6380> dump key6380
"\x00\x06hi6380\a\x00\x88%\xa4k\xa2\xc7\x97n"
- redis-6379執(zhí)行restore命令蜀变,將key6380的值進(jìn)行反序列化,保存到內(nèi)存中
127.0.0.1:6379> restore key6380 0 "\x00\x06hi6380\a\x00\x88%\xa4k\xa2\xc7\x97n"
OK
127.0.0.1:6379> get key6380
"hi6380"
注意:
- 整個(gè)過(guò)程不是原子性的介评,是通過(guò)客戶端分步完成的
- 開(kāi)啟兩個(gè)客戶端库北,所以dump的結(jié)果不是在源redis和目標(biāo)redis之間進(jìn)行傳輸
(3)migrate
migrate host port key|"" destination-db timeout [COPY] [REPLACE] [KEYS key]
參數(shù)說(shuō)明:
host : 目標(biāo)redis IP地址
port :目標(biāo)redis 端口
key|"" :遷移的鍵,“”代表 多個(gè)遷移鍵
destination-db :目標(biāo)redis的數(shù)據(jù)庫(kù)索引们陆,默認(rèn)是0
timeout :超時(shí)時(shí)間
[COPY] :添加的話寒瓦,不會(huì)刪除源redis鍵
[REPLACE]:如果目標(biāo)redis存在遷移鍵,則會(huì)遷移覆蓋數(shù)據(jù)
[KEYS key]:遷移多個(gè)鍵
用于redis實(shí)例之間進(jìn)行數(shù)據(jù)遷移,
dump坪仇、restore杂腰、del 三個(gè)命令組合,簡(jiǎn)化操作流程
3點(diǎn)不太相同:
- 整個(gè)過(guò)程是
原子
執(zhí)行椅文,只需在源redis
上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)的鍵
示例:
- 情況 源redis有 鍵key6379 喂很,目標(biāo)redis沒(méi)有
127.0.0.1:6379> migrate 127.0.0.1 6380 key6379 0 2000 copy replace
OK
- 源redis和目標(biāo)redis都有鍵key6379, 如果migrate 沒(méi)加replace參數(shù),則會(huì)報(bào)錯(cuò)
127.0.0.1:6379> migrate 127.0.0.1 6380 key6379 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 key6379 0 1000 replace
OK
- 源redis沒(méi)有遷移鍵key6381,則返回nokey
127.0.0.1:6379> migrate 127.0.0.1 6380 key6381 0 1000
NOKEY
遍歷鍵
1. 全量遍歷鍵 -- keys pattern
pattern 通配符:
- “*”:任意字符
- 皆刺?:一個(gè)字符
- [] : 部分字符少辣,[1,3] 代表匹配1,3
- \x : 用來(lái)做轉(zhuǎn)義
示例:
- 查找user開(kāi)頭的鍵
127.0.0.1:6379> keys user*
1) "user:2:tags"
2) "user:ranking:1"
3) "user:ranking:2"
4) "user:1:follow"
...
- 查找含tag的鍵
127.0.0.1:6379> keys *tags*
1) "user:2:tags"
2) "user:3:tags"
3) "user:1_2:tags"
4) "user:1:tags"
如果redis包含大量的鍵,keys命令可能會(huì)造成redis阻塞羡蛾,所以一般不要在生產(chǎn)環(huán)境中使用keys命令漓帅,以下三種情況使用:
- 在一個(gè)
不對(duì)外提供服務(wù)的
redis從節(jié)點(diǎn)上執(zhí)行 - 如果確認(rèn)鍵值總數(shù)較少,可以執(zhí)行該命令
- 使用scan漸進(jìn)式遍歷所有鍵,有效阻止阻塞
2.漸進(jìn)式遍歷 -- scan cursor [MATCH pattern] [COUNT count]
scan命令 采取漸進(jìn)式遍歷方式解決keys的阻塞問(wèn)題
時(shí)間復(fù)雜度為O(1),reids存儲(chǔ)鍵值對(duì)實(shí)際是用hashtable數(shù)據(jù)結(jié)構(gòu)
scan的使用方式如下:
scan cursor [MATCH pattern] [COUNT count]
參數(shù):
- cursor 必填參數(shù) 忙干,一個(gè)游標(biāo)屯伞,第一次遍歷時(shí)從0開(kāi)始,每次遍歷完返回當(dāng)前游標(biāo)值直到游標(biāo)值為0, 表示遍歷結(jié)束
- [MATCH pattern] 可選參數(shù)豪直,作用:做模式匹配,跟keys相似
- [COUNT count] 可選參數(shù)珠移,表示每次遍歷的鍵個(gè)數(shù)弓乙,默認(rèn)值為0
示例:
- 遍歷但是redis6379所有鍵
127.0.0.1:6379> scan 6
1) "41"
2) 1) "user:2:follow"
2) "article:2"
3) "user:1_2:union"
4) "user:3:tags"
5) "hashkey"
6) "user:ranking:1_union_2"
7) "listkey"
8) "user:ranking:1_inter_2"
9) "user:ranking:1"
10) "setkey"
11) "user:ranking:2"
127.0.0.1:6379> scan 41
1) "27"
2) 1) "myset"
2) "user:ranking"
3) "article:3"
4) "tag1:users"
5) "hashkey1"
6) "user:1_2:tags"
7) "lishkey"
8) "list:test3"
9) "testkey"
10) "user:1"
127.0.0.1:6379> scan 27
1) "0"
2) 1) "user:1:tags"
2) "article:1"
3) "user:ranking:20190210"
如果scan過(guò)程中如有有鍵變化(增加、刪除钧惧、修改)暇韧,那么遍歷可能會(huì)出問(wèn)題:新的鍵沒(méi)遍歷到,遍歷出了重復(fù)的鍵等情況
數(shù)據(jù)庫(kù)管理
1.切換數(shù)據(jù)庫(kù) -- select index
redis只是用數(shù)字
作為多個(gè)數(shù)據(jù)庫(kù)的實(shí)現(xiàn)浓瞪,redis默認(rèn)中是16
個(gè)數(shù)據(jù)庫(kù)
databases 16
0-15號(hào)數(shù)據(jù)庫(kù)之間是沒(méi)有任何聯(lián)系懈玻,甚至可以存在相同的鍵
127.0.0.1:6379> get hello
"word"
127.0.0.1:6379> select 15 # 15號(hào)切換數(shù)據(jù)庫(kù)
OK
127.0.0.1:6379[15]> get hello
(nil)
如果使用多個(gè)數(shù)據(jù)庫(kù)功能,可以一臺(tái)機(jī)器上部署多個(gè)redis實(shí)例乾颁,然后用端口來(lái)劃分涂乌,因?yàn)楝F(xiàn)在服務(wù)器是多個(gè)cpu的,保證了業(yè)務(wù)不受到影響英岭,合理使用cpu資源
2.清楚數(shù)據(jù)庫(kù)--flushdb/flushall
兩者區(qū)別:flushdb只清除當(dāng)前數(shù)據(jù)湾盒,flushall會(huì)清除所有數(shù)據(jù)庫(kù)
127.0.0.1:6379[15]> set hello world15
OK
127.0.0.1:6379[15]> keys hello
1) "hello"
127.0.0.1:6379[15]> flushdb
OK
127.0.0.1:6379[15]> keys
(error) ERR wrong number of arguments for 'keys' command
# 切到0號(hào)數(shù)據(jù)庫(kù),還是有數(shù)據(jù)
127.0.0.1:6379[15]> select 0
OK
127.0.0.1:6379> get hello
"word"
flushall 清除所有數(shù)據(jù)庫(kù)
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> keys *
(empty list or set)
flushdb/flushall會(huì)將所有數(shù)據(jù)清除诅妹,一旦誤操作后果不堪設(shè)想
如果數(shù)據(jù)庫(kù)鍵值數(shù)量比較多罚勾,存在阻塞redis可能性,一定要小謹(jǐn)慎使用
--END--
創(chuàng)作不易,覺(jué)得不錯(cuò)的話,歡迎關(guān)注吭狡、點(diǎn)贊??或掌賞尖殃!