1. 程式人生 > >記憶體耗盡後Redis會發生什麼

記憶體耗盡後Redis會發生什麼

# 前言 作為一臺伺服器來說,記憶體並不是無限的,所以總會存在記憶體耗盡的情況,那麼當 `Redis` 伺服器的記憶體耗盡後,如果繼續執行請求命令,`Redis` 會如何處理呢? # 記憶體回收 使用`Redis` 服務時,很多情況下某些鍵值對只會在特定的時間內有效,為了防止這種型別的資料一直佔有記憶體,我們可以給鍵值對設定有效期。`Redis` 中可以通過 `4` 個獨立的命令來給一個鍵設定過期時間: - `expire key ttl`:將 `key` 值的過期時間設定為 `ttl` **秒**。 - `pexpire key ttl`:將 `key` 值的過期時間設定為 `ttl` **毫秒**。 - `expireat key timestamp`:將 `key` 值的過期時間設定為指定的 `timestamp` **秒數**。 - `pexpireat key timestamp`:將 `key` 值的過期時間設定為指定的 `timestamp` **毫秒數**。 PS:不管使用哪一個命令,最終 `Redis` 底層都是使用 `pexpireat` 命令來實現的。另外,`set` 等命令也可以設定 `key` 的同時加上過期時間,這樣可以保證設值和設過期時間的原子性。 設定了有效期後,可以通過 `ttl` 和 `pttl` 兩個命令來查詢剩餘過期時間(如果未設定過期時間則下面兩個命令返回 `-1`,如果設定了一個非法的過期時間,則都返回 `-2`): - `ttl key` 返回 `key` 剩餘過期秒數。 - `pttl key` 返回 `key` 剩餘過期的毫秒數。 ## 過期策略 如果將一個過期的鍵刪除,我們一般都會有三種策略: - 定時刪除:為每個鍵設定一個定時器,一旦過期時間到了,則將鍵刪除。這種策略對記憶體很友好,但是對 `CPU` 不友好,因為每個定時器都會佔用一定的 `CPU` 資源。 - 惰性刪除:不管鍵有沒有過期都不主動刪除,等到每次去獲取鍵時再判斷是否過期,如果過期就刪除該鍵,否則返回鍵對應的值。這種策略對記憶體不夠友好,可能會浪費很多記憶體。 - 定期掃描:系統每隔一段時間就定期掃描一次,發現過期的鍵就進行刪除。這種策略相對來說是上面兩種策略的折中方案,需要注意的是這個定期的頻率要結合實際情況掌控好,使用這種方案有一個缺陷就是可能會出現已經過期的鍵也被返回。 在 `Redis` 當中,其選擇的是策略 `2` 和策略 `3` 的綜合使用。不過 `Redis` 的定期掃描只會掃描設定了過期時間的鍵,因為設定了過期時間的鍵 `Redis` 會單獨儲存,所以不會出現掃描所有鍵的情況: ```c typedef struct redisDb { dict *dict; //所有的鍵值對 dict *expires; //設定了過期時間的鍵值對 dict *blocking_keys; //被阻塞的key,如客戶端執行BLPOP等阻塞指令時 dict *watched_keys; //WATCHED keys int id; //Database ID //... 省略了其他屬性 } redisDb; ``` ## 8 種淘汰策略 假如 `Redis` 當中所有的鍵都沒有過期,而且此時記憶體滿了,那麼客戶端繼續執行 `set` 等命令時 `Redis` 會怎麼處理呢?`Redis` 當中提供了不同的淘汰策略來處理這種場景。 首先 `Redis` 提供了一個引數 `maxmemory` 來配置 `Redis` 最大使用記憶體: ```java ma