1. 服務器中的資料庫
Redis服務器將所有資料庫都保存在服務器狀態redis.h / redisServer結構的db陣列中,db陣列的每個項都是一個redis.h/redisDb結構,每個redisDb結構代表一個資料庫:
2. 切換資料庫
3. 資料庫鍵空間
Redis是一個鍵值對資料庫服務器,服務器中的每個資料庫由一個redis.h/redisDb結構表示,其中,redisDb結構的dict字典保存了資料庫中所有的鍵值對,稱這個字典為鍵空間,
3.1 添加新鍵
![]()
3.2 洗掉鍵
![]()
3.3 更新鍵
![]()

3.4 對鍵取值
3.5 讀寫鍵空間時的維護操作
當使用redis命令對資料庫進行讀寫時,服務器不僅會對鍵空間執行指定的讀寫操作,還會執行一些額外的維護操作,包括:
- 在讀取一個鍵后(讀和寫操作都要對鍵進行讀取),服務器會根據鍵是否存在來更新服務器的鍵空間命中(hit)次數或鍵空間不命中(miss)次數
- 在讀取一個鍵后,服務器會更新鍵的LRU(最后一次使用)時間
- 如果服務器在讀取一個鍵時,發現鍵已過期,服務器會先洗掉過期鍵,再執行余下操作
- 如果有客戶端使用WATCH命令監視了某個鍵,服務器在對被監視的鍵進行修改后,會將這個鍵標記為臟(在事務一章會介紹)
- 服務器每修改一個鍵之后,都會對臟鍵計數器的值增1,這個計數器會觸發服務器的持久化和復制操作(在持久化和復制議長中介紹)
- 如果服務器開啟了資料庫通知功能,在對鍵進行修改之后,服務器將按配置發送相應的資料庫通知(發布和訂閱一章中介紹)
4. 設定鍵的生存時間或過期時間
4.1 設定過期時間
- EXPIRE<key> <ttl> 鍵的生存時間為 ttl ( time to live ) 秒
- PEXPIRE<key> <ttl> 鍵的生存時間為 ttl ( time to live ) 毫秒
- EXPIREAT <key> <timestamp> 命令用于將鍵的過期時間設定為timestamp所指定的秒時間戳
- PEXPIREAT <key> <timestamp> 命令用于將鍵的過期時間設定為timestamp所指定的毫秒時間戳
4.2 移除過期鍵
PERSIST命令用于移除過期鍵,

4.3 計算并回傳剩余生存時間
TTL 命令以秒回傳鍵的生存時間,PTTL以毫秒回傳鍵的生存時間,

5. 過期鍵洗掉策略
- 定時洗掉(占用太多的CPU時間,影響服務器的回應時間和吞吐量)
在設定鍵的過期時間的同時,創建一個定時器(timer),讓定時器在鍵的過期時間來臨時,立即執行對鍵的洗掉操作,
- 惰性洗掉(浪費記憶體,有記憶體泄漏風險)
放任鍵過期不管,但是每次從鍵空間獲取鍵時,都檢查取得的鍵是否過期,如果過期,就洗掉該鍵;如果沒有過期,就回傳該鍵,
- 定期洗掉
每隔一段時間,程式就對資料庫進行一次檢查,洗掉里面的過期鍵,
6. Redis過期鍵洗掉策略
Redis服務器使用惰性洗掉和定期洗掉兩種策略,
6.1 惰性洗掉策略

6.2 定期洗掉策略的實作
過期鍵的定期洗掉策略由redis.c/activeExpireCycle函式實作,每當Redis的服務器周期性操作redis.c/serverCron函式時,activeExpireCycle函式就會被呼叫,整個程序的偽碼描述如下:
# 默認每次檢查的資料庫數量 DEFAULT_DB_NUMBERS = 16 # 默認每個資料庫檢查的鍵數量 DEFAULT_KEY_NUMBERS = 20 # 全域變數,記錄檢查進度 current_db = 0 def activeExpireCycle(): # 初始化要檢查資料庫的數量 # 如果服務器的資料庫數量比DEFAULT_DB_NUMBERS 要小 # 那么以服務器的資料庫數量為準 if server.dbnum < DEFAULT_DB_NUMBERS: db_numbers = server.dbnum else: db_numbers = DEFAULT_DB_NUMBERS # 遍歷各個資料庫 for i in range(db_numbers): # 如果current_db的值等于服務器的資料庫數量 # 這表示檢查程式已經遍歷了服務器的所有資料庫一次 # 將current_db重置為0,開始新的一輪遍歷 if current_db == server.dbnum: current_db = 0 # 獲取當前要處理的資料庫 redisDb = server.db[current_db] # 將資料庫索引增1,指向下一個要處理的資料庫 current_db += 1 # 檢查資料庫鍵 for j in range(DEFAULT_KEY_NUMBERS): # 如果資料庫中沒有一個鍵帶有過期時間,那么跳過這個資料庫 if redisDb.expires.size() == 0 : break # 隨機獲取一個帶有過期時間的鍵 key_with_ttl = redisDb.expires.get_random_key() # 檢查鍵是否過期,如果過期就洗掉它 if is_expired(key_with_ttl): delete_key(key_with_ttl) # 已達到時間上限,停止處理 if reach_time_limit() : return
7 AOF、RDB和復制功能對過期鍵的處理
7.1 生成RDB檔案
在執行SAVE或BGSAVE命令創建一個新的RDB檔案時,程式會對資料庫中的鍵進行檢查,已過期的鍵不會被保存到新創建的RDB檔案中,
7.2 載入RDB檔案
在啟動Redis服務器時,如果服務器開啟了RDB功能,那么服務器會對RDB檔案進行載入:
- 如果服務器以主服務器模式運行,在載入RDB檔案時,程式會對檔案中保存的鍵進行檢查,只有未過期的鍵會被載入到資料庫中
- 如果服務器以從服務器運行,載入RDB檔案時,檔案中保存的所有鍵,無論過期與否都會被載入到資料庫中
7.3 AOF檔案寫入
當服務器以AOF持久化模式運行時,如果資料庫中的某個鍵已經過期,且被惰性洗掉或定期洗掉之后,程式會向AOF檔案追加一條DEL命令,顯式記錄該鍵已被洗掉,
7.4 AOF重寫
和生成RDB檔案時類似,在執行AOF重寫的程序中,程式會對資料庫中的鍵進行檢查,已過期的鍵不會被保存到重寫后的AOF檔案中
7.5 復制
當服務器運行在復制模式下時,從服務器的過期鍵洗掉動作由主服務器控制:
- 主服務器在洗掉一個過期鍵后,會顯式地向所有從服務器發送一個DEL命令,告知從服務器洗掉這個過期鍵
- 從服務器在執行客戶端發送的讀命令時,即使碰到過期鍵,也不會將過期鍵洗掉
- 從服務器只有在接到主服務器地DEL命令之后,才會洗掉過期鍵
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/296141.html
標籤:其他
上一篇:第二章 物件
