記憶體耗盡後Redis會發生什麼
阿新 • • 發佈:2021-02-15
# 前言
作為一臺伺服器來說,記憶體並不是無限的,所以總會存在記憶體耗盡的情況,那麼當 `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