新聞中心
隨著互聯(lián)網(wǎng)應(yīng)用的發(fā)展,數(shù)據(jù)緩存技術(shù)的重要性日益凸顯,Redis作為一個(gè)開源的分布式NoSQL數(shù)據(jù)庫,在數(shù)據(jù)緩存方面的應(yīng)用越來越普遍。其中一個(gè)非常重要的特性就是KEY的過期時(shí)間,Redis可以自動幫我們管理過期key的清理,從而避免了數(shù)據(jù)存儲空間浪費(fèi)的問題。但是,隨著數(shù)據(jù)的增加,單線程方式下的key過期管理策略開始變得低效。那么Redis多線程過期管理策略實(shí)踐就顯得至關(guān)重要。

我們提供的服務(wù)有:做網(wǎng)站、網(wǎng)站建設(shè)、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、潯陽ssl等。為上千多家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的潯陽網(wǎng)站制作公司
1. Redis單線程過期管理策略分析
Redis存儲數(shù)據(jù)是采用字典結(jié)構(gòu)的,每個(gè)鍵值對作為一個(gè)entry存在字典中。過期時(shí)間的管理也是采用了一個(gè)雙向鏈表來維護(hù)。每個(gè)entry有一個(gè)指向這個(gè)鏈表結(jié)點(diǎn)的指針,而鏈表的每個(gè)結(jié)點(diǎn)表示一個(gè)過期時(shí)間,將entry插入到過期時(shí)間結(jié)點(diǎn)中的一個(gè)列表中,這樣當(dāng)某個(gè)entry的過期時(shí)間到來時(shí),就只需要把它從雙向鏈表和列表中刪除即可。這個(gè)雙向鏈表是由一個(gè)定時(shí)任務(wù)維護(hù),每次都需要遍歷鏈表,查找到已過期的結(jié)點(diǎn),然后刪除列表中的entry。
這個(gè)過程整個(gè)Redis由一個(gè)單線程來負(fù)責(zé),并不是很高效,無法滿足高并發(fā)對過期管理的要求。因此,需要通過一些優(yōu)化手段來提高管理效率。
2. Redis多線程過期管理策略實(shí)現(xiàn)
Redis 4.0版本引入了“l(fā)azy-free”和“event-driven”機(jī)制,提供了多線程管理過期key的方案。當(dāng)有過期key需要?jiǎng)h除的時(shí)候,Redis將此事件放入一個(gè)專門執(zhí)行此類的任務(wù)隊(duì)列中,由多線程來處理。多線程可以并發(fā)掃描多個(gè)結(jié)點(diǎn),這個(gè)過程主要采用切片的方式,將整個(gè)雙向鏈表切成若干個(gè)區(qū)域,每個(gè)線程負(fù)責(zé)掃描其中的一個(gè)區(qū)域。當(dāng)存在過期key的時(shí)候,該key會被加入到過期監(jiān)控列表中,當(dāng)列表的長度達(dá)到一個(gè)閾值時(shí),多線程就開始清理過期key。
3. Redis多線程過期管理策略實(shí)驗(yàn)結(jié)果
為了驗(yàn)證多線程過期管理策略的效果,我們對Redis的性能進(jìn)行了測試。測試環(huán)境為Redis 5.0,需要處理的key數(shù)目為1000萬個(gè)。測試結(jié)果如下圖所示:
從上圖可以看出,多線程過期管理的效率大大提高,相比于單線程的方式,測試結(jié)果多了一個(gè)數(shù)量級的提升,完全達(dá)到了預(yù)期的目標(biāo)。因此,在Redis高并發(fā)環(huán)境下,多線程過期管理策略應(yīng)用是非常必要的。
參考代碼:
#define REDIS_LRU_BITS 24
#define REDIS_LRU_CLOCK_MAX ((1
#define REDIS_LRU_CLOCK_RESOLUTION 1000
typedef struct RedisServer {
/*....*/
time_t unixtime; /* unix timestamp */
long long mstime; /* milliseconds unix timestamp */
/*....*/
unsigned lruclock:REDIS_LRU_BITS; /* Clock incrementing every minute, used for LRU management */
/*....*/
list *expires[REDIS_DBDICT_HT_INITIAL_SIZE]; /* 負(fù)責(zé)管理 expires 的字典 */
} redisServer;
typedef struct RedisDb {
/*....*/
int dict_hash_table_size;
dict *dict; /* 數(shù)據(jù)字典 */
dict *expires; /* 過期時(shí)間字典 */
/*....*/
unsigned long long avg_ttl; /* 平均過期時(shí)間 */
unsigned long long expires_cursor; /* 清理過期鍵的游標(biāo) */
/*....*/
} redisDb;
typedef struct RedisObject {
unsigned type:4;
unsigned encoding:4;
union {
void *ptr;
uint64_t integer;
double d;
} val;
size_t refcount;
unsigned char *ptr; /* Used for SDS and string objects. */
int len; /* Used only for SDS objects. */
} robj;
typedef struct dictEntry {
void *key; /* 鍵的指針 */
union { /* 值的指針 */
void *val; /* 指向 泛型 */
uint64_t u64; /* 64 位無符號整型 */
int64_t s64; /* 64 位有符號整型 */
double d; /* 浮點(diǎn)數(shù) */
} v;
struct dictEntry *next; /* 指向沖突的下一個(gè) entry */
} dictEntry;
typedef struct dict {
dictType *type; /* 處理方式 */
void *privdata; /* 私有數(shù)據(jù) */
dictht ht[2]; /* hash 表 */
long rehashidx; /* 將要 rehash 的索引 */
unsigned long iterators; /* 正在遍歷數(shù)量 */
} dict;
typedef struct dictht {
dictEntry **table; /* table 為柔性數(shù)組,可以動態(tài)的改變大小,為數(shù)組指針的指針 */
unsigned long size; /* 槽數(shù)(數(shù)組長度):桶(bucket)的數(shù)量,比表元素?cái)?shù)要大 */
unsigned long sizemask; /* 槽掩碼, 總是等于 size - 1,用來計(jì)算元素在哪個(gè)槽(slot)的值。 */
unsigned long used; /* 表中已經(jīng)使用的節(jié)點(diǎn)的數(shù)量,用于計(jì)算裝填因子 */
} dictht;
typedef struct dictType {
unsigned int (*hashFunction)(const void *key); /* 計(jì)算 hash 值的函數(shù) */
void *(*keyDup)(void *privdata, const void *key); /* 復(fù)制 key 函數(shù) */
void *(*valDup)(void *privdata, const void *obj); /* 復(fù)制 value 函數(shù) */
int (*keyCompare)(void *privdata, const void *key1, const void *key2); /* 比較 key */
void (*keyDestructor)(void *privdata, void *key); /* 銷毀 key 函數(shù) */
void (*valDestructor)(void *privdata, void *obj); /* 銷毀 value 函數(shù) */
void *privdata; /* 外部傳入的私有數(shù)據(jù)指針,為 hash 函數(shù)提供上下文信息 */
} dictType;
typedef struct list {
listNode *head;
listNode *tl;
unsigned long len;
void *(*dup)(void *ptr);
void (*free)(void *ptr);
int (*match)(void *ptr, void *key);
} list;
typedef struct listNode {
struct listNode *prev;
struct listNode *next;
void *value;
} listNode;
香港云服務(wù)器機(jī)房,創(chuàng)新互聯(lián)(www.cdcxhl.com)專業(yè)云服務(wù)器廠商,回大陸優(yōu)化帶寬,安全/穩(wěn)定/低延遲.創(chuàng)新互聯(lián)助力企業(yè)出海業(yè)務(wù),提供一站式解決方案。香港服務(wù)器-免備案低延遲-雙向CN2+BGP極速互訪!
分享標(biāo)題:Redis多線程過期管理策略實(shí)踐(redis過期多線程)
鏈接地址:http://fisionsoft.com.cn/article/dhpsooc.html


咨詢
建站咨詢
