Redis中的過期鍵以及如何刪除的?

2021-01-11 一線IT民工

勤能補拙是良訓,一分耕耘一分才。——華羅庚

引導語

Redis伺服器的資料庫實現進行詳細介紹,說明伺服器保存資料庫的方法,客戶端切換資料庫的方法,資料庫保存鍵值對的方法,以及針對資料庫的添加、刪除、查看、更新操作的實現方法等。除此之外,本章還會說明伺服器保存鍵的過期時間的方法,以及伺服器自動刪除過期鍵的方法。

1 伺服器中的資料庫

Redis伺服器將所有資料庫都保存在伺服器狀態redis.h/redisServer結構的db數組中,db數組的每個項都是一個redis.h/redisDb結構,每個redisDb結構代表一個資料庫:

struct redisServer {

//一個數組,保存著伺服器中的所有資料庫

redisDb *db;

};

在初始化伺服器時,程序會根據伺服器狀態的dbnum屬性來決定應該創建多少個資料庫:

struct redisServer {

//伺服器的資料庫數量

int dbnum;

};

dbnum屬性的值由伺服器配置的database選項決定,默認情況下,該選項的值為16,所以Redis伺服器默認會創建16個資料庫。

2 切換資料庫

每個Redis客戶端都有自己的目標資料庫,每當客戶端執行資料庫寫命令或者資料庫讀命令的時候,目標資料庫就會成為這些命令的操作對象。

默認情況下,Redis客戶端的目標資料庫為0號資料庫,但客戶端可以通過執行SELECT命令來切換目標資料庫。

在伺服器內部,客戶端狀態redisClient結構的db屬性記錄了客戶端當前的目標資料庫,這個屬性是一個指向redisDb結構的指針:

typedef struct redisClient {

//記錄客戶端當前正在使用的資料庫

redisDb *db;

} redisClient;

redisClient.db指針指向redisServer.db數組的其中一個元素,而被指向的元素就是客戶端的目標資料庫。

客戶端的目標資料庫為1號資料庫

3 資料庫鍵空間

Redis是一個鍵值對資料庫伺服器,伺服器中的每個資料庫都由一個redis.h/redisDb結構表示,其中,redisDb結構的dict字典保存了資料庫中的所有鍵值對,我們將這個字典稱為鍵空間:

typedef struct redisDb {

//資料庫鍵空間,保存著資料庫中的所有鍵值對

dict *dict;

} redisDb;

鍵空間和用戶所見的資料庫是直接對應的:

a. 鍵空間的鍵也就是資料庫的鍵,每個鍵都是一個字符串對象。

b. 鍵空間的值也就是資料庫的值,每個值可以是字符串對象、列表對象、哈希表對象、集合對象和有序集合對象中的任意一種Redis對象。

資料庫鍵空間例子

因為資料庫的鍵空間是一個字典,所以所有針對資料庫的操作,比如添加一個鍵值對到資料庫,或者從資料庫中刪除一個鍵值對,又或者在資料庫中獲取某個鍵值對等,實際上都是通過對鍵空間字典進行操作來實現的。

讀寫鍵空間時的維護操作

當使用Redis命令對資料庫進行讀寫時,伺服器不僅會對鍵空間執行指定的讀寫操作,還會執行一些額外的維護操作,其中包括:

a. 在讀取一個鍵之後(讀操作和寫操作都要對鍵進行讀取),伺服器會根據鍵是否存在來更新伺服器的鍵空間命中(hit)次數或鍵空間不命中(miss)次數,這兩個值可以在INFO stats命令的keyspace_hits屬性和keyspace_misses屬性中查看。

b. 在讀取一個鍵之後,伺服器會更新鍵的LRU(最後一次使用)時間,這個值可以用於計算鍵的閒置時間,使用OBJECT idletime命令可以查看鍵key的閒置時間。

c. 如果伺服器在讀取一個鍵時發現該鍵已經過期,那麼伺服器會先刪除這個過期鍵,然後才執行餘下的其他操作,本章稍後對過期鍵的討論會詳細說明這一點。

d. 如果有客戶端使用WATCH命令監視了某個鍵,那麼伺服器在對被監視的鍵進行修改之後,會將這個鍵標記為髒(dirty),從而讓事務程序注意到這個鍵已經被修改過。

e. 伺服器每次修改一個鍵之後,都會對髒(dirty)鍵計數器的值增1,這個計數器會觸發伺服器的持久化以及複製操作。

