日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

Redis数据库实现原理(划重点)

發(fā)布時間:2025/3/17 数据库 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis数据库实现原理(划重点) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Redis服務(wù)器將所有數(shù)據(jù)庫都保存在服務(wù)器狀態(tài)redis.h/redisServer結(jié)構(gòu)的db數(shù)組中,db數(shù)組的每一項都是一個redis.h/redisDb結(jié)構(gòu),每個redisDb結(jié)構(gòu)代表一個數(shù)據(jù)庫,服務(wù)器設(shè)置dbnum屬性為初始數(shù)據(jù)庫的個數(shù),這個屬性一般由數(shù)據(jù)庫服務(wù)器配置conf文件中的database節(jié)點來配置,默認(rèn)情況下這個初始值是16。

struct redisServer{????//數(shù)據(jù)庫????redisDb?*db;????//服務(wù)器數(shù)量????int?dbnum;};

數(shù)據(jù)庫切換

前面我們說到默認(rèn)的redis數(shù)據(jù)庫有16個,那么我們?nèi)绾蝸砬袚Q數(shù)據(jù)庫呢?

127.0.0.1:6379> get name"mango"127.0.0.1:6379> select 1OK127.0.0.1:6379[1]> get name(nil)127.0.0.1:6379[1]> select 0OK127.0.0.1:6379> get name"mango"

默認(rèn)情況下我們操作的都是第一個數(shù)據(jù)庫,數(shù)據(jù)庫數(shù)組索引為[0],我們通過select命令來切換數(shù)據(jù)庫,通過修改客戶端的指針,來指向第二個數(shù)據(jù)庫。

注意:這里我們值得注意的是,我們在維護(hù)redis的時候執(zhí)行一些敏感的指令時養(yǎng)成一個習(xí)慣就是先切換數(shù)據(jù)庫,然后執(zhí)行。

數(shù)據(jù)庫鍵空間

Redis 中的每個數(shù)據(jù)庫,都由一個 redis.h/redisDb 結(jié)構(gòu)表示,下面我們來看看代碼。

