Redis 相關面試題(下)

2021-08-20 15:05:37 字數 4230 閱讀 3930

(1)redis的快取失效策略和主鍵失效機制

作為快取系統都要定期清理無效資料,就需要乙個主鍵失效和淘汰策略.

在redis當中,有生存期的key被稱為volatile。在建立快取時,要為給定的key設定生存期,當key過期的時候(生存期為0),它可能會被刪除。

1.過期時間跟著key走,與值無關

在redis中,帶有過期時間的key被稱為『易失的』(volatile)。 過期時間可以通過使用 del命令來刪除整個key來移除,或者被 set和 getset命令覆寫(overwrite),這意味著,如果乙個命令只是修改(alter)乙個帶過期時間的 key的值而不是用乙個新的 key值來代替(replace)它的話,那麼過期時間不會被改變。比如說,對乙個 key執行 incr命令,對乙個列表進行 lpush命令,或者對乙個雜湊表執行 hset命令,這類操作都不會修改 key本身的過期時間。

2.設定永久有效期

使用persist命令可以清除超時,使其變成乙個永久的key。

3.rename命令對有效期影響

如果key被rename命令修改,相關的超時時間會轉移到新key上面。

如果key被rename命令修改,比如原來就存在key_a,然後呼叫rename key_b key_a命令,這時不管原來key_a是永久的還是設定為超時的,都會由key_b的有效期狀態覆蓋。

4.重新整理過期時間

對已經有過期時間的key執行expire操作,將會更新它的過期時間。

5.最大快取配置

在 redis 中,允許使用者設定最大使用記憶體大小server.maxmemory預設為0,沒有指定最大快取,如果有新的資料新增,超過最大記憶體,則會使redis崩潰,所以一定要設定。redis 記憶體資料集大小上公升到一定大小的時候,就會實行資料淘汰策略。redis 提供 6種資料淘汰策略:

volatile-lru:從已設定過期時間的資料集(server.db[i].expires)中挑選最近最少使用的資料淘汰

volatile-ttl:從已設定過期時間的資料集(server.db[i].expires)中挑選將要過期的資料淘汰

volatile-random:從已設定過期時間的資料集(server.db[i].expires)中任意選擇資料淘汰

allkeys-lru:從資料集(server.db[i].dict)中挑選最近最少使用的資料淘汰

allkeys-random:從資料集(server.db[i].dict)中任意選擇資料淘汰

no-enviction(驅逐):禁止驅逐資料

注意這裡的6種機制,volatile和allkeys規定了是對已設定過期時間的資料集淘汰資料還是從全部資料集淘汰資料,後面的lru、ttl以及random是三種不同的淘汰策略,再加上一種no-enviction永不**的策略。

使用策略規則:

1、如果資料呈現冪律分布,也就是一部分資料訪問頻率高,一部分資料訪問頻率低,則使用allkeys-lru

2、如果資料呈現平等分布,也就是所有的資料訪問頻率都相同,則使用allkeys-random

三種資料淘汰策略:

ttl和random比較容易理解,實現也會比較簡單。主要是lru最近最少使用淘汰策略,設計上會對key 按失效時間排序,然後取最先失效的key進行淘汰.

(2)redis內部資料結構的實現

在redis內部,有非常多的資料結構:sds(簡單動態字串),list,intset(整數集合),hash(字典),zskiplist(跳躍表),ziplist(壓縮表)等。

1.****** dynamic string:一種簡單動態字串,而sdshdr封裝了c原生字串,並在其基礎上,增加了一些功能,使之後對它的呼叫簡單易懂可擴充套件。

sds 的具體實現結構adshdr,len表示sds的長度,alloc表示分配了的長度,這樣方便擴充套件;free空閒的長度;flags標誌來判斷使用哪個型別;buf則作為sds的真正儲存陣列。

2.list

redis中,list的實現是乙個雙端鍊錶,這樣可以方便的獲取其前後的節點值,方便之後對節點的查詢;redis通過list來對listnode進行持有,分別記錄list的頭尾節點list長度,可在o(n)的時間複雜度上進行查詢;

