电竞比分网-中国电竞赛事及体育赛事平台

分享

【Redis15】Redis基礎(chǔ):通用命令(二)

 硬核項(xiàng)目經(jīng)理 2023-04-24 發(fā)布于湖南

Redis基礎(chǔ)學(xué)習(xí):通用命令(二)

今天我們繼續(xù)學(xué)習(xí) Redis 剩余的一些通用命令。這些命令也都是非常簡(jiǎn)單的命令,而且更重要的是,今天的內(nèi)容是我們基礎(chǔ)部分的最后一篇了哦,大家可要卯足精神堅(jiān)持學(xué)完啦。

數(shù)據(jù)類型查看

要查看一個(gè) KEY 的數(shù)據(jù)類型直接使用 TYPE 命令就可以,我們就以五大基礎(chǔ)數(shù)據(jù)類型為例。

127.0.0.1:6379> SET a 123
OK
127.0.0.1:6379> LPUSH b a b c d
(integer) 4
127.0.0.1:6379> hmset c name zy age 18
OK
127.0.0.1:6379> ZADD d 1 a 2 b 3 c
(integer) 3
127.0.0.1:6379> SADD e a b c
(integer) 3

127.0.0.1:6379> TYPE a
string
127.0.0.1:6379> TYPE b
list
127.0.0.1:6379> TYPE c
hash
127.0.0.1:6379> TYPE d
zset
127.0.0.1:6379> TYPE e
set

還記得之前講過(guò)的 Bitmap、HyperLogLog、GEO 之類的類型或功能嗎?現(xiàn)在你可以試試用 TYPE 命令看看它們本質(zhì)上都是屬于哪種類型。

真正的內(nèi)部類型對(duì)象及調(diào)試

上面使用 TYPE 看到的只是基本的數(shù)據(jù)類型,但其實(shí)在 Redis 的內(nèi)部,不同的數(shù)據(jù)類型還有更深層次的優(yōu)化。我們把每一個(gè) KEY 都看成是一個(gè)類型對(duì)象,就和在編程語(yǔ)言中的對(duì)象一樣。不同類型的 KEY 對(duì)象在使用的時(shí)候會(huì)根據(jù)條件再次選取不同類型的數(shù)據(jù)結(jié)構(gòu)。這些內(nèi)容,我們可以通過(guò) OBJECT 相關(guān)的命令看到,它是一個(gè)復(fù)合命令,包含下面這些子命令。

127.0.0.1:6379> OBJECT HELP
 1) OBJECT <subcommand> [<arg> [value] [opt] ...]. Subcommands are:
 2) ENCODING <key>
 3)     Return the kind of internal representation used in order to store the value
 4)     associated with a <key>.
 5) FREQ <key>
 6)     Return the access frequency index of the <key>. The returned integer is
 7)     proportional to the logarithm of the recent access frequency of the key.
 8) IDLETIME <key>
 9)     Return the idle time of the <key>, that is the approximated number of
10)     seconds elapsed since the last access to the key.
11) REFCOUNT <key>
12)     Return the number of references of the value associated with the specified
13)     <key>.
14) HELP
15)     Prints this help.

OBJECT ENCODING

首先來(lái)看到的就是如何查看某個(gè)數(shù)據(jù)類型的真實(shí)數(shù)據(jù)存儲(chǔ)結(jié)構(gòu),使用的就是 OBJECT ENCODING 這個(gè)命令。從字面意思也可以看出,它是獲得對(duì)象的編碼類型。

127.0.0.1:6379> OBJECT ENCODING a
"int"
127.0.0.1:6379> OBJECT ENCODING b
"quicklist"
127.0.0.1:6379> OBJECT ENCODING c
"ziplist"
127.0.0.1:6379> OBJECT ENCODING d
"ziplist"
127.0.0.1:6379> OBJECT ENCODING e
"hashtable"

