網站首頁 編程語言 正文
1.服務器和客戶端實現的數據庫
?Redis服務器在啟動時,會根據redis.conf文件的中databases xx
這個配置決定創建多少個數據庫(默認配置是16),啟動后默認使用的0號數據庫,當然可以使用select dbnum
這個命令來切換。需要注意的是在redis集群模式下,只有0號數據庫可以用,是無法切換到其他庫的。
?Redis服務器會將所有的數據庫都保存在服務器狀態的redisServer的db數組中,數組的每一項都代表了一個數據庫,用redisDb結構來表示,首先看一下redisServer.db的源碼:
struct redisServer { ... // 代表數據庫的數組 redisDb *db; // 這個記錄的配置文件中數據庫的數量 int dbnum; ... }
?我們通過客戶端向Redis寫入的任何數據都會記錄到這個db數組中,根據前面描述,我們知道可以通過select命令切換到另一個目標數據庫,但是客戶端是怎么記錄的它當前操作的哪個數據庫呢?我們繼續看一下源碼:
typedef struct client { ... // 指針指向當前客戶端正在操作的數據庫 redisDb *db; /* Pointer to currently SELECTed DB. */ ... } client;
?看,在client客戶端狀態中,有一個db指針,指向了server.db數組中的某一項,代表了當前客戶端正在操作的數據庫。所以通過切換client.db的指針,調整客戶端操作的數據庫,這就是select命令的實現原理。
2.數據庫字典的實現
?Redis是支持key-value鍵值對存儲的,這其實是通過dict結構來實現的,在前面講到的內容中,服務器和客戶端都指向了一個redisDb的結構,在這個db結構中,就包含存儲了鍵值對的字典結構,首先看一下源碼:
typedef struct redisDb { ... // 這個存放的就是鍵值對 dict *dict; /* The keyspace for this DB */ // 這個存放的是鍵值對的過期時間,下面一節會說到 dict *expires; /* Timeout of keys with a timeout set */ ... } redisDb;
?dict這個指針就指向了存儲鍵值對的字典結構,key是字符串robj類型,value可以是任何的robj類型。當我們分別新增、刪除、更新或者查詢的時候,其實就是根據輸入的key在這個字典上做curd的操作。我們在Redis寫入兩個鍵值對,圖示如下:
?除了對數據庫鍵值對的curd操作,基于整個數據操作的一些命令也是在這個dict上面實現的,比如清空所有鍵值對的flushdb,或者exists、del、dbsize命令等等。在執行命令前后,redis還會執行一些其他操作,比如檢查是否超出最大內存,更新lru時間,記錄慢查詢日志,或者向monitor客戶端發送命令等等,這就是redis數據字典的實現原理。
3.鍵值對的生命周期管理
?這里說的生命周期,其實就是指鍵值對的過期時間。通常我們使用expire key
這個命令設置鍵的過期時間,但其實Redis是有四個命令支持設置過期時間的:
-
expire key seconds
將key的生命周期設置為second秒; -
pexpire key milliseconds
將key的生命周期設置為milliseconds毫秒; -
expireat key timestamp
將key的過期時間設置在timestamp這個秒的時間戳過期; -
pexpireat key timestamp
將key的過期時間設置在timestamp這個毫秒的時間戳過期;
?值得說明的是,雖然有這么多命令支持設置過期時間,但是最終經過轉換都是指向pexpireat
這一個命令來實現?,F在的問題是,這么多鍵值對的過期時間,在redis服務端是怎么保存和維護的呢?
?前面在看redisDb源碼的時候,有一個expires屬性,我們再把源碼拿過來看一下:
typedef struct redisDb { ... // 這個存放的是鍵的過期時間 dict *expires; /* Timeout of keys with a timeout set */ ... } redisDb;
?這就很清晰了,通過expires這個指針,指向了一個dict結構,字典中記錄的就是所有鍵值對的過期時間。其中,key是鍵值對的鍵,value是long類型的毫秒精度的unix時間戳,即過期的時間點。值得注意的是,保存鍵值對的dict字典和保存過期時間的expires字典,key指針都指向相同的一個鍵字符串對象,所以在內存空間上是不會存在浪費的。
?除此之外,跟過期時間操作相關的兩個命令,當然也是基于expires這個字典來實現的:
-
ttl
返回鍵值對的剩余時間 -
persist
刪除鍵值對的過期時間
4.過期鍵的管理策略
?既然有過期時間,那么鍵值對過期之后,是不是立即被刪除了呢?答案肯定不是,redis通過惰性刪除和定期刪除兩種策略實現對過期鍵的管理:
- 惰性刪除策略:當程序訪問到某個鍵值對的時候,會對過期時間檢查,如果過期就刪除,否則不處理。
- 定期刪除策略:基于serverCron時間事件函數,從一定數量的數據庫中取出一定數量的隨機鍵進行檢查,并刪除其中過期的鍵值對。
?使用這兩種過期鍵管理策略可以最大程度上在合理使用CPU時間和避免浪費內存空間之間取得平衡。
5.持久化對過期鍵的處理
rdb 持久化
- save或者bgsave會檢查鍵的過期時間,已過期的鍵不會保存到的持久化的rdb文件中。
- 服務器啟動載入rdb文件時,如果是主服務器,過期鍵會被忽略加載;如果是從服務器,不論是否過期,都會被加載。
aof 持久化
- 寫入aof文件時,key是會寫入的,過期之后,通過追加del命令,才會顯示的刪除此過期鍵。
- bgrewriteaof 重寫時會檢查鍵的過期時間,已過期的鍵不會寫入新的aof文件中。
- 服務器啟動載入aof文件時,過期鍵也會被忽略,不會被加載。
6.主從復制對過期鍵的處理
?主從復制,為了保證數據的一致性,通常由主服務器執行更新的操作,然后將命令發送給從服務器。在3.2版本之前,由于惰性刪除策略的存在,主服務器遇到對過期鍵的訪問,會刪除此鍵值對,并給客戶端返回null值,但是從服務器由于不能執行刪除操作,即便是此鍵已過期,也會返回對應的value值,出現數據不一致導致的臟讀問題。
?在3.2版本之后,這個問題得到了修改,從服務器會判斷當前鍵是否過期,如果已過期并且是從服務器的話,也會返回null值。
原文鏈接:https://blog.csdn.net/qq_35850405/article/details/127937100
相關推薦
- 2023-02-17 python中列表推導式與生成器表達式對比詳解_python
- 2024-03-22 解決springboot錯誤頁面exception、message取值為空
- 2022-06-19 Rainbond使用Dockerfile構建便捷應用運行流程_云其它
- 2023-10-16 element--el-input限制輸入為數字且必須大于0
- 2022-09-09 C++中vector<vector<int>?>的基本使用方法_C 語言
- 2023-01-12 Golang遠程調用框架RPC的具體使用_Golang
- 2022-04-17 python中lambda匿名函數詳解_python
- 2022-04-19 python 讀寫yaml
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支