list在redis中運用相當廣泛,除了實現列表外,發布和訂閱、慢查詢、監視器等功能也使用了鍊錶來獲取,另外,redis伺服器還使用鍊錶來持有 多個客戶端的狀態資訊,以及用鍊錶來構建客戶端輸出緩衝區。

3.dict

dictentry是最核心的字典結構的節點結構,它儲存了key和value的內容;另外,next指標是為了解決hash衝突,字典結構的hash衝突解決方法是拉鍊法,對於hashcode重複的節點以鍊錶的形式儲存。

dictht是節點dictentry的持有者,將dictentry結構串起來,table就是hash表,其實dictentry *table這樣的書寫方式更容易理解些,size就是table陣列的長度,used標誌已有節點的數目。

dict是最外層的字典結構的介面形式,type標誌型別,privdata標誌其私有資料,dict持有兩個dictht結構,乙個用來儲存資料,乙個用來在rehash時使用,rehashidx標誌是否正在rehash(因為redis中rehash是乙個漸近的過程,正在rehash的時候rehashidx記錄rehash的階段,否則為-1。

注:因為dictentry節點組成的鍊錶沒有子項鍊表尾部的指標,所以新加的節點一般都加在鍊錶的頭部,排在已有節點的前面,因為這樣的時間複雜度為o(1)。

4.intset

當乙個集合元素只有整數並且數量元素不多的時候,可以選擇用整數集合來作為其底層實現。整數集合的資料結構如上所示。

重點說一下這個contents陣列,它儲存集合中的內容,並且以從小到大的順序排列,並保證其沒有重複的元素。雖然定義中其型別為int8_t,但具體編碼方式還是取決於encoding。

當最大的數在相關範圍之內是便會對應不同的資料型別,但是如果移除了這個最大取值,不會降級。int_6, int_32,int_64

分範圍定義其型別有兩個好處:提高其靈活性,節約記憶體。但是也增加了公升級的開銷。

在redis 中,整數集合的應用範圍不是很廣,只在實現集合時用到。

5.zskiplist(跳躍表)

對於不了解跳躍表的可以去這個地方看看,了解一下:

跳表是一種實現起來很簡單,單層多指標的鍊錶,它查詢效率很高,堪比優化過的二叉平衡樹,且比平衡樹的實現,簡單的多的多。

6.ziplist(壓縮表)

ziplist是乙個編碼後的列表,是由一系列特殊編碼的連續記憶體塊組成的順序型資料結構,特殊的設計使得記憶體操作非常有效率,此列表可以同時存放字串和整數型別,列表可以在頭尾各邊支援推加和彈出操作在o(1)常量時間,但是,因為每次操作涉及到記憶體的重新分配釋放,所以加大了操作的複雜性 。

zlentry是實際儲存資料的節點。乙個ziplist可以有多個zlentry節點,具體形式如下:

壓縮表在redis中的應用只存在於hash和list結構的實現中,為了在儲存時節省記憶體。

Redis相關面試題

reids 單執行緒 io多路復用機制 redis與memcached的區別 一 memcached值是簡單字串,redis支援hash set list等複雜資料型別 二 redis可持久化資料,容災能力強。memcached只存於記憶體中。三 redis是單執行緒操作,核心是io多路復用機制,效...

Redis相關面試題

原因 redis是記憶體儲存,斷電丟失資料,所以需要資料持久化。非同步執行緒 fork copy on write 系統io fsync rdb 指定時間間隔內觸發頻率,對資料進行快照儲存。儲存rdb檔案是父程序fork子程序來完成,最大化redis的效能 丟失資料多 aof 每次對伺服器寫操作會追...

鏈表面試題(下)

鍊錶帶環問題 是環,返回相遇點 slistnode slistiscycle slistnode list return null 求環長度 int slistcyclelen slistnode meetnode return count 返回環的入口點 slistnode slistentryn...