f. 如果伺服器開啟了資料庫通知功能,那麼在對鍵進行修改之後,伺服器將按配置發送相應的資料庫通知。

4 設置鍵的生存時間或過期時間

通過EXPIRE命令或者PEXPIRE命令,客戶端可以以秒或者毫秒精度為資料庫中的某個鍵設置生存時間(Time To Live,TTL),在經過指定的秒數或者毫秒數之後,伺服器就會自動刪除生存時間為0的鍵。

SETEX命令可以在設置一個字符串鍵的同時為鍵設置過期時間,因為這個命令是一個類型限定的命令(只能用於字符串鍵)。

過期時間是一個UNIX時間戳,當鍵的過期時間來臨時,伺服器就會自動從資料庫中刪除這個鍵。

TTL命令和PTTL命令接受一個帶有生存時間或者過期時間的鍵,返回這個鍵的剩餘生存時間,也就是,返回距離這個鍵被伺服器自動刪除還有多長時間;都是通過計算鍵的過期時間和當前時間之間的差來實現的。

設置過期時間

Redis有四個不同的命令可以用於設置鍵的生存時間(鍵可以存在多久)或過期時間(鍵什麼時候會被刪除):

· EXPIRE<key><ttl>命令用於將鍵key的生存時間設置為ttl秒。

· PEXPIRE<key><ttl>命令用於將鍵key的生存時間設置為ttl毫秒。

· EXPIREAT<key><timestamp>命令用於將鍵key的過期時間設置為timestamp所指定的秒數時間戳。

· PEXPIREAT<key><timestamp>命令用於將鍵key的過期時間設置為timestamp所指定的毫秒數時間戳。

實際上EXPIRE、PEXPIRE、EXPIREAT三個命令都是使用PEXPIREAT命令來實現的。

設置生存時間和設置過期時間的命令之間

保存過期時間

redisDb結構的expires字典保存了資料庫中所有鍵的過期時間,我們稱這個字典為過期字典:

a. 過期字典的鍵是一個指針,這個指針指向鍵空間中的某個鍵對象(也即是某個資料庫鍵)。

b. 過期字典的值是一個long long類型的整數,這個整數保存了鍵所指向的資料庫鍵的過期時間——一個毫秒精度的UNIX時間戳。

typedef struct redisDb {

//過期字典,保存著鍵的過期時間

dict *expires;

} redisDb;

鍵空間的鍵和過期字典的鍵都指向同一個鍵對象,所以不會出現任何重複對象,也不會浪費任何空間。

移除過期時間

PERSIST命令可以移除一個鍵的過期時間。

PERSIST命令就是PEXPIREAT命令的反操作:PERSIST命令在過期字典中查找給定的鍵,並解除鍵和值(過期時間)在過期字典中的關聯。

過期鍵的判定

通過過期字典,程序可以用以下步驟檢查一個給定鍵是否過期:

a. 檢查給定鍵是否存在於過期字典:如果存在,那麼取得鍵的過期時間。

b. 檢查當前UNIX時間戳是否大於鍵的過期時間:如果是的話,那麼鍵已經過期;否則的話,鍵未過期。

(*)實現過期鍵判定的另一種方法是使用TTL命令或者PTTL命令,比如說,如果對某個鍵執行TTL命令,並且命令返回的值大於等於0,那麼說明該鍵未過期。在實際中,Redis檢查鍵是否過期的方法和is_expired函數所描述的方法一致,因為直接訪問字典比執行一個命令稍微快一些。

5 Redis的過期鍵刪除策略

如果一個鍵過期了,那麼它什麼時候會被刪除呢?

Redis伺服器實際使用的是惰性刪除和定期刪除兩種策略:通過配合使用這兩種刪除策略,伺服器可以很好地在合理使用CPU時間和避免浪費內存空間之間取得平衡。

惰性刪除策略的實現

過期鍵的惰性刪除策略由db.c/expireIfNeeded函數實現,所有讀寫資料庫的Redis命令在執行之前都會調用expireIfNeeded函數對輸入鍵進行檢查:

· 如果輸入鍵已經過期,那麼expireIfNeeded函數將輸入鍵從資料庫中刪除。

· 如果輸入鍵未過期,那麼expireIfNeeded函數不做動作。

命令調用expireIfNeeded來刪除過期鍵
GET命令的執行過程

定期刪除策略的實現

過期鍵的定期刪除策略由redis.c/activeExpireCycle函數實現,每當Redis的伺服器周期性操作redis.c/serverCron函數執行時,activeExpireCycle函數就會被調用,它在規定的時間內,分多次遍歷伺服器中的各個資料庫,從資料庫的expires字典中隨機檢查一部分鍵的過期時間,並刪除其中的過期鍵。

