Redis | 第4章 Redis中的數(shù)據(jù)庫《Redis設(shè)計(jì)與實(shí)現(xiàn)》

前言

參考資料:《Redis設(shè)計(jì)與實(shí)現(xiàn) 第二版》;

第二部分為單機(jī)數(shù)據(jù)庫的實(shí)現(xiàn),主要由以下模塊組成:數(shù)據(jù)庫、持久化、事件、客戶端服務(wù)器

本篇將介紹 Redis 中的數(shù)據(jù)庫;

與本章相關(guān)的 Redis 命令總結(jié)在下篇文章,歡迎點(diǎn)擊收藏,本篇將不再重復(fù):

《Redis常用命令及示例總結(jié)(API)》http://www.itdecent.cn/p/f8eb9afaa908


1. Redis中的數(shù)據(jù)庫

  • Redis服務(wù)器的所有數(shù)據(jù)庫保存在redis.h/redisService結(jié)構(gòu)的db數(shù)組中:

    struct redisService{
        //...
        //保存所有數(shù)據(jù)庫的數(shù)組
        redisDB *db;
      
        //服務(wù)器的數(shù)據(jù)庫數(shù)量
        int dbnum;
        //...
    }
    
    • dbnum屬性由服務(wù)器配置的 database 選項(xiàng)決定,默認(rèn)為 16;
  • Redis客戶端數(shù)據(jù)庫保存在在redisClient結(jié)構(gòu)的db屬性:

    typedef struct redisClient{
        //...
        //記錄客戶端當(dāng)前正在使用的數(shù)據(jù)庫
        redisDB *db;
    } redisClient;
    
    • 客戶端通過修改目標(biāo)數(shù)據(jù)庫指針,讓它指向 redisService.db 數(shù)組中的不同元素;
    • 可以通過 SELECT index 命令來切換數(shù)據(jù)庫;
      客戶端的目標(biāo)數(shù)據(jù)庫.png
  • 數(shù)據(jù)庫的定義在redis.h/redisDb結(jié)構(gòu)中:

    typedef struct redisDb{
        //...
        //數(shù)據(jù)庫鍵空間,保存數(shù)據(jù)庫中所有的鍵值對
        dict *dict;
        
        //過期字典,保存著鍵的過期時(shí)間
        dict *expires;
    } redisDb;
    
    • 鍵空間的鍵是數(shù)據(jù)庫的鍵,每個(gè)鍵是一個(gè)字符串對象;
    • 鍵空間的值是數(shù)據(jù)庫的值,每個(gè)值可以是字符串對象列表對象、哈希表對象集合對象有序集合對象中的一種;
帶過期字典的數(shù)據(jù)庫.png


2. 數(shù)據(jù)庫的鍵空間

  • 數(shù)據(jù)庫鍵空間是一個(gè)字典,所有針對數(shù)據(jù)庫的操作都是通過鍵空間字典來操作的;
  • 在對鍵空間進(jìn)行讀寫操作時(shí),Redis 還會進(jìn)行一些維護(hù)操作:
    • 讀取鍵后,會根據(jù)鍵是否存在更新服務(wù)器的鍵空間命中 keyspace_hits 次數(shù)或鍵空間不命中 keyspace_misses 次數(shù)。通過 INFO stats 命令查看屬性;
    • 讀取鍵后,服務(wù)器會更新鍵的 LRU(最后一次使用時(shí)間)。通過 ONBJECT idlettime [key] 命令查看key的閑置時(shí)間;
    • 服務(wù)器在讀取鍵時(shí)發(fā)現(xiàn)鍵已經(jīng)過期,會先刪除這個(gè)過期鍵;
    • 如果有客戶端使用 WATCH 命令監(jiān)視某個(gè)鍵,服務(wù)器對該鍵修改后會標(biāo)記上臟 dirty,讓事務(wù)處理程序注意;
    • 服務(wù)器每修改一個(gè)鍵后,會對臟 dirty 鍵計(jì)數(shù)器值增 1,計(jì)數(shù)器會觸發(fā)服務(wù)器的持久化以及復(fù)制操作;