這都是個(gè)啥?別怕,官網(wǎng)文檔中有解釋。

  • 字符串可以被編碼為 raw (常規(guī)字符串) 或者int (用字符串表示64位無(wú)符號(hào)整數(shù)這種編碼方式是為了節(jié)省空間)。
  • 列表類型可以被編碼為ziplist 或者 linkedlist。ziplist 是為了節(jié)省較小的列表空間而設(shè)計(jì)的一種特殊編碼方式。
  • 集合被編碼為 intset 或者 hashtable。 intset 是為了存儲(chǔ)數(shù)據(jù)的較小集合而設(shè)計(jì)的一種特殊編碼方式。
  • 哈希表可以被編碼為 zipmap 或者h(yuǎn)ashtable。zipmap 是專為了較小的哈希表而設(shè)計(jì)的一種特殊編碼方式。
  • 有序集合被編碼為ziplist 或者 skiplist 格式。ziplist可以表示較小的有序集合, skiplist 表示任意大小的有序集合。

其實(shí)呀,就是如果某個(gè) Key 在數(shù)據(jù)量較小的情況下,會(huì)使用某一種數(shù)據(jù)結(jié)構(gòu),而內(nèi)部的數(shù)量量大的時(shí)候會(huì)使用另一種數(shù)據(jù)結(jié)構(gòu)。比如說(shuō)普通字符串是 raw ,但如果你這個(gè) KEY 中只是數(shù)字的話,那么它會(huì)使用 int 類型來(lái)保存。同樣的,較小的 LIST 會(huì)使用 ziplist ,而當(dāng)數(shù)據(jù)項(xiàng)超過(guò)一定數(shù)量或者某個(gè)數(shù)據(jù)項(xiàng)的內(nèi)容長(zhǎng)度非常大時(shí),就會(huì)變成 linkedlist 。這個(gè) linkedlist 大家應(yīng)該不陌生吧,就是鏈表的意思。所以 LIST 在頭尾插入和刪除的時(shí)候能達(dá)到 O(1) 的速度。

不過(guò)我們這里顯示出來(lái)的 LIST 的數(shù)據(jù)結(jié)構(gòu)是 quicklist ,它是 Redis3.2 引入的數(shù)據(jù)結(jié)構(gòu),是結(jié)合了 ziplist 和 linkedlist 的一種快速鏈表?,F(xiàn)在默認(rèn)情況下 LIST 都是使用 quicklist 這種結(jié)構(gòu)了。

光說(shuō)不練假把式,注意看上面的 c 這個(gè) Hash 的類型是 ziplist ,我們直接給它增加一個(gè)內(nèi)容比較長(zhǎng)的 field ,看看它的數(shù)據(jù)結(jié)構(gòu)會(huì)不會(huì)發(fā)生改變。

127.0.0.1:6379> hmset c test abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxy
OK
127.0.0.1:6379> OBJECT ENCODING c
"hashtable"

怎么樣,是不是發(fā)生變化了,一般來(lái)說(shuō),集合中超過(guò)多少個(gè)元素,或者某一個(gè)元素的內(nèi)容長(zhǎng)度大于多少個(gè)字節(jié),就無(wú)法使用 ziplist 這種數(shù)據(jù)結(jié)構(gòu)了。大家可以自己再拿 Set 或者 Sorted Set 試下哦。具體的內(nèi)容我們將在進(jìn)階系列的文章中再進(jìn)行深入的學(xué)習(xí)。

OBJECT REFCOUNT

Redis 為了節(jié)省內(nèi)存會(huì)在初始化服務(wù)器時(shí),創(chuàng)建一萬(wàn)個(gè)字符串對(duì)象,這些對(duì)象包含了1到9999的所有整數(shù)值,當(dāng)服務(wù)器需要用到值為0到9999的字符串對(duì)象時(shí),服務(wù)器就會(huì)使用這些共享對(duì)象,而不是創(chuàng)建新的對(duì)象

127.0.0.1:6379> set a 9999
OK
127.0.0.1:6379> set b1 100000
OK
127.0.0.1:6379> OBJECT REFCOUNT a
(integer) 2147483647
127.0.0.1:6379> OBJECT REFCOUNT b1
(integer) 1

OBJECT REFCOUNT 就是用來(lái)查看對(duì)象的線上服務(wù)情況的,它只對(duì)value >= 0 && value < OBJ_SHARED_INTEGERS 的數(shù)值類對(duì)象生效,除此之外的其他redis對(duì)象,都不會(huì)相互引用。

OBJECT IDLETIME

IDLE 一般指的是閑置、懶散的意思,很明顯,這個(gè)命令就是獲取指定的 KEY 從被存儲(chǔ)之后空閑的時(shí)間,以秒為單位的。

