通過之前的學(xué)習(xí),我們已經(jīng)了解了 Redis 中五大數(shù)據(jù)類型相關(guān)的一些命令,通過這些命令操作其實(shí)也能知道這五種數(shù)據(jù)類型都能夠應(yīng)用在哪些場(chǎng)景中。但是,今天我們依然要總結(jié)一下,為什么呢?因?yàn)檫@五大數(shù)據(jù)類型是非常常見的面試題呀。
如果你在簡(jiǎn)歷上寫了用過 Redis ,或者說寫了“精通” Redis 的話,那么大部分面試官第一個(gè)問題就是用過哪些數(shù)據(jù)類型,都用在什么場(chǎng)景解決了什么問題。當(dāng)然,也有可能會(huì)問你 Redis 和 Memcached 之間的區(qū)別。即使是問區(qū)別,Redis 豐富的數(shù)據(jù)類型也是它和 Memcached 之間的一個(gè)重點(diǎn)區(qū)別之一。
既然如此的話,那么今天我們就來總結(jié)一下這五大數(shù)據(jù)類型。
字符串類型,就是我們最常見也最常使用的 k/v 形式的數(shù)據(jù)類型啦。最基礎(chǔ)的緩存操作基本上都是基于這個(gè)數(shù)據(jù)類型的,同時(shí)在 Memcached 中也僅有這一種數(shù)據(jù)類型。你可以把它想象成我們程序代碼中的一個(gè)字符串變量,key 就是變量名,value 就是變量的值。這個(gè)變量被定義在 Redis 服務(wù)器中,可以指定它的過期時(shí)間,也可以永久保存,不跟隨程序的生命周期而結(jié)束。
對(duì)于 Redis 來說,字符串類型是二進(jìn)制安全的,有 512M 的空間可以使用,也就是說,一個(gè) key 可以存放最大 512M 的數(shù)據(jù)。同時(shí),它也可以存儲(chǔ)二進(jìn)制數(shù)據(jù),比如圖片或者文件之類的二進(jìn)制內(nèi)容。
因此,我們可以直接緩存整個(gè)頁面、整張圖片、序列化后的 JSON 對(duì)象等等,前提是它們不會(huì)超過 512M 的大小。
列表類型,或者說就是一個(gè)字符串列表,可以按照指定的順序添加元素。同樣的,將它想象成是我們 PHP 中的數(shù)組也是可以的,只不過這個(gè)數(shù)組同樣是在程序之外運(yùn)行在 Redis 服務(wù)上的。
列表最重要的一點(diǎn)就是可以方便地實(shí)現(xiàn)隊(duì)列和棧的功能,它可以支持非??斓念^尾數(shù)據(jù)插入和彈出,但是如果是訪問中間的元素就非常慢了,畢竟這是一個(gè)鏈表實(shí)現(xiàn)的數(shù)據(jù)結(jié)構(gòu)。
要實(shí)現(xiàn)隊(duì)列,我們可以 LPUSH 之后 RPOP ,或者 RPUSH 之后 LPOP ,只要不是從同一邊 POP 出來數(shù)據(jù)就是一個(gè)隊(duì)列應(yīng)用。而棧的話,只要同邊操作就可以了,比如 LPUSH 之后 LPOP 。
更為方便的是使用阻塞操作,也就是 BLPOP/BRPOP ,之前在文章中也說過,在取隊(duì)列的時(shí)候,我們往往要用一個(gè)守護(hù)進(jìn)程不停的 POP 新數(shù)據(jù),如果沒有新數(shù)據(jù)了一般會(huì) sleep() 一會(huì)程序。但有了阻塞操作之后,其實(shí)我們就可以不用 sleep() 了,直接進(jìn)行阻塞獲取就可以。
典型的應(yīng)用場(chǎng)景上面已經(jīng)說過了,就是隊(duì)列和棧的應(yīng)用。像我們實(shí)現(xiàn)微博的最新動(dòng)態(tài)、消息之類的功能,就可以將用戶發(fā)布的最新數(shù)據(jù) PUSH 到 List 中。另外,發(fā)郵件、短信之類的耗時(shí)操作,都可以通過隊(duì)列實(shí)現(xiàn)解耦。當(dāng)然,經(jīng)典的秒殺場(chǎng)景也是可以直接上隊(duì)列實(shí)現(xiàn)的。
如果你的項(xiàng)目本身不大,每秒請(qǐng)求入庫的量在幾千或者幾萬的情況下,使用 Redis 來實(shí)現(xiàn)隊(duì)列就足夠了,完全沒必要上專業(yè)的隊(duì)列服務(wù),比如 RabbitMQ 或者 Kafka 之類的。我之前最高的項(xiàng)目在最高峰有單機(jī) 2 萬并發(fā),每秒 2000 條左右的日志數(shù)據(jù)入 Redis 隊(duì)列,使用的是阿里云單機(jī)版4G的 Redis ,完全無壓力。(Redis理論讀寫可以達(dá)到 11萬/秒 和 8萬/秒 ,比 RabbitMQ 快)
哈希類型,這個(gè)類型怎么說好呢?想象成是一個(gè)對(duì)象吧。一個(gè) key 是我們的變量名,然后里面又存儲(chǔ)了一堆鍵值對(duì)數(shù)據(jù),就像我們對(duì)象里面的屬性?;蛘呓兴值漕愋鸵彩强梢缘?,一個(gè) key 里面的數(shù)據(jù)就像是一個(gè)數(shù)據(jù)字典。
對(duì)于一個(gè)少于 100 個(gè)字段的哈希類型來說,可以使用很少的空間來保存它,不過,哈希類型可以創(chuàng)建的字段數(shù)量遠(yuǎn)比100個(gè)多,在可使用內(nèi)存的范圍內(nèi)你可以無限制的為它添加字段。話又說回來,其實(shí)這個(gè)意思也就是你可以創(chuàng)建很多哈希數(shù)據(jù),比如數(shù)據(jù)庫查詢出來的列表,不想使用序列化存儲(chǔ)成 String 或者 List 的話,那么就可以直接一個(gè)接一個(gè)的創(chuàng)建成 Hash 。在 PHP 中,直接使用 hGetAll 返回的就是一個(gè)數(shù)組,不需要再進(jìn)行反序列化的操作,非常方便。
集合類型,同樣可以看成是數(shù)組,不過它是值不能重復(fù)的數(shù)組。也就說,它是完全符合數(shù)學(xué)上集合定義的一種數(shù)據(jù)類型。通過 Set 類型,可以非??焖俚靥砑?、刪除以及測(cè)試元素是否存在。一個(gè)集合可以包含 40 億個(gè)元素,同時(shí),因?yàn)槭羌希越?、并、差的?jì)算命令都已經(jīng)提供了,能夠方便地實(shí)現(xiàn)這些運(yùn)算。
通過集合類型,我們可以方便地實(shí)現(xiàn)一些標(biāo)簽操作,比如給文章打標(biāo)簽,合并同類標(biāo)簽之類的。另外還可以快速方便地獲取隨機(jī)的數(shù)據(jù),統(tǒng)計(jì)不重復(fù)的訪問IP等等。
有序集合,高大上了吧,在集合的基礎(chǔ)上加上了一個(gè) score 分?jǐn)?shù)的設(shè)置,從而讓集合實(shí)現(xiàn)有序排列。因?yàn)樵卦诓迦氲臅r(shí)候就會(huì)根據(jù)分?jǐn)?shù)進(jìn)行排序,所以可以很快地獲得當(dāng)前集合中的一個(gè)有序列表。應(yīng)用場(chǎng)景不用我說大家也能想到了,排行榜、延時(shí)隊(duì)列等等。
假如我們使用 Hash 存儲(chǔ)了很多用戶的信息,這時(shí)候我們想按用戶的某一個(gè)屬性返回一個(gè)排行數(shù)據(jù),那么就可以將屬性設(shè)置為 score ,將 Hash 的 key 設(shè)置為值。比如用戶的年齡作為 score ,返回一個(gè)關(guān)于年齡的排行榜。當(dāng)然,你直接把序列化后的整個(gè)用戶對(duì)象屬性全部放在值里也是沒問題的。
而對(duì)于延時(shí)隊(duì)列,則是在 ThinkPHP 的隊(duì)列組件中看到的,同時(shí) Laravel 中的延時(shí)隊(duì)列也是用它實(shí)現(xiàn)的。分?jǐn)?shù)使用時(shí)間戳,內(nèi)容保存的是隊(duì)列需要使用的數(shù)據(jù)。在彈出數(shù)據(jù)前,先查看時(shí)間是否到了,如果小于當(dāng)前時(shí)間,就彈出這條數(shù)據(jù)并執(zhí)行相應(yīng)的操作,具體的源碼大家可以查閱 TP 的 think-queue 組件,這個(gè)比 Laravel 的看得要簡(jiǎn)單一些。
基礎(chǔ)五大類型的內(nèi)容就到這里了,我們后面還將繼續(xù)學(xué)習(xí)其它基礎(chǔ)方面的知識(shí),畢竟是從頭重新刷一遍文檔,所以小伙伴們也不要著急哦。高階面試八股文我們?cè)缤硪矔?huì)學(xué)到,但是在這之前,基礎(chǔ)才是更重要的,畢竟我們要真正的把知識(shí)學(xué)到,而不是僅僅為了通過面試而已。
聯(lián)系客服