jtoken判断是否包含键_Redis 数据库、键过期的实现
今天看看作為內(nèi)存數(shù)據(jù)庫,Redis 是怎么存儲(chǔ)數(shù)據(jù)的以及鍵是怎么過期的。
閱讀這篇文章你將會(huì)了解到:
- Redis 的數(shù)據(jù)庫實(shí)現(xiàn)
- Redis 鍵過期的策略
數(shù)據(jù)庫的實(shí)現(xiàn)
我們先看代碼 server.h/redisServer
struct redisServer{ ... //保存 db 的數(shù)組 redisDb *db; //db 的數(shù)量 int dbnum; ...}再看redisDb的代碼:
typedef struct redisDb { dict *dict; /* The keyspace for this DB */ dict *expires; /* Timeout of keys with a timeout set */ dict *blocking_keys; /* Keys with clients waiting for data (BLPOP)*/ dict *ready_keys; /* Blocked keys that received a PUSH */ dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */ int id; /* Database ID */ long long avg_ttl; /* Average TTL, just for stats */} redisDb;總體來說redis的 server 包含若干個(gè)(默認(rèn)16個(gè)) redisDb 數(shù)據(jù)庫。
Redis 是一個(gè) k-v 存儲(chǔ)的鍵值對(duì)數(shù)據(jù)庫。其中字典 dict 保存了數(shù)據(jù)庫中的所有鍵值對(duì),這個(gè)地方叫做 keyspace 直譯過來就是“鍵空間”。
所以我們就可以這么認(rèn)為,在 redisDb 中我們使用 dict(字典)來維護(hù)鍵空間。
- keyspace 的 kay 是數(shù)據(jù)庫的 key,每一個(gè)key 是一個(gè)字符串對(duì)象。注意不是字符串,而是字符串對(duì)象。
- keyspace 的 value 是數(shù)據(jù)庫的 value,這個(gè) value 可以是 redis 的,字符串對(duì)象,列表對(duì)象,哈希表對(duì)象,集合對(duì)象或者有序?qū)ο笾械囊环N。
數(shù)據(jù)庫讀寫操作
所以對(duì)于數(shù)據(jù)的增刪改查,就是對(duì) keyspace 這個(gè)大 map 的增刪改查。
當(dāng)我們執(zhí)行:
>redis SET mobile "13800000000"實(shí)際上就是為 keyspace 增加了一個(gè) key 是包含字符串“mobile”的字符串對(duì)象,value 為包含字符“13800000000”的字符串對(duì)象。
看圖:
對(duì)于刪改查,沒啥好說的。類似java 的 map 操作,大多數(shù)程序員應(yīng)該都能理解。
需要特別注意的是,再執(zhí)行對(duì)鍵的讀寫操作的時(shí)候,Redis 還要做一些額外的維護(hù)動(dòng)作:
- 維護(hù) hit 和 miss 兩個(gè)計(jì)數(shù)器。用于統(tǒng)計(jì) Redis 的緩存命中率。
- 更新鍵的 LRU 時(shí)間,記錄鍵的最后活躍時(shí)間。
- 如果在讀取的時(shí)候發(fā)現(xiàn)鍵已經(jīng)過期,Redis 先刪除這個(gè)過期的鍵然后再執(zhí)行余下操作。
- 如果有客戶對(duì)這個(gè)鍵執(zhí)行了 WATCH 操作,會(huì)把這個(gè)鍵標(biāo)記為 dirty,讓事務(wù)注意到這個(gè)鍵已經(jīng)被改過。
- 沒修改一次 dirty 會(huì)增加1。
- 如果服務(wù)器開啟了數(shù)據(jù)庫通知功能,鍵被修改之后,會(huì)按照配置發(fā)送通知。
鍵的過期實(shí)現(xiàn)
Redis 作為緩存使用最主要的一個(gè)特性就是可以為鍵值對(duì)設(shè)置過期時(shí)間。就看看 Redis 是如果實(shí)現(xiàn)這一個(gè)最重要的特性的?
在 Redis 中與過期時(shí)間有關(guān)的命令
- EXPIRE 設(shè)置 key 的存活時(shí)間單位秒
- EXPIREAT 設(shè)置 key 的過期時(shí)間點(diǎn)單位秒
- PEXPIRE 設(shè)置 key 的存活時(shí)間單位毫秒
- PEXPIREAT 設(shè)置 key 的過期時(shí)間點(diǎn)單位毫秒
其實(shí)這些命令,底層的命令都是由 REXPIREAT 實(shí)現(xiàn)的。
在 redisDb 中使用了 dict *expires,來存儲(chǔ)過期時(shí)間的。其中 key 指向了 keyspace 中的 key(c 語言中的指針), value 是一個(gè) long long 類型的時(shí)間戳,標(biāo)定這個(gè) key 過期的時(shí)間點(diǎn),單位是毫秒。
如果我們?yōu)樯衔牡?mobile 增加一個(gè)過期時(shí)間。
>redis PEXPIREAT mobile 1521469812000這個(gè)時(shí)候就會(huì)在過期的 字典中增加一個(gè)鍵值對(duì)。如下圖:
對(duì)于過期的判斷邏輯就很簡單:
接下來就需要討論一下過期的鍵的刪除策略。
key的刪除有三種策略:
這三種策略就是對(duì)時(shí)間和空間有不同的傾向。Redis為了平衡時(shí)間和空間,采用了后兩種策略 惰性刪除和定時(shí)部分刪除。
惰性刪除比較簡單,不做過多介紹。主要討論一下定時(shí)部分刪除。
過期鍵的定時(shí)刪除的策略由 expire.c/activeExpireCycle() 函數(shù)實(shí)現(xiàn),server.c/serverCron() 定時(shí)的調(diào)用 activieExpireCycle() 。
activeExpireCycle 的大的操作原則是,如果過期的key比較少,則刪除key的數(shù)量也比較保守,如果,過期的鍵多,刪除key的策略就會(huì)很激進(jìn)。
static unsigned int current_db = 0; /* Last DB tested. */static int timelimit_exit = 0; /* Time limit hit in previous call? */static long long last_fast_cycle = 0; /* When last fast cycle ran. */- 首先三個(gè) static 全局參數(shù)分別記錄目前遍歷的 db下標(biāo),上一次刪除是否是超時(shí)退出的,上一次快速操作是什么時(shí)候進(jìn)行的。
- 計(jì)算 timelimit = 1000000*ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC/server.hz/100; 可以理解為 25% 的 cpu 時(shí)間。
- 如果 db 中 expire 的大小為0 不操作
- expire 占總 key 小于 1% 不操作
- num = dictSize(db->expires);num 是 expire 使用的key的數(shù)量。
- slots = dictSlots(db->expires); slots 是 expire 字典的尺寸大小。
- 已使用的key(num) 大于 ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 則設(shè)置為 ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP。也就是說每次只檢查 ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 個(gè)鍵。
- 隨機(jī)獲取帶過期的 key。計(jì)算是否過期,如果過期就刪除。
- 然后各種統(tǒng)計(jì),包括刪除鍵的次數(shù),平均過期時(shí)間。
- 每遍歷十六次,計(jì)算操作時(shí)間,如果超過 timelimit 結(jié)束返回。
- 如果刪除的過期鍵大于 ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 的 14 就跳出循環(huán),結(jié)束。
步驟比較復(fù)雜,總結(jié)一下:(這里都是以默認(rèn)配置描述)
后記
這篇文章主要解釋了 Redis 的數(shù)據(jù)庫是怎么實(shí)現(xiàn)的,同時(shí)介紹了 Redis 處理過期鍵的邏輯。看 Redis 的代碼越多越發(fā)現(xiàn),實(shí)際上 Redis 一直在做的一件事情就是平衡,一直在平衡程序的空間和時(shí)間。其實(shí)平時(shí)的業(yè)務(wù)設(shè)計(jì),就是在宏觀上平衡,平衡宏觀系統(tǒng)的時(shí)間和空間。所以,看源碼是讓我們從微觀學(xué)習(xí)系統(tǒng)架構(gòu)的良好途徑,是架構(gòu)師的成長的必經(jīng)之路。
總結(jié)
以上是生活随笔為你收集整理的jtoken判断是否包含键_Redis 数据库、键过期的实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: matlab里数组的赋值,arrays
- 下一篇: oracle高资源消耗sql,Oracl