127.0.0.1:6379> OBJECT IDLETIME a
(integer) 32
127.0.0.1:6379> OBJECT IDLETIME b
(integer) 156
127.0.0.1:6379> OBJECT IDLETIME c
(integer) 161
127.0.0.1:6379> OBJECT IDLETIME d
(integer) 167
127.0.0.1:6379> OBJECT IDLETIME e
(integer) 169

在上個(gè)例子中我們修改過(guò)了 a 的值,所以 a 的空閑時(shí)間發(fā)生了改變。

OBJECT FREQ

最后這個(gè) FREQ 子命令返回的是在 LFU 淘汰算法下,對(duì)于某個(gè) KEY 的使用計(jì)數(shù)。

127.0.0.1:6379> CONFIG SET maxmemory-policy allkeys-lfu
OK
127.0.0.1:6379> OBJECT FREQ a
(integer) 0
127.0.0.1:6379> get a
"10000000"
127.0.0.1:6379> OBJECT FREQ a
(integer) 1
127.0.0.1:6379> OBJECT FREQ b
(integer) 0

當(dāng) a 被使用了一次之后,這個(gè) KEY 下面的相關(guān)計(jì)數(shù)器就會(huì)加一。關(guān)于具體的淘汰算法的問(wèn)題我們?cè)谥蟮倪M(jìn)階系列中再學(xué)習(xí),現(xiàn)在你只要知道,必須要使用 LFU 相關(guān)的緩存淘汰算法,這個(gè)命令才可以使用。

排序

對(duì)于 List、Set、Sorted Set 來(lái)說(shuō),我們可以通過(guò) SORT 這個(gè)命令來(lái)對(duì)它們的值進(jìn)行排序。這個(gè)命令的參數(shù)比較多,它的命令簽名是這樣的。

SORT key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]

先來(lái)進(jìn)行一個(gè)簡(jiǎn)單的不加任何參數(shù)的排序,默認(rèn)情況是正序排列。

127.0.0.1:6379> LPUSH b1 5 2 4 5 7 3 1 7 8 10 2 8 9
(integer) 13
127.0.0.1:6379> SORT b1
 1) "1"
 2) "2"
 3) "2"
 4) "3"
 5) "4"
 6) "5"
 7) "5"
 8) "7"
 9) "7"
10) "8"
11) "8"
12) "9"
13) "10"

直接使用 DESC 就可以進(jìn)行倒序的排列,同時(shí)還可以使用 LIMIT 控制偏移量和數(shù)量,和 MySQL 中非常類似。

127.0.0.1:6379> SORT b1 LIMIT 2 5 DESC
1) "8"
2) "8"
3) "7"
4) "7"
5) "5"

對(duì)于數(shù)字來(lái)說(shuō),排序非常方便,那么能不能對(duì)字符串進(jìn)行排序呢?

127.0.0.1:6379> SMEMBERS e
1) "a"
2) "c"
3) "b"

127.0.0.1:6379> SORT e
(error) ERR One or more scores can't be converted into double
127.0.0.1:6379> SORT e ALPHA
1) "a"
2) "b"
3) "c"

通過(guò)上面的例子可以看出,直接對(duì)字符類型的元素排序是不行的,但是我們可以加一個(gè) ALPAH 參數(shù),這樣就可以對(duì)字符串進(jìn)行排序了。另外我們可以通過(guò) STORE 參數(shù)將排序后的內(nèi)容放到另一個(gè) KEY 中。

127.0.0.1:6379> SORT e ALPHA STORE e1
(integer) 3

127.0.0.1:6379> SMEMBERS e1
(error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> type e1
list
127.0.0.1:6379> LRANGE e1 0 -1
1) "a"
2) "b"
3) "c"

注意看這個(gè)例子中,排序的結(jié)果會(huì)是一個(gè) List 類型。

除了上面這些簡(jiǎn)單的排序操作外,我們還可以通過(guò) BY 和 GET 命令實(shí)現(xiàn)非常復(fù)雜的排序操作。BY 是通過(guò)外部元素的 KEY 作為權(quán)重來(lái)進(jìn)行排序。還是拿上面那個(gè) e 中的 Set 元素為例,這回我們定義三個(gè)外部 KEY ,它們的鍵名中包含 Set 集合中的元素信息,它們的值是用于排序的數(shù)字類型。