typedef struct redisDb { // 保存著數(shù)據(jù)庫以整數(shù)表示的號碼????int?id; // 保存著數(shù)據(jù)庫中的所有鍵值對數(shù)據(jù),這個屬性也被稱為鍵空間(key space) dict *dict; // 保存著鍵的過期信息 dict *expires;????//?實現(xiàn)列表阻塞原語,如?BLPOP dict *blocking_keys; dict *ready_keys;????//?用于實現(xiàn)?WATCH?命令,在事務(wù)中有提到 dict *watched_keys;} redisDb;

因為Redis本身就是一個字典類型的數(shù)據(jù)庫,我們可以看到在RedisDb中,dict保存數(shù)據(jù)庫的所有鍵值對數(shù)據(jù)。

字典的鍵是一個字符串對象(StringObject)

字典的值則可以包括Redis的五種基礎(chǔ)結(jié)構(gòu)的任意一種(字符串、列表、哈希表、集合或有序集),例如:列表就是一個ListObject,哈希就是HashObject等。

如圖所示,每個類型對應(yīng)數(shù)據(jù)結(jié)構(gòu)不同。

關(guān)于Redis數(shù)據(jù)庫的增、刪、改、查操作這里就不過多解釋了,跟java或是c#中的實現(xiàn)是相似的,只不過對于字典擴(kuò)容稍有不同,Redis的擴(kuò)容是一種漸進(jìn)式的方式,一點點的將舊表遷入新表,不會在擴(kuò)容的時候阻塞其他操作。

其他操作
除了增刪該查的鍵值操作之外,還有很多針對數(shù)據(jù)庫本身的命令,也是通過對鍵空間進(jìn)行處理:
? FLUSHDB 命令:刪除鍵空間中的所有鍵值對。
? RANDOMKEY 命令:從鍵空間中隨機(jī)返回一個鍵。
? DBSIZE 命令:返回鍵空間中鍵值對的數(shù)量。
? EXISTS 命令:檢查給定鍵是否存在于鍵空間中。
? RENAME 命令:在鍵空間中,對給定鍵進(jìn)行改名。

過期設(shè)置

數(shù)據(jù)過期操作命令通過EXPIRE、PEXPIRE、EXPIREAT和PEXPIREAT四個命令,客戶端可以給某個存在的鍵設(shè)置過期時間,當(dāng)鍵的過期時間到達(dá)時,鍵就不再可用。當(dāng)然SETEX也是可以的,只不過它是一個限定類型命令(可以說是一個復(fù)合命令),跟其他的過期時間設(shè)置原理一樣。

>set name mango(integer)1>expire?name?5????#設(shè)置過期時間

過期時間是一個UNIX時間戳,當(dāng)鍵的過期時間到了,這個鍵就會在數(shù)據(jù)庫中被刪除。那么我們可以通過TTL和PTTL命令來返回距離過期時間還有多長時間

> SETEX key 10086 valueOK> TTL key(integer) 10082> PTTL key(integer) 10068998

過期時間保存

前面我們給出的RedisDb里面的一個屬性dict *expires是保存過期時間的,我們可以看到它也是一個dict鍵值的指針類型,其中這個過期字典中的是一個long long類型的整數(shù),這個整數(shù)保存的是過期時間。下面我們來畫一個圖加深印象。

注意:這里的過期時間的字典是指向的鍵空間的,只不過為了區(qū)分才這樣畫的。

如何檢測key是否過期?

  • 檢查這個key是否存在expires中

  • 檢查當(dāng)前時間是否大于過期時間,如果大于則過期,反之未過期

  • 過期key刪除策略

    Redis設(shè)置好過期時間后,如果key的過期時間到期,我們的redis沒有及時回收資源可能會導(dǎo)致Redis內(nèi)存溢出,所以我們需要及時清理過期的key來釋放資源。

    定時清理:

    此方法就是我設(shè)置一個定時器,到點了我就去清理已經(jīng)過期的key。

    優(yōu)點:就是方便簡潔,保證key過期及時處理;

    缺點:也很明顯,掃描整個字典是一個O(n)的時間復(fù)雜度,使用這種方式的時候會占用大量的cpu可能會導(dǎo)致服務(wù)器卡頓等現(xiàn)象,我們說過Redis盡量避免使用這類的操作,這樣處理并不高效。

    惰性清理:

    這種方式就是客戶端請求這個key的時候去判斷時間是否過期,過期則清理。

    優(yōu)點:對cup很友好,使用的時候去清理

    缺點:對內(nèi)存不友好,無效key不及時清理內(nèi)存得不到釋放,積壓的內(nèi)存越來越多,如果過期key特別多而且永遠(yuǎn)不訪問,可能會導(dǎo)致內(nèi)存溢出。

    定期清理:

    定期刪除是結(jié)合定是清理和惰性清理的特點選擇一個折中處理,一段時間內(nèi)處理一定量的key,這樣減少使用cpu帶來的阻塞,一定程度的減少內(nèi)存積壓。

    定期清理的難點在于清理算法,也就是說什么時候清理多少key這個量度是很難把握的。

    那么我們介紹了這三種清理方式后,Redis的清理過期key的方式是通過惰性清理和定期清理兩種策略來實現(xiàn)的。通過這兩種方式使Redis在cpu和內(nèi)存之間取得平衡,這兩種方式也是在不同的時期進(jìn)行的。

    過期鍵對AOF、RDB和復(fù)制的影響
    前面的內(nèi)容討論了過期鍵對cpu和內(nèi)存的影響,那么過期鍵在RDB文件、AOF 文件、AOF重寫以及復(fù)制中的影響。
    RDB文件在創(chuàng)建新的RDB文件時,程序會對鍵進(jìn)行檢查,過期的鍵不會被寫入到更新后的RDB文件中,過期鍵對更新后的RDB文件沒有影響。

    AOF文件在鍵已經(jīng)過期,但是還沒有被惰性刪除或者定期刪除之前,這個鍵不會產(chǎn)生任何影響,AOF文件也不會因為這個鍵而被修改。當(dāng)過期鍵被惰性刪除、或者定期刪除之后,程序會向AOF文件追加一條DEL命令,來顯式地記錄該鍵已被刪除。
    AOF重寫時程序?qū)︽I進(jìn)行檢查,過期的鍵不會被保存到重寫后的AOF文件。過期鍵對重寫后的AOF文件沒有影響。
    復(fù)制:當(dāng)服務(wù)器帶有附屬節(jié)點時,過期鍵的刪除由主節(jié)點統(tǒng)一控制:

    ? ? 如果服務(wù)器是主節(jié)點,那么它在刪除一個過期鍵之后,會顯式地向所有附屬節(jié)點發(fā)送一個DEL命令。
    ? ? 如果服務(wù)器是附屬節(jié)點,那么當(dāng)它碰到一個過期鍵的時候,它會向程序返回鍵已過期的回復(fù),但并不真正的刪除過期鍵。因為程序只根據(jù)鍵是否已經(jīng)過期、而不是鍵是否已經(jīng)被刪除來決定執(zhí)行流程,所以這種處理并不影響命令的正確執(zhí)行結(jié)果。當(dāng)接到從主節(jié)點發(fā)來的DEL命令之后,附屬節(jié)點才會真正的將過期鍵刪除掉。附屬節(jié)點不自主對鍵進(jìn)行刪除是為了和主節(jié)點的數(shù)據(jù)保持絕對一致,因為這個原因,當(dāng)一個過期鍵還存在于主節(jié)點時,這個鍵在所有附屬節(jié)點的副本也不會被刪除。這種處理機(jī)制對那些使用大量附屬節(jié)點,并且?guī)в写罅窟^期鍵的應(yīng)用來說,可能會造成一部分內(nèi)存不能立即被釋放,但是,因為過期鍵通常很快會被主節(jié)點發(fā)現(xiàn)并刪除

    ?

    總結(jié)一下

  • Redis默認(rèn)有16個數(shù)據(jù)庫,但如果沒有切換那么使用的是第一個默認(rèn)的數(shù)據(jù)庫

  • 數(shù)據(jù)庫主要由dict和expires兩個字典構(gòu)成,其中dict保存鍵值對,而expires則保存鍵的過期時間。
    數(shù)據(jù)庫的鍵總是一個字符串對象,而值可以是任意一種 Redis 數(shù)據(jù)類型,包括字符串、哈希、集合、列表和有序集。

  • expires的某個鍵和dict的某個鍵共同指向同一個字符串對象,而expires 鍵的值則是該鍵以毫秒計算的 UNIX 過期時間戳。

  • Redis使用惰性刪除和定期刪除兩種策略來刪除過期的鍵。

  • 更新后的RDB文件和重寫后的AOF文件都不會保留已經(jīng)過期的鍵。

  • 當(dāng)一個過期鍵被刪除之后,程序會追加一條新的DEL命令到現(xiàn)有AOF文件末尾。

  • 當(dāng)主節(jié)點刪除一個過期鍵之后,它會顯式地發(fā)送一條DEL命令到所有附屬節(jié)點,而從節(jié)點是不會主動刪除某個key,這樣保證主從一致性問題。

  • ?

    一名正在搶救的coder

    筆名:mangolove

    CSDN地址:https://blog.csdn.net/mango_love

    GitHub地址:https://github.com/mangoloveYu

    ?

    ?

    總結(jié)

    以上是生活随笔為你收集整理的Redis数据库实现原理(划重点)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。