全局命令
-
查看所有鍵
keys *
下面插入了3對(duì)字符串類型的鍵值對(duì):
127.0.0.1:6379> set hello world OK 127.0.0.1:6379> set java jedis OK 127.0.0.1:6379> set python redis-py OKkey *命令會(huì)將所有的鍵輸出:
127.0.0.1:6379> key * 1) "python" 2) "java" 3) "hello" -
鍵總數(shù)
dbsize
下面插入一個(gè)列表類型的鍵值對(duì)(值是多個(gè)元素組成):
127.0.0.1:6379> rpush mylist a b c d e f g (integer) 7dbsize 命令會(huì)返回當(dāng)前數(shù)據(jù)庫(kù)中鍵的總數(shù)。例如當(dāng)前數(shù)據(jù)庫(kù)有4個(gè)鍵,分別是
hello、java、python、mylist,所以dbsize的結(jié)果是4:127.0.0.1:6379> dbsize (integer) 4dbsize命令在計(jì)算鍵總數(shù)時(shí)不會(huì)遍歷所有的鍵,而是直接獲取Redis內(nèi)置的鍵總
數(shù)變量,所以dbsize命令的時(shí)間復(fù)雜度是O(1)。而keys命令會(huì)遍歷所有鍵,所
以它的時(shí)間復(fù)雜度是O(n),當(dāng)Redis保存了大量鍵時(shí),線上環(huán)境禁止使用。 -
檢查鍵是否存在
exists key
如果鍵存在則返回1,不存在則返回0:
127.0.0.1:6379> exists java (integer) 1 127.0.0.1:6379> exists not_exists_key (integer) 0 -
刪除鍵
del key [key ...]
del是一個(gè)通用命令,無(wú)論值是什么數(shù)據(jù)結(jié)構(gòu)類型,del命令都可以將其刪除,
例如下面將字符串類型的鍵java和列表類型的鍵mylist分別刪除:127.0.0.1:6379> del java (integer) 1 127.0.0.1:6379> exists java (integer) 0 127.0.0.1:6379> del mylist (integer) 1 127.0.0.1:6379> exists mylist (integer) 0返回結(jié)果為成功刪除鍵的個(gè)數(shù),假設(shè)刪除一個(gè)不存在的鍵,就會(huì)返回0:
127.0.0.1:6379> del not_exists_key (integer) 0同時(shí)del命令可以支持刪除多個(gè)鍵:
127.0.0.1:6379> set a 1 OK 127.0.0.1:6379> set b 2 OK 127.0.0.1:6379> set c 3 OK 127.0.0.1:6379> del a b c (integer) 3 -
鍵過(guò)期
expire key seconds
Redis支持對(duì)鍵添加過(guò)期時(shí)間,當(dāng)超過(guò)過(guò)期時(shí)間后,會(huì)自動(dòng)刪除鍵,例如為鍵
hello設(shè)置了10秒過(guò)期時(shí)間:127.0.0.1:6379> set hello world OK 127.0.0.1:6379> expire hello 10 (integer) 1ttl命令返回鍵的生育過(guò)期時(shí)間,它有3中返回值:
- 大于等于0的整數(shù):鍵剩余的過(guò)期時(shí)間。
- -1:鍵沒(méi)設(shè)置過(guò)期時(shí)間。
- -2:鍵不存在
可以通過(guò)ttl命令觀察鍵hello的剩余過(guò)期時(shí)間:
# 還剩7秒 127.0.0.1:6379> ttl hello (integer) 7 ... # 還剩1秒 127.0.0.1:6379> ttl hello (integer) 1 # 返回結(jié)果為-2,說(shuō)明鍵hello已經(jīng)被刪除 127.0.0.1:6379> ttl hello (integer) -2 127.0.0.1:6379> get hello (nil) -
鍵的數(shù)據(jù)結(jié)構(gòu)類型
type key
例如鍵hello是字符串類型,返回結(jié)果為string。鍵mylist是列表類型,返回
結(jié)果為list:127.0.0.1:6379> set a b OK 127.0.0.1:6379> type a string 127.0.0.1:6379> rpush mylist a b c d e f g (integer) 7 127.0.0.1:6379> type mylist list如果鍵不存在,則返回none:
127.0.0.1:6379> type not_exists_key none
數(shù)據(jù)結(jié)構(gòu)和內(nèi)部編碼
-
數(shù)據(jù)結(jié)構(gòu)和內(nèi)部編碼
type命令實(shí)際返回的就是當(dāng)前鍵的數(shù)據(jù)結(jié)構(gòu)類型,他們分別是:string(字符
串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合),但
這些只是Redis 對(duì)外的數(shù)據(jù)結(jié)構(gòu)。實(shí)際上每種數(shù)據(jù)結(jié)構(gòu)都有自己底層的內(nèi)部編碼實(shí)現(xiàn),而且是多種實(shí)現(xiàn)。
2019-03-27-23-59-27.png可以看到每種數(shù)據(jù)結(jié)構(gòu)都有兩種以上的內(nèi)部編碼實(shí)現(xiàn),可以通過(guò)
object encoding命令查詢內(nèi)部編碼:127.0.0.1:6379> object encoding hello "embstr" 127.0.0.1:6379> object encoding mylist "ziplist"可以看到鍵hello對(duì)應(yīng)值的內(nèi)部編碼是embstr,鍵mylist對(duì)應(yīng)值的內(nèi)部編碼
是:ziplist。Redis這樣設(shè)計(jì)有兩個(gè)有好處:第一,可以改進(jìn)內(nèi)部編碼,而對(duì)外的數(shù)據(jù)結(jié)構(gòu)和
命令沒(méi)有影響,這樣一旦開(kāi)發(fā)出更優(yōu)秀的內(nèi)部編碼,無(wú)需改動(dòng)外部數(shù)據(jù)結(jié)構(gòu)和
命令,例如Redis3.2提供了quicklist,結(jié)合了ziplist和linkedlist兩者的
優(yōu)勢(shì),而列表類型提供了一種更為優(yōu)秀的內(nèi)部編碼實(shí)現(xiàn),而對(duì)外部用戶來(lái)說(shuō)基本
感知不到。第二,多種內(nèi)部編碼實(shí)現(xiàn)可以在不同場(chǎng)景下發(fā)揮各自優(yōu)勢(shì),例如
ziplist比較省內(nèi)存,但是在列表元素比較多的情況下,性能會(huì)有所下降,這時(shí)
候Redis會(huì)根據(jù)配置選項(xiàng)將列表類型的內(nèi)部實(shí)現(xiàn)轉(zhuǎn)換為linkedlist。
單線程架構(gòu)
-
引出單線程模型
現(xiàn)在開(kāi)啟了三個(gè)redis-cli客戶端同事執(zhí)行命令。
客戶端1設(shè)置一個(gè)字符串鍵值對(duì):127.0.0.1:6379> set hello world客戶端2對(duì)counter做自增操作:
127.0.0.1:6379> incr counter客戶端3對(duì)counter做自增操作:
127.0.0.1:6379> incr counterRedis每次客戶端調(diào)用都經(jīng)歷了發(fā)送命令、執(zhí)行命令、返回結(jié)果三個(gè)過(guò)程。
其中第2步是重點(diǎn)研究的,因?yàn)镽edis是單線程來(lái)處理命令的,所以一條命令從
客戶端達(dá)到服務(wù)端不會(huì)立刻被執(zhí)行,所有命令都會(huì)進(jìn)入一個(gè)隊(duì)列中,然后逐個(gè)
被執(zhí)行。所以上面3個(gè)客服端命令執(zhí)行順序是不確定的,但是可以確定不會(huì)有
兩條命令同時(shí)被執(zhí)行,所以兩條incr命令無(wú)論怎么執(zhí)行最終結(jié)果都是2,不會(huì)產(chǎn)
生并發(fā)問(wèn)題,這就是Redis單線程的基礎(chǔ)模型。但是像發(fā)送命令、返回結(jié)果、命
令排隊(duì)肯定不像描述的這么簡(jiǎn)單,Redis使用I/O多路復(fù)用技術(shù)解決I/O問(wèn)題。 -
為什么單線程還能這么快
通常來(lái)講,單線程處理能力要比多線程差,Redis使用單線程模型會(huì)達(dá)到每秒萬(wàn)
級(jí)別的處理能力原因有三點(diǎn):純內(nèi)存訪問(wèn),Redis將所有數(shù)據(jù)放在內(nèi)存中,內(nèi)存的響應(yīng)時(shí)長(zhǎng)大約為100納
秒,這是Redis達(dá)到每秒萬(wàn)級(jí)別訪問(wèn)的重要基礎(chǔ)。非阻塞I/O,Redis使用epoll作為I/O多路復(fù)用技術(shù)的實(shí)現(xiàn),再加上Redis
自身的事件處理模型將epoll中的連接、讀寫(xiě)、關(guān)閉都轉(zhuǎn)換為時(shí)間,不在網(wǎng)絡(luò)
I/O上浪費(fèi)過(guò)多的時(shí)間。單線程避免了線程切換和競(jìng)態(tài)產(chǎn)生的消耗。既然采用單線程就能達(dá)到如此高
的性能,那么也不失為一種不錯(cuò)的選擇,因?yàn)閱尉€程能帶來(lái)幾個(gè)好處:第一,單
線程可以簡(jiǎn)化數(shù)據(jù)結(jié)構(gòu)和算法的實(shí)現(xiàn)。如果對(duì)高級(jí)編程語(yǔ)言熟悉的讀者應(yīng)該了解
并發(fā)數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)不但困難而且開(kāi)發(fā)測(cè)試比較麻煩。第二,單線程避免了線程切
換和競(jìng)態(tài)產(chǎn)生的消耗,對(duì)于服務(wù)端開(kāi)發(fā)來(lái)說(shuō),鎖和線程切換通常是性能殺手。
但是單線程會(huì)有一個(gè)問(wèn)題:對(duì)于每個(gè)命令的執(zhí)行時(shí)間是有要求的。如果某個(gè)命令
時(shí)間執(zhí)行過(guò)長(zhǎng),會(huì)造成其他命令的阻塞,對(duì)于Redis這種高性能的服務(wù)來(lái)說(shuō)是致
命的,所以Redis是面向快速執(zhí)行場(chǎng)景的數(shù)據(jù)庫(kù)。
