天天看點

關于Redis的幾件小事 | Redis的資料類型/過期政策/記憶體淘汰

5萬人關注的大資料成神之路,不來了解一下嗎?

5萬人關注的大資料成神之路,真的不來了解一下嗎?

5萬人關注的大資料成神之路,确定真的不來了解一下嗎?

歡迎您關注《大資料成神之路》

關于Redis的幾件小事 | Redis的資料類型/過期政策/記憶體淘汰

1.string

這是最基本的類型了,就是普通的set和get,做簡單的kv緩存。

2.hash

這個是類似map的一種結構,這個一般就是可以将結構化的資料,比如一個對象(前提是這個對象沒嵌套其他的對象)給緩存在redis裡,然後每次讀寫緩存的時候,可以就操作hash裡的某個字段。

key=150

value={
  “id”: 150,
  “name”: “zhangsan”,
  “age”: 20
}           

複制

hash類的資料結構,主要是用來存放一些對象,把一些簡單的對象給緩存起來,後續操作的時候,你可以直接僅僅修改這個對象中的某個字段的值

value={
  “id”: 150,
  “name”: “zhangsan”,
  “age”: 21
}           

複制

3.list

有序清單,這個是可以做很多不同操作的

比如:微網誌,某個大v的粉絲,就可以以list的格式放在redis裡去緩存

key=某大v
value=[zhangsan, lisi, wangwu]           

複制

比如:可以通過list存儲一些清單型的資料結構,類似粉絲清單了、文章的評論清單了之類的東西

比如:可以通過lrange指令,就是從某個元素開始讀取多少個元素,可以基于list實作分頁查詢,這個很棒的一個功能,基于redis實作簡單的高性能分頁,可以做類似微網誌那種下拉不斷分頁的東西,性能高,就一頁一頁走

比如:可以搞個簡單的消息隊列,從list頭怼進去,從list尾巴那裡弄出來

4.set

無序集合,自動去重

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

得基于redis進行全局的set去重

可以基于set玩兒交集、并集、差集的操作,比如交集吧,可以把兩個人的粉絲清單整一個交集,看看倆人的共同好友是誰?對吧

把兩個大v的粉絲都放在兩個set中,對兩個set做交集

5.sorted set

排序的set,去重但是可以排序,寫進去的時候給一個分數,自動根據分數排序,這個可以玩兒很多的花樣,最大的特點是有個分數可以自定義排序規則

比如說你要是想根據時間對資料排序,那麼可以寫入進去的時候用某個時間作為分數,人家自動給你按照時間排序了

排行榜:将每個使用者以及其對應的什麼分數寫入進去,zadd board score username,接着zrevrange board 0 99,就可以擷取排名前100的使用者;zrank board username,可以看到使用者在排行榜裡的排名

zadd board 85 zhangsan
zadd board 72 wangwu
zadd board 96 lisi
zadd board 62 zhaoliu
96 lisi
85 zhangsan
72 wangwu
62 zhaoliu
zrevrange board 0 3
擷取排名前3的使用者
96 lisi
85 zhangsan
72 wangwu
zrank board zhaoliu
4           

複制

6. 資料為什麼會過期?

首先,要明白redis是用來做資料緩存的,不是用來做資料存儲的(當然也可以當資料庫用),是以資料時候過期的,過期的資料就不見了,過期主要有兩種情況,

①在設定緩存資料時制定了過期時間,這樣到了過期時間資料就不見了。

②redis的資料是存放在記憶體中的,而記憶體是有限的,是不可能放過多資料的,比如隻有10G的記憶體,想要向裡面放入20G的資料,那麼就注定會有10G的資料會丢失。

7. redis的過期政策是什麼樣的?

redis采用了 “定期删除+惰性删除” 的過期政策。

①定期删除

原理:定期删除指的是redis預設每隔100ms就随機抽取一些設定了過期時間的key,檢測這些key是否過期,如果過期了就将其删掉。

為什麼會選擇一部分,而不是全部:因為如果這是redis裡面有大量的key都設定了過期時間,那麼如果全部去檢測一遍,CPU負載就會很高,會浪費大量的時間在檢測上面,甚至直接導緻redis挂掉。所有隻會抽取一部分而不會全部檢查。

出現問題:這樣的話就會出現大量的已經過期的key并沒有被删除,這就是 為什麼有時候大量的key明明已經過了失效時間,但是redis的記憶體還是被大量占用的原因 ,為了解決這個問題,就需要 惰性删除 這個政策了。

②惰性删除

原理:惰性删除不在是redis去主動删除,而是在你要擷取某個key 的時候,redis會先去檢測一下這個key是否已經過期,如果沒有過期則傳回給你,如果已經過期了,那麼redis會删除這個key,不會傳回給你。

這樣兩種政策就保證了 過期的key最終一定會被删除掉 ,但是這隻是保證了最終一定會被删除,要是定時删除漏掉了大量過期的key,而且我們也沒有及時的去通路這些key,那麼這些key不就不會被删除了嗎?不就會一直占着我們的記憶體嗎?這樣不還是會導緻redis記憶體耗盡嗎?

由于存在這樣的問題,是以redis引入了 記憶體淘汰機制 來解決。

8.記憶體淘汰機制

記憶體淘汰機制就保證了在redis的記憶體占用過多的時候,去進行記憶體淘汰,也就是删除一部分key,保證redis的記憶體占用率不會過高,那麼它會删除那些key呢?

redis提供了6中記憶體淘汰政策,我們可以去進行選擇,六中政策如下:

①noeviction:當記憶體不足以容納新寫入資料時,新寫入操作會報錯,無法寫入新資料,一般不采用。

②allkeys-lru:當記憶體不足以容納新寫入資料時,在鍵空間中,移除最近最少使用的key,這個是最常用的。

③allkeys-random:當記憶體不足以容納新寫入的資料時,在鍵空間中,随機移除key,一般也不使用。

④volatile-lru:volatile-lru:當記憶體不足以容納新寫入資料時,在設定了過期時間的鍵空間中,移除最近最少使用的key(這個一般不太合适) 。

⑤volatile-random:當記憶體不足以容納新寫入資料時,在設定了過期時間的鍵空間中,随機移除某個key 。

⑥volatile-ttl:當記憶體不足以容納新寫入資料時,在設定了過期時間的鍵空間中,有更早過期時間的key優先移除。

9.手寫一個LRU算法

//基于JavaLinkedHashMap實作
public class LRUCache<K,V> extends LinkedHashMap<K,V>{
private final int CACHE_SIZE;
      
//儲存傳遞進來的最大資料量
public LRUCache(int cacheSize){
//設定hashmap的初始大小,同時最後一個true指的是讓linkedhashmap按照通路順序來進行排序,
//最近通路的放在頭,最老通路的放在尾
super((int)Math.ceil(cacheSize/0.75)+1,0.75f,true);
          CACHE_SIZE = CacheSize;
      }

@Override
protected boolean removeEldestEntry(Map.Entry eldest){
//當map中的資料量大于指定的緩存個數的時候,就自動删除最老的資料。
return size() > CACHE_SIZE;
      }
}           

複制

— THE END —