說明:

· 定時刪除佔用太多CPU時間,影響伺服器的響應時間和吞吐量。

· 惰性刪除浪費太多內存,有內存洩漏的危險。

定期刪除策略是前兩種策略的一種整合和折中:

· 定期刪除策略每隔一段時間執行一次刪除過期鍵操作,並通過限制刪除操作執行的時長和頻率來減少刪除操作對CPU時間的影響。

AOF和RDB持久化時對過期鍵的處理,請參考

面試常問道:Redis持久化之RDB》

面試常問道:Redis持久化之AOF》

redis 2.9版本

分享是一種積極的生活態度

相關焦點

  • 機率大的 Redis 面試題(含答案)|內存|key|原子性|哈希|redis_網易...
    單線程的redis為什麼這麼快redis的數據類型,以及每種數據類型的使用場景,Redis 內部結構redis的過期策略以及內存淘汰機制【~】Redis 為什麼是單線程的,優點如何解決redis的並發競爭key問題Redis 集群方案應該怎麼做?都有哪些方案?有沒有嘗試進行多機redis 的部署?如何保證數據一致的?對於大量的請求怎麼樣處理Redis 常見性能問題和解決方案?
  • 面試常問道:Redis持久化之AOF
    在實際中,為了避免在執行命令時造成客戶端輸入緩衝區溢出,重寫程序在處理列表、哈希表、集合、有序集合這四種可能會帶有多個元素的鍵時,會先檢查鍵所包含的元素數量,如果元素的數量超過了redis.h/REDIS_AOF_REWRITE_ITEMS_PER_CMD常量的值,那麼重寫程序將使用多條命令來記錄鍵的值,而不單單使用一條命令。
  • Redis教程:Redis持久化方式
    比如說, 以下設置會讓 Redis 在滿足「 60 秒內有至少有 1000 個鍵被改動」這一條件時, 自動保存一次數據集:save 60 1000這種持久化方式被稱為快照 snapshotting.子進程將數據集寫入到一個臨時 RDB 文件中。當子進程完成對新 RDB 文件的寫入時,Redis 用新 RDB 文件替換原來的 RDB 文件,並刪除舊的 RDB 文件。這種工作方式使得 Redis 可以從寫時複製(copy-on-write)機制中獲益。
  • redis cluster 集群管理工具
    :將新節點加入集群 del-node:從集群中刪除節點 set-timeout:設置集群節點間心跳連接的超時時間 call:在集群全部節點上執行命令 import:將外部redis數據導入集群 常用例子1、create創建集群:create命令可選replicas參數,replicas
  • redis cluster-cluster 命令手動管理redis集群
    使用cluster命令管理redis cluster集群1、列印集群的信息 CLUSTER INFO cluster_state:okcluster_slots_assigned:16384cluster_slots_ok:16384cluster_slots_pfail
  • redis cluster 之master 選舉過程
    在redis 3.0版本後,官方推出了redis cluster 分布式解決方案,當一個redis節點掛了可以快速地切換到另一個節點。當遇到單機內存、並發等瓶頸時,可以採用分布式方案要解決問題.redis-cluster架構中,被設計成共有16384(2的14次方)個hash slot。每個master分得一部分slot,其算法為:hash_slot = crc16(key) mod 16384 ,這就找到對應slot。群集至少需要3主3從,且每個實例使用不同的配置文件。
  • redis - aof持久化介紹
    AOF文件保存了歷史所有的操作過程;當redis server需要數據恢復的時候,可以直接從該文件中讀取日誌進行重做就可以還原。AOF配置打開aof配置,只要在配置文件裡面寫入對應的參數開關,並寫上對應的aof文件的位置即可。
  • Python使用redis存儲對象
    Python總的對象存儲到redis中默認為字符串,那麼如何存儲對象呢?下面就看看如何直接將Python中對象存儲到redis中先寫個測試redis是否正常連接上import rediscache = redis.StrictRedis('172.20.0.227',6379)
  • 詳解Redis持久化(RDB和AOF)
    舉例說明:比如Redis使用五條rpush命令分別插入五種顏色AOF重寫後RPUSH color 〝yellow〝 〝green〝 〝black〝 〝pink〝〝white〝所以AOF重寫的原理:● AOF 文件重寫功能會丟棄過期的數據,也就是過期的數據不會被寫入 AOF 文件中。
  • Redis的批量操作是什麼?怎麼實現的延時隊列?以及訂閱模式、LRU
    前言這次的內容是我自己為了總結Redis知識而擴充的,上一篇其實已經總結了幾點知識了,但是Redis的強大,以及適用範圍之廣可不是單單一篇博文就能總結清的。所以這次準備繼續總結,因為第一個問題,Redis的批量操作,是我在面試過程中被真實問到的,當時沒答上來,也是因為確實沒了解過Redis的批量操作。
  • 面試必問的 Redis:RDB、AOF、混合持久化
    時間事件中常見的就是 serverCron,redis 核心流程中通常也只有這個時間事件。serverCron 默認配置下每100ms會被觸發一次,在該時間事件中,會執行很多操作:清理過期鍵、AOF 後臺重寫、RDB 的 save point 的檢查、將 aof_buf 內容寫到磁碟上(flushAppendOnlyFile 函數)等等。
  • Redis如何存儲和計算一億用戶的活躍度
    01前段時間,在網上看到一道面試題:如何用redis存儲統計1億用戶一年的登陸情況,並快速檢索任意時間窗口內的活躍用戶數量。覺得很有意思,就仔細想了下 。並做了一系列實驗,自己模擬了下 。還是有點收穫的,現整理下來。
  • Redis持久化和備份
    而一個持續寫入的資料庫如何生成快照呢。Redis藉助了fork命令的copy on write機制。在生成快照時,將當前進程fork出一個子進程,然後在子進程中循環所有的數據,將數據寫成為RDB文件。比如如下命令redis 127.0.0.1:6379> set key1 HelloOKredis 127.0.0.1:6379> append key1 " World!"
  • 詳解Redis中兩種持久化機制RDB和AOF(面試常問,工作常用)
    現在主要考慮的是redis如何來實現上面5個保存磁碟的步驟。它提供了兩種策略機制,也就是RDB和AOF。二、RDB機制RDB其實就是把數據以快照的形式保存在磁碟上。什麼是快照呢,你可以理解成把當前時刻的數據拍成一張照片保存下來。RDB持久化是指在指定的時間間隔內將內存中的數據集快照寫入磁碟。
  • Redis 設計與實現 4:字典
    Redis 中,字典是基礎結構。Redis 資料庫數據、過期時間、哈希類型都是把字典作為底層結構。字典的結構哈希表哈希表的實現代碼在:dict.h/dictht ,Redis 的字典用哈希表的方式實現。
  • 大數據必學:redis深入了解 Redis 的持久化機制(RDB、AOF)
    因為 redis是一個內存資料庫,所有數據都存儲在內存中,而且內存中的數據非常容易丟失,所以 redis的數據持久化就變得非常重要, redis提供了兩種數據持久化方法,分別用於 RDB和 AOF,而 redis默認用於 RDB的數據持久化方法。
  • 微信附近的人,用redis也能實現?(GEO)
    ,又得遍歷計算上述方式如果用戶量比較小其實是可以實現的,但是現在移動網際網路公司一般用戶體量都很大,全表遍歷的方式基本都可以 pass 掉,所以接下來我們來看一種新的方案,用 redis geo 的方式來實現redis geo 介紹首先我們需要注意的是,redis geo 是 3.2 版本才有的,所以需要用這個功能的朋友記得更新 redis 的版本其實 redis
  • Redis 3.0.0 RC4 發布,無 Redis Cluster 修復
    此版本包括關於 redis-cli 方面的新特性,一個使用 xterm 256 顏色的延遲光譜可視化工具。Reids 團隊計劃兩周後發布一個 RC 版本或者是 3.0.0 穩定版本。Reids 3.0.0.RC4 常規改進:* [FIX] redis-cli CSV output NIL spurious newline removed.
  • Redis 的 8 大數據類型,寫得非常好!(建議收藏)
    和setnx(set if not exist):不存在再設置(在分布式鎖中會經常使用)127.0.0.1:6379> setex key3 30 "hello" # 設置 30 秒後過期OK127.0.0.1:6379> ttl key3 # 剩餘過期時間(integer) 25127.0.0.1:6379> setnx
  • 如何刪除word文檔中的空白頁
    我們通常在使用word寫文章或者論文的時候,大多數情況是需要給別人閱讀的,不管是電子版還是列印版本,如果word文檔中出現空白頁,就會很大程度上影響讀者的閱讀,那麼如何刪除word文檔中出現的空白頁呢,今天就給大家介紹一下三種不同情況出現的空白頁,應該如何刪除。