redis(9)--数据库
目錄
?
服務(wù)器中的數(shù)據(jù)庫(kù)
redisServer結(jié)構(gòu)
redisDB結(jié)構(gòu)
切換數(shù)據(jù)庫(kù)
數(shù)據(jù)庫(kù)鍵空間
設(shè)置鍵的生存時(shí)間或過期時(shí)間
過期鍵判定
過期鍵刪除策略
過期鍵刪除的三種可能策略:
三種策略比較
Redis 的過期鍵刪除策略
惰性刪除策略實(shí)現(xiàn)
定期刪除策略實(shí)現(xiàn)
AOF 、RDB 和復(fù)制功能對(duì)過期鍵的處理
數(shù)據(jù)庫(kù)通知
服務(wù)器中的數(shù)據(jù)庫(kù)
redisServer結(jié)構(gòu)
struct redisServer
{
???? //數(shù)組,保存所有數(shù)據(jù)庫(kù)
????? redisDb *db;
???? //數(shù)據(jù)庫(kù)數(shù)據(jù)量
????? int dbnum;
}
redisDB結(jié)構(gòu)
typedef struct redisDb {// 保存著數(shù)據(jù)庫(kù)以整數(shù)表示的號(hào)碼int id;// 保存著數(shù)據(jù)庫(kù)中的所有鍵值對(duì)數(shù)據(jù)// 這個(gè)屬性也被稱為鍵空間(key space)dict *dict;// 保存著鍵的過期信息dict *expires;// 實(shí)現(xiàn)列表阻塞原語,如 BLPOP// 在列表類型一章有詳細(xì)的討論dict *blocking_keys;dict *ready_keys;// 用于實(shí)現(xiàn) WATCH 命令// 在事務(wù)章節(jié)有詳細(xì)的討論dict *watched_keys;} redisDb;
切換數(shù)據(jù)庫(kù)
每個(gè)Redis客戶端都有自己的目標(biāo)數(shù)據(jù)庫(kù),每當(dāng)客戶端執(zhí)行數(shù)據(jù)庫(kù)讀寫命名時(shí),目標(biāo)數(shù)據(jù)庫(kù)成為這些命令的操作的對(duì)象。
默認(rèn)情況下,Redis客戶端的目錄數(shù)據(jù)庫(kù)為0號(hào)數(shù)據(jù)庫(kù),可以通過select命令切換目標(biāo)數(shù)據(jù)庫(kù)。
select 2
在服務(wù)器內(nèi)部,客戶端狀態(tài)redisClient結(jié)構(gòu)的db屬性,記錄了客戶端當(dāng)前的目標(biāo)數(shù)據(jù)庫(kù)
typedef struct redisClient{
//記錄客戶端當(dāng)前正使用的數(shù)據(jù)庫(kù),指向redisServer中redisDb中的一個(gè)。
redisDb *db;
}? redisClient
到目前為止,redis仍沒有可以返回客戶端目標(biāo)數(shù)據(jù)庫(kù)的命令。在執(zhí)行像Flushdb等危險(xiǎn)操作時(shí),先執(zhí)行select命令,顯示切換到目標(biāo)數(shù)據(jù)庫(kù)。
數(shù)據(jù)庫(kù)鍵空間
為 Redis 是一個(gè)鍵值對(duì)數(shù)據(jù)庫(kù)(key-value pairs database), 所以它的數(shù)據(jù)庫(kù)本身也是一個(gè)字典(俗稱 key space):
- 字典的鍵是一個(gè)字符串對(duì)象。
- 字典的值則可以是包括字符串、列表、哈希表、集合或有序集在內(nèi)的任意一種 Redis 類型對(duì)象。
在 redisDb 結(jié)構(gòu)的 dict 屬性中,保存著數(shù)據(jù)庫(kù)的所有鍵值對(duì)數(shù)據(jù)。
數(shù)據(jù)庫(kù)鍵空間示例因?yàn)閿?shù)據(jù)庫(kù)本身是一個(gè)字典, 所以對(duì)數(shù)據(jù)庫(kù)的操作基本上都是對(duì)字典的操作, 加上以下一些維護(hù)操作:
- 更新鍵的命中率和不命中率,這個(gè)值可以用 INFO 命令查看;
- 更新鍵的 LRU 時(shí)間,這個(gè)值可以用 OBJECT 命令來查看;
- 刪除過期鍵(稍后會(huì)詳細(xì)說明);
- 如果鍵被修改了的話,那么將鍵設(shè)為臟(用于事務(wù)監(jiān)視),并將服務(wù)器設(shè)為臟(等待 RDB 保存);
- 將對(duì)鍵的修改發(fā)送到 AOF 文件和附屬節(jié)點(diǎn),保持?jǐn)?shù)據(jù)庫(kù)狀態(tài)的一致;
除了上面展示鍵值操作之外,還有很多針對(duì)數(shù)據(jù)庫(kù)本身的命令,也是通過對(duì)鍵空間進(jìn)行處理來完成的:
- FLUSHDB 命令:刪除鍵空間中的所有鍵值對(duì)。
- RANDOMKEY 命令:從鍵空間中隨機(jī)返回一個(gè)鍵。
- DBSIZE 命令:返回鍵空間中鍵值對(duì)的數(shù)量。
- EXISTS 命令:檢查給定鍵是否存在于鍵空間中。
- RENAME 命令:在鍵空間中,對(duì)給定鍵進(jìn)行改名。
設(shè)置鍵的生存時(shí)間或過期時(shí)間
在數(shù)據(jù)庫(kù)中, 所有鍵的過期時(shí)間都被保存在 redisDb 結(jié)構(gòu)的 expires 字典里:
帶有過期時(shí)間的數(shù)據(jù)庫(kù)在實(shí)際中, 鍵空間字典的鍵和過期時(shí)間字典的鍵都指向同一個(gè)字符串對(duì)象, 所以不會(huì)浪費(fèi)任何空間。
過期時(shí)間涉及命令包括:
- expire
- expireat
- pexpire
- pexpireat
- persist
- ttl
- pttl
過期鍵判定
通過 expires 字典, 可以用以下步驟檢查某個(gè)鍵是否過期:
過期鍵刪除策略
過期鍵刪除的三種可能策略:
三種策略比較
| 策略 | 優(yōu)點(diǎn) | 缺點(diǎn) | 說明 |
| 定時(shí)刪除 | 內(nèi)存友好 | 可能占用大量CPU | 目前 Redis 事件處理器對(duì)時(shí)間事件的實(shí)現(xiàn)方式 —— 無序鏈表, 查找一個(gè)時(shí)間復(fù)雜度為 O(N)—— 并不適合用來處理大量時(shí)間事件。 |
| 惰性刪除 | CPU友好 | 占用內(nèi)存 | 如果長(zhǎng)時(shí)間沒有訪問,不會(huì)被刪除 |
| 定期刪除 | 折中 | 折中 | 定期刪除,限制操作時(shí)長(zhǎng)和頻率,減少CPU占用時(shí)間,減少內(nèi)存占用 |
?
Redis 的過期鍵刪除策略
Redis 使用的過期鍵刪除策略是惰性刪除加上定期刪除, 這兩個(gè)策略相互配合,可以很好地在合理利用 CPU 時(shí)間和節(jié)約內(nèi)存空間之間取得平衡。
惰性刪除策略實(shí)現(xiàn)
定期刪除策略實(shí)現(xiàn)
對(duì)過期鍵的定期刪除由 redis.c/activeExpireCycle 函執(zhí)行: 每當(dāng) Redis 的例行處理程序 serverCron 執(zhí)行時(shí), activeExpireCycle 都會(huì)被調(diào)用 —— 這個(gè)函數(shù)在規(guī)定的時(shí)間限制內(nèi), 盡可能地遍歷各個(gè)數(shù)據(jù)庫(kù)的 expires 字典, 隨機(jī)地檢查一部分鍵的過期時(shí)間, 并刪除其中的過期鍵。
整個(gè)過程可以用偽代碼描述如下:
def activeExpireCycle():# 遍歷數(shù)據(jù)庫(kù)(不一定能全部都遍歷完,看時(shí)間是否足夠)for db in server.db:# MAX_KEY_PER_DB 是一個(gè) DB 最大能處理的 key 個(gè)數(shù)# 它保證時(shí)間不會(huì)全部用在個(gè)別的 DB 上(避免饑餓)i = 0while (i < MAX_KEY_PER_DB):# 數(shù)據(jù)庫(kù)為空,跳出 while ,處理下個(gè) DBif db.is_empty(): break# 隨機(jī)取出一個(gè)帶 TTL 的鍵key_with_ttl = db.expires.get_random_key()# 檢查鍵是否過期,如果是的話,將它刪除if is_expired(key_with_ttl):db.deleteExpiredKey(key_with_ttl)# 當(dāng)執(zhí)行時(shí)間到達(dá)上限,函數(shù)就返回,不再繼續(xù)# 這確保刪除操作不會(huì)占用太多的 CPU 時(shí)間if reach_time_limit(): returni += 1?
AOF 、RDB 和復(fù)制功能對(duì)過期鍵的處理
-
生成RDB文件
過期鍵不會(huì)寫入到新創(chuàng)建的RDB文件
-
載入RDB文件
主服務(wù)器模式運(yùn)行,過期鍵忽略。
從服務(wù)器模式運(yùn)行,過期鍵保留。——主從同步時(shí)會(huì)刪除。
-
AOF寫入
過期鍵被刪除后,向AOF追加DEL命令。
-
AOF重寫
過期鍵忽略
-
復(fù)制
主服務(wù)器刪除一個(gè)過期鍵,會(huì)向從服務(wù)器發(fā)送DEL命令
從服務(wù)器執(zhí)行讀取命令時(shí),不會(huì)刪除過期鍵。——所有從服務(wù)器讀取命令,可能返回不一致信息
從服務(wù)器只有接收到主服務(wù)器的DEL命令,才會(huì)刪除過期鍵。
數(shù)據(jù)庫(kù)通知
數(shù)據(jù)庫(kù)通知是Redis2.8版本新增加的功能,可以讓客戶端通過訂閱,獲知數(shù)據(jù)庫(kù)中鍵的變化
參考SUBSCRIBE 命令。
?
總結(jié)
以上是生活随笔為你收集整理的redis(9)--数据库的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: redis命令-key操作
- 下一篇: Redis--进阶