3. 鍵的生成時(shí)間與過期時(shí)間

  • 鍵的時(shí)間相關(guān)設(shè)置命令參看《Redis常用命令及示例總結(jié)》1.3 生存時(shí)間的功能
  • 生存時(shí)間:
    • 客戶端可以通過 EXPIREPEXPIRE 命令以秒或毫秒精度為數(shù)據(jù)庫中某個(gè)鍵設(shè)置生存時(shí)間(Time To Live,TTL)。經(jīng)過指定時(shí)間后,服務(wù)器自動(dòng)刪除生存時(shí)間為0的鍵;
    • 可以通過 SETEX 命令在設(shè)置字符串鍵同時(shí)設(shè)置過期時(shí)間;
    • 使用 TTLPTTL 命令獲取鍵的剩余生存時(shí)間;
  • 過期時(shí)間:
    • 客戶端設(shè)置過期時(shí)間的命令是 EXPIREATPEXPIREAT
    • 過期時(shí)間是一個(gè) UNIX 時(shí)間戳;
  • EXPIRE、PEXPIREEXPIREAT 三個(gè)命令都會轉(zhuǎn)換成 PEXPIREAT 命令實(shí)現(xiàn);


4. Redis中的過期鍵刪除策略

  • 有三種刪除過期鍵的策略:

    • 定時(shí)刪除:主動(dòng)策略。對內(nèi)存最友好,到期就釋放內(nèi)存。缺點(diǎn)是對CPU事件不友好,當(dāng)過期鍵比較多時(shí),會占用一部分CPU時(shí)間;
    • 惰性刪除:被動(dòng)策略。對CPU時(shí)間最友好。每次從鍵空間獲取鍵時(shí),檢查取得的鍵是否過期,過期則刪除。缺點(diǎn)是對內(nèi)存不友好;
    • 定期刪除:主動(dòng)策略。前兩種策略的整合與折中。每隔一段時(shí)間執(zhí)行一次刪除過期鍵操作,并通過限制刪除操作執(zhí)行的時(shí)長與頻率減少刪除操作對CPU時(shí)間的影響。缺點(diǎn)是難以確定刪除操作執(zhí)行的時(shí)長和頻率;
  • 惰性刪除策略由 db.c/expireIfNeeded 函數(shù)實(shí)現(xiàn),流程如下:

惰性刪除策略的執(zhí)行流程.png
  • 定期刪除策略由 redis.c/activeExpireCycle 函數(shù)實(shí)現(xiàn),每當(dāng)Redis的服務(wù)器周期性操作 redis.c/serverCron 函數(shù)執(zhí)行時(shí),activeExpireCycle 函數(shù)會被調(diào)用。在規(guī)定的時(shí)間內(nèi),分多次遍歷服務(wù)器各個(gè)數(shù)據(jù)庫,從數(shù)據(jù)庫的 expires 字典中隨機(jī)檢查一部分過期時(shí)間,刪除其中過期鍵;


5. AOF、RDB和復(fù)制功能對過期鍵的處理

5.1 生成 RDB 文件

  • 在執(zhí)行 SAVEBGSAVE 命令創(chuàng)建一個(gè)新的 RBG 文件時(shí),程序會對數(shù)據(jù)庫中的鍵進(jìn)行檢查,已過期的鍵不會被保存到新創(chuàng)建的 RDB 文件中;

5.2 載入 RDB 文件

  • 載入 RDB 文件時(shí):
    • 若服務(wù)器以主服務(wù)器模式運(yùn)行,過期鍵不載入;
    • 若服務(wù)器以從服務(wù)器模式運(yùn)行,所有鍵都會載入;

5.3 AOF 文件寫入

  • 當(dāng)服務(wù)器以 AOF 持久化模式運(yùn)行時(shí),未被惰性刪除和定期刪除的過期鍵不會對 AOF 文件產(chǎn)生影響;
  • 當(dāng)過期鍵被惰性刪除或定期刪除后,程序會向 AOF 文件追加(append)一條 DEL 命令,顯示記錄該鍵已被刪除;

5.4 AOF 重寫

  • 與 RDB 文件類似,在執(zhí)行 AOF 重寫過程中,程序會對數(shù)據(jù)庫中的鍵進(jìn)行檢查,已過期的鍵不會被保存到重寫后的 AOF 文件中;

5.5 復(fù)制

  • 當(dāng)服務(wù)器運(yùn)行在復(fù)制模式下時(shí),從服務(wù)器的過期鍵刪除動(dòng)作由主服務(wù)器控制;


    客戶端訪問從服務(wù)器.png
客戶端訪問主服務(wù)器.png.png


6. 數(shù)據(jù)庫通知

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



最后

\color{blue}{\rm\small{新人制作,如有錯(cuò)誤,歡迎指出,感激不盡!}}

\color{blue}{\rm\small{歡迎關(guān)注我,并與我交流!}}

\color{blue}{\rm\small{如需轉(zhuǎn)載,請標(biāo)注出處!}}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容