目錄
前言
參考資料:《Redis設計與實現 第二版》;
第二部分為單機數據庫的實現,主要由以下模塊組成:數據庫、持久化、事件、客戶端與服務器;
本篇將介紹 Redis 中的數據庫;
與本章相關的 Redis 命令總結在下篇文章,歡迎點擊收藏,本篇將不再重復:
《Redis常用命令及示例總結(API)》:https://www.cnblogs.com/dlhjw/p/15639773.html
1. Redis中的數據庫
-
Redis服務器的所有數據庫保存在
redis.h/redisService結構的db數組中:struct redisService{ //... //保存所有數據庫的數組 redisDB *db; //服務器的數據庫數量 int dbnum; //... }dbnum屬性由服務器配置的 database 選項決定,默認為 16;
-
Redis客戶端數據庫保存在在
redisClient結構的db屬性:typedef struct redisClient{ //... //記錄客戶端當前正在使用的數據庫 redisDB *db; } redisClient;- 客戶端通過修改目標數據庫指針,讓它指向 redisService.db 數組中的不同元素;
- 可以通過 SELECT index 命令來切換數據庫;

-
數據庫的定義在
redis.h/redisDb結構中:typedef struct redisDb{ //... //數據庫鍵空間,保存數據庫中所有的鍵值對 dict *dict; //過期字典,保存着鍵的過期時間 dict *expires; } redisDb;- 鍵空間的鍵是數據庫的鍵,每個鍵是一個字符串對象;
- 鍵空間的值是數據庫的值,每個值可以是字符串對象、列表對象、哈希表對象、集合對象和有序集合對象中的一種;

2. 數據庫的鍵空間
- 數據庫鍵空間是一個字典,所有針對數據庫的操作都是通過鍵空間字典來操作的;
- 在對鍵空間進行讀寫操作時,Redis 還會進行一些維護操作:
- 讀取鍵后,會根據鍵是否存在更新服務器的鍵空間命中 keyspace_hits 次數或鍵空間不命中 keyspace_misses 次數。通過 INFO stats 命令查看屬性;
- 讀取鍵后,服務器會更新鍵的 LRU(最后一次使用時間)。通過 ONBJECT idlettime [key] 命令查看key的閑置時間;
- 服務器在讀取鍵時發現鍵已經過期,會先刪除這個過期鍵;
- 如果有客戶端使用 WATCH 命令監視某個鍵,服務器對該鍵修改后會標記上臟
dirty,讓事務處理程序注意; - 服務器每修改一個鍵后,會對臟
dirty鍵計數器值增 1,計數器會觸發服務器的持久化以及復制操作;
3. 鍵的生成時間與過期時間
- 鍵的時間相關設置命令參看《Redis常用命令及示例總結》1.3 生存時間的功能;
- 生存時間:
- 客戶端可以通過 EXPIRE 或 PEXPIRE 命令以秒或毫秒精度為數據庫中某個鍵設置生存時間(Time To Live,TTL)。經過指定時間后,服務器自動刪除生存時間為0的鍵;
- 可以通過 SETEX 命令在設置字符串鍵同時設置過期時間;
- 使用 TTL 或 PTTL 命令獲取鍵的剩余生存時間;
- 過期時間:
- 客戶端設置過期時間的命令是 EXPIREAT 或 PEXPIREAT;
- 過期時間是一個 UNIX 時間戳;
- EXPIRE、PEXPIRE 和 EXPIREAT 三個命令都會轉換成 PEXPIREAT 命令實現;
4. Redis中的過期鍵刪除策略
-
有三種刪除過期鍵的策略:
- 定時刪除:主動策略。對內存最友好,到期就釋放內存。缺點是對CPU事件不友好,當過期鍵比較多時,會占用一部分CPU時間;
- 惰性刪除:被動策略。對CPU時間最友好。每次從鍵空間獲取鍵時,檢查取得的鍵是否過期,過期則刪除。缺點是對內存不友好;
- 定期刪除:主動策略。前兩種策略的整合與折中。每隔一段時間執行一次刪除過期鍵操作,並通過限制刪除操作執行的時長與頻率減少刪除操作對CPU時間的影響。缺點是難以確定刪除操作執行的時長和頻率;
-
惰性刪除策略由
db.c/expireIfNeeded函數實現,流程如下:

- 定期刪除策略由
redis.c/activeExpireCycle函數實現,每當Redis的服務器周期性操作redis.c/serverCron函數執行時,activeExpireCycle 函數會被調用。在規定的時間內,分多次遍歷服務器各個數據庫,從數據庫的expires字典中隨機檢查一部分過期時間,刪除其中過期鍵;
5. AOF、RDB和復制功能對過期鍵的處理
5.1 生成 RDB 文件
- 在執行 SAVE 或 BGSAVE 命令創建一個新的 RBG 文件時,程序會對數據庫中的鍵進行檢查,已過期的鍵不會被保存到新創建的 RDB 文件中;
5.2 載入 RDB 文件
- 載入 RDB 文件時:
- 若服務器以主服務器模式運行,過期鍵不載入;
- 若服務器以從服務器模式運行,所有鍵都會載入;
5.3 AOF 文件寫入
- 當服務器以 AOF 持久化模式運行時,未被惰性刪除和定期刪除的過期鍵不會對 AOF 文件產生影響;
- 當過期鍵被惰性刪除或定期刪除后,程序會向 AOF 文件追加(append)一條 DEL 命令,顯示記錄該鍵已被刪除;
5.4 AOF 重寫
- 與 RDB 文件類似,在執行 AOF 重寫過程中,程序會對數據庫中的鍵進行檢查,已過期的鍵不會被保存到重寫后的 AOF 文件中;
5.5 復制
- 當服務器運行在復制模式下時,從服務器的過期鍵刪除動作由主服務器控制;


6. 數據庫通知
- 數據庫通知是 Redis 2.8 版本新增的功能;
- 數據庫通知可以讓客戶端通過訂閱給定的頻道或模式,來獲知數據庫中鍵的變化,以及數據庫中命令的執行情況;
- Redis 命令對數據庫進行修改后,服務器會根據配置向客戶端發送數據庫通知;
- 通知的相關命令可以參考 《Redis常用命令及示例總結》7. Pub/Sub(發布/訂閱);
- 兩類通知類型:
- 鍵空間通知 key-space notification:關注 “某個鍵執行了什么命令”;SUBSCRIBE channel:message;
- 鍵事件通知 key-event notification:關注 “某個命令被什么鍵執行了”;SUBSCRIBE channel:del;
- 服務器配置的
notify-keyspace-events選項決定服務器所發送通知的類型:- AKE:發送所有類型的鍵空間和鍵事件通知;
- AK:發送所有類型的鍵空間通知;
- AE:發送所有類型的鍵事件通知;
- K$:只發送字符串有關的鍵空間通知;
- EL:只發送列表鍵有關的鍵事件通知;
- 發送數據庫通知的功能是由
notify.c/notifyKeyspaceEvent函數實現;
最后
