Redis 的基礎資料型別

2022-01-12 08:40:39 字數 4142 閱讀 5544

十年河東,十年河西,莫欺少年窮

學無止境,精益求精

正文如下

行吧,那我先從string說起。

string:

這是最簡單的型別,就是普通的 set 和 get,做簡單的 kv 快取。

但是真實的開發環境中,很多仔可能會把很多比較複雜的結構也統一轉成string去儲存使用,比如有的仔他就喜歡把物件或者list轉換為jsonstring進行儲存,拿出來再反串行話啥的。

我在這裡就不討論這樣做的對錯了,但是我還是希望大家能在最合適的場景使用最合適的資料結構,物件找不到最合適的但是型別可以選最合適的嘛,之後別人接手你的**一看這麼規範,誒這小夥子有點東西呀,看到你啥都是用的string,垃圾!

好了這些都是題外話了,道理還是希望大家記在心裡,習慣成自然嘛,小習慣成就你。

string的實際應用場景比較廣泛的有:

hash:

這個是類似 map 的一種結構,這個一般就是可以將結構化的資料,比如乙個物件(前提是這個物件沒巢狀其他的物件)給快取在 redis 裡,然後每次讀寫快取的時候,可以就操作 hash裡的某個字段。

但是這個的場景其實還是多少單一了一些,因為現在很多物件都是比較複雜的,比如你的商品物件可能裡面就包含了很多屬性,其中也有物件。我自己使用的場景用得不是那麼多。

list:

list 是有序列表,這個還是可以玩兒出很多花樣的。

比如可以通過 lrange 命令,讀取某個閉區間內的元素,可以基於 list 實現分頁查詢,這個是很棒的乙個功能,基於 redis 實現簡單的高效能分頁,可以做類似微博那種下拉不斷分頁的東西,效能高,就一頁一頁走。

比如可以搞個簡單的訊息佇列,從 list 頭懟進去,從 list 屁股那裡弄出來。

list本身就是我們在開發過程中比較常用的資料結構了,熱點資料更不用說了。

set:

set 是無序集合,會自動去重的那種。

直接基於 set 將系統裡需要去重的資料扔進去,自動就給去重了,如果你需要對一些資料進行快速的全域性去重,你當然也可以基於 jvm 記憶體裡的 hashset 進行去重,但是如果你的某個系統部署在多台機器上呢?得基於redis進行全域性的 set 去重。

可以基於 set 玩兒交集、並集、差集的操作,比如交集吧,我們可以把兩個人的好友列表整乙個交集,看看倆人的共同好友是誰?對吧。

反正這些場景比較多,因為對比很快,操作也簡單,兩個查詢乙個set搞定。

sorted set:

sorted set 是排序的 set,去重但可以排序,寫進去的時候給乙個分數,自動根據分數排序。

有序集合的使用場景與集合類似,但是set集合不是自動有序的,而sorted set可以利用分數進行成員間的排序,而且是插入時就排序好。所以當你需要乙個有序且不重複的集合列表時,就可以選擇sorted set資料結構作為選擇方案。

redis基礎型別有五種,這個我在基礎裡面也有提到了,這個問題其實一般都是對p6以下,也就是1-3年左右的小夥伴可能是會問得比較多的問題。

能回答出來五種我想大家都可以,但是不知道大家是否知道,五種型別具體的使用場景,以及什麼時候用什麼型別最合適呢?

要是你回答的不好,沒說出幾種資料型別,也沒說什麼場景,你完了,面試官對你印象肯定不好,覺得你平時就是做個簡單的 set 和 get。所以看似很簡單的面試題實則最容易看出你的深淺了,大家都要注意打好基礎。

嗯嗯這個問題我以前開發的時候遇到過,其實併發過程中確實會有這樣的問題,比如下面這樣的情況

系統a、b、c三個系統,分別去操作redis的同乙個key,本來順序是1,2,3是正常的,但是因為系統a網路突然抖動了一下,b,c在他前面操作了redis,這樣資料不就錯了麼。

我們可以找個管家幫我們管理好資料的嘛!

某個時刻,多個系統例項都去更新某個 key。可以基於 zookeeper 實現分布式鎖。每個系統通過 zookeeper 獲取分布式鎖,確保同一時間,只能有乙個系統例項在操作某個 key,別人都不允許讀和寫。

你要寫入快取的資料,都是從 mysql 裡查出來的,都得寫入 mysql 中,寫入 mysql 中的時候必須儲存乙個時間戳,從 mysql 查出來的時候,時間戳也查出來。

每次要寫之前,先判斷一下當前這個 value 的時間戳是否比快取裡的 value 的時間戳要新。如果是的話,那麼可以寫,否則,就不能用舊的資料覆蓋新的資料。

一般來說,如果允許快取可以稍微的跟資料庫偶爾有不一致的情況,也就是說如果你的系統不是嚴格要求 「快取+資料庫」 必須保持一致性的話,最好不要做這個方案,即:讀請求和寫請求序列化,串到乙個記憶體佇列裡去。