127.0.0.1:6379> mset es:b 2 es:c 5 es:a 4
OK
127.0.0.1:6379> SORT e BY es:*
1) "b"
2) "a"
3) "c"

神奇嗎?現(xiàn)在的順序是按照新定義的那三個(gè)外部 KEY 的值來(lái)排序的,不信?你可以再通過(guò) GET 參數(shù)來(lái)驗(yàn)證。

127.0.0.1:6379> SORT e BY es:* get es:*
1) "2"
2) "4"
3) "5"

GET 參數(shù)是將排序的結(jié)果信息顯示為外部鍵的值信息。如果想跳過(guò)排序的元素,可以直接使用一個(gè)不存在的 KEY 。

127.0.0.1:6379> SORT e BY es:noone
1) "a"
2) "c"
3) "b"

說(shuō)了半天 BY 和 GET ,感覺(jué)很強(qiáng)大,但是有什么實(shí)際用處呢?咱們來(lái)看一個(gè)例子,通過(guò) BY 和 GET 來(lái)對(duì)多個(gè) Hash 數(shù)據(jù)進(jìn)行排序。

127.0.0.1:6379> hmset es2:a title Bob score 30
OK
127.0.0.1:6379> hmset es2:b title Alice score 70
OK
127.0.0.1:6379> hmset es2:c title Mary score 60
OK

127.0.0.1:6379> SORT e BY es2:*->socre get es2:*->title
1) "Bob"
2) "Alice"
3) "Mary"
127.0.0.1:6379> SORT e BY es2:*->socre get es2:*->title DESC
1) "Mary"
2) "Alice"
3) "Bob"

看明白啥意思了沒(méi)?-> 這個(gè)符號(hào),就像我們?cè)?PHP 中調(diào)用對(duì)象的屬性或方法一樣的符號(hào),在這里也是類似的概念。BY xxx->score 就是通過(guò) Hash 對(duì)象中 score 字段進(jìn)行排序 ,然后再使用 GET 來(lái)獲得 ->title 標(biāo)題,是不是酷斃了。

刪除

最后的最后,我們?cè)賮?lái)看兩個(gè)非常簡(jiǎn)單的命令,它們都是用于刪除數(shù)據(jù)的。

127.0.0.1:6379> del es:a es:b
(integer) 2
127.0.0.1:6379> UNLINK es:c es:d
(integer) 1
127.0.0.1:6379> keys es*
1) "es2"
2) "es2:b"
3) "es2:a"
4) "es3"
5) "es1"
6) "es2:c"

DEL 和 UNLINK 命令都可以刪除一個(gè)或多個(gè)鍵,但是,DEL 是在主線程中運(yùn)行的,大量刪除時(shí)會(huì)阻塞線程影響效率,而 UNLINK 是將鍵的引用標(biāo)記斷開(kāi),然后通過(guò)其它的線程回收內(nèi)存,真正的刪除會(huì)在異步完成。

DEL 刪除一個(gè)普通的 String 類型的 Key 是 O(1) ,但是,如果是 List、Hash、Set、Sorted Set 就不會(huì)這么輕松了,會(huì)達(dá)到 O(n) 的級(jí)別。另外,假如一個(gè) String 類型的值有幾百兆,要?jiǎng)h它的話,也會(huì)產(chǎn)生阻塞。

因此,估計(jì)大家也都猜到了,線上繁忙的生產(chǎn)環(huán)境,或許使用 UNLINK 會(huì)更合適一些。這也是 bigkey 刪除的一個(gè)面試點(diǎn)。

總結(jié)

完結(jié)撒花!!

對(duì)于 Redis 的基礎(chǔ)命令的學(xué)習(xí)就告一段落了,其實(shí)明眼人應(yīng)該一眼就能看出,我這又是開(kāi)始在刷 Redis 的文檔了。接下來(lái)我們就要進(jìn)入更深層次的學(xué)習(xí),也就是進(jìn)階部分的學(xué)習(xí)。這部分,少不了各種面試的八股文。不過(guò)我們也并不是以面試為主,而是通過(guò)面試時(shí)的這些常見(jiàn)問(wèn)題,來(lái)更加深入的理解 Redis ,從而能更進(jìn)一步地用好它。

繼續(xù)跟著,別掉隊(duì)哦!

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多