《Redis設計與實現》學習筆記-單機數據庫

一個Redis服務器實例在單機運行時可以添加多個數據庫來保存鍵值對,Redis在實現中通過一個redisDb結構體來描述數據庫,該結構體中有一個字典類型的字段來保存數據庫中所有的鍵值對,redisServer結構體來描述服務器實例,該結構體中有一個dbnum字段來保存數據庫數量,一個redisDb數組字段來保存服務器中的所有數據庫。

struct redisServer{
    ...
    redisDb *db;
    int dbnum;
    ...
};

typedef struct redisDb{
    ...
    dict *dict;
    ...
} redisDb;

當客戶端調用SET、RPUSH等命令之後會把命令中內容作爲鍵值對添加到redisDb的dict字典字段中,調用DEL等刪除操作時會刪除dict字段中相應的數據。

客戶端可以通過調用select <數據庫編號> 來切換數據庫。在服務器內部,通過redisClient結構體保存客戶端狀態,該結構體中有一個db字段來記錄目標數據庫,切換數據庫之後,redisClient結構體中的db屬性指向目標的數據庫結實例。

typedef struct redisClient{
    ...
    redisDb *db;
    ...
}redisClient;

鍵的過期時間:
redis提供了四種命令設置鍵的過期時間:

  • EXPIRE <key> <ttl> 設置key的生存時間爲ttl秒。
  • PEXPIRE <key> <ttl> 設置key的生存時間爲ttl毫秒。
  • EXPIREAT <key> <timestamp> 設置key的過期時間爲timestamp所指定秒數時間戳。
  • PEXPIREAT <key> <timestamp>設置key的過期時間爲timestamp所指定的毫秒數時間戳。

在redisDb結構體中有一個expires字段,用來保存數據庫中所有鍵的過期時間,這是一個字典字段,鍵是一個指向鍵對象的指針,值是一個長整型數保存過期時間(精確的UNIX毫秒時間戳),服務器通過該字段來檢查鍵是否已過期。

此外可以通過TTL<key>和PTTL<key>查詢鍵的剩餘生存時間,通過PERSIST <key>移除鍵的過期時間。

當鍵過期時有三種刪除策略:

  1. 定時刪除,創建一個定時器,在定時任務中刪除過期的鍵。這種策略節約內存但是耗CPU資源。
  2. 惰性刪除,不主動刪除過期鍵,每次訪問該鍵時如果該鍵過期刪除該鍵。這種策略對CPU消耗比較小,但是浪費內存,而且如果過期的鍵一致不被訪問的話有內存泄露的風險。
  3. 定期刪除,每隔一段時間,程序對數據庫做一次檢查,刪除裏面的過期鍵。但是不全部刪除,刪除多少由算法定,可以根據刪除鍵花費的時間或者一次刪除鍵的數量來控制。這種策略是1和2的折中,在內存和CPU上平衡,事實上很多性能調優的場景都是在內存和CPU之間犧牲哪一個而糾結。
redis在實現時採用了2和3策略。

關於持久化和複製功能對過期鍵的處理:

  • 在生成RDB文件時會過濾掉過期的鍵。
  • 在生成AOF文件時如果鍵過期會增加一條DEL命令到AOF文件中,AOF重寫時也會忽略過期的鍵。
  • 當主服務器刪除一個過期的鍵後它會向所有從服務器發送一條DEL命令,顯示地刪除過期鍵。從服務器不會主動刪除過期的鍵,而是由主服務器統一通知,這種統一、中心化的過期鍵刪除策略可以保證主從服務器數據的一致性

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章