序列化可以保證一定不會出現不一致的情況,但是它也會導致系統的吞吐量大幅度降低,用比正常情況下多幾倍的機器去支撐線上的乙個請求。

把一些列的操作都放到佇列裡面,順序肯定不會亂,但是併發高了,這佇列很容易阻塞,反而會成為整個系統的弱點,瓶頸

最經典的快取+資料庫讀寫的模式,就是 cache aside pattern

原因很簡單,很多時候,在複雜點的快取場景,快取不單單是資料庫中直接取出來的值。

比如可能更新了某個表的乙個字段,然後其對應的快取,是需要查詢另外兩個表的資料並進行運算,才能計算出快取最新的值的。

另外更新快取的代價有時候是很高的。是不是說,每次修改資料庫的時候,都一定要將其對應的快取更新乙份?也許有的場景是這樣,但是對於比較複雜的快取資料計算的場景,就不是這樣了。如果你頻繁修改乙個快取涉及的多個表,快取也頻繁更新。但是問題在於,這個快取到底會不會被頻繁訪問到?

舉個栗子:乙個快取涉及的表的字段,在 1 分鐘內就修改了 20 次,或者是 100 次,那麼快取更新 20 次、100 次;但是這個快取在 1 分鐘內只被讀取了 1 次,有大量的冷資料。

實際上,如果你只是刪除快取的話,那麼在 1 分鐘內,這個快取不過就重新計算一次而已,開銷大幅度降低。用到快取才去算快取。

其實刪除快取,而不是更新快取,就是乙個 lazy 計算的思想,不要每次都重新做複雜的計算,不管它會不會用到,而是讓它到需要被使用的時候再重新計算。

像 mybatis,hibernate,都有懶載入思想。查詢乙個部門,部門帶了乙個員工的 list,沒有必要說每次查詢部門,都裡面的 1000 個員工的資料也同時查出來啊。80% 的情況,查這個部門,就只是要訪問這個部門的資訊就可以了。先查部門,同時要訪問裡面的員工,那麼這個時候只有在你要訪問裡面的員工的時候,才會去資料庫裡面查詢 1000 個員工。

redis 支援複雜的資料結構:

redis 相比 memcached 來說,擁有更多的資料結構,能支援更豐富的資料操作。如果需要快取能夠支援更複雜的結構和操作, redis 會是不錯的選擇。

redis 原生支援集群模式:

在 redis3.x 版本中,便能支援 cluster 模式,而 memcached 沒有原生的集群模式,需要依靠客戶端來實現往集群中分片寫入資料。

效能對比:

由於 redis 只使用單核,而 memcached 可以使用多核,所以平均每乙個核上 redis 在儲存小資料時比 memcached 效能更高。而在 100k 以上的資料中,memcached 效能要高於 redis,雖然 redis 最近也在儲存大資料的效能上進行優化,但是比起 remcached,還是稍有遜色。

tip:其實面試官這麼問,是想看你知道為啥用這個技術棧麼?你為啥選這個技術棧,你是否做過技術選型的對比,優缺點你是否了解,你啥都不知道,只是為了用而用,那你可能就差點意思了。

redis 內部使用檔案事件處理器file event handler,這個檔案事件處理器是單執行緒的,所以 redis 才叫做單執行緒的模型。它採用 io 多路復用機制同時監聽多個 socket,根據 socket 上的事件來選擇對應的事件處理器進行處理。

檔案事件處理器的結構包含 4 個部分:

多個 socket 可能會併發產生不同的操作,每個操作對應不同的檔案事件,但是 io 多路復用程式會監聽多個 socket,會將 socket 產生的事件放入佇列中排隊,事件分派器每次從佇列中取出乙個事件,把該事件交給對應的事件處理器進行處理。

redis基礎之資料型別 雜湊型別

redis是採用字典結構以鍵值對的形式儲存資料的,而雜湊型別 hash 的鍵值也是一種字典結構,其儲存了字段和字段值的對映,但字段值只能是字串,不支援其他資料型別,也就是說,雜湊型別不能巢狀其他的資料型別。乙個雜湊型別鍵可以包含至多2 32 1個字段。除了雜湊型別,redis的其他資料型別同樣不支援...

redis基礎之資料型別 列表型別

列表型別 list 可以儲存乙個有序的字串列表,常用的操作室向列表兩端新增元素,或者獲得列表的某乙個片段。列表型別內部是使用雙向鍊錶 double linked list 實現的,所有向列表兩端新增元素時間複雜度為o 1 獲取越接近兩端的元素速度就越快。這意味著即使是乙個有幾千萬個元素的列表,獲取頭...

Redis的資料型別

redis支援五種資料型別是string 字串 hash 雜湊 list 列表 set 集合 和zset sortedset 有序集合 string是redis最基本的型別,乙個key對應乙個value string型別是二進位制安全的,意思是redis的string可以包含任何資料,比如jpg或者...