網站首頁 編程語言 正文
我們平時用Redis的時候,只是了解到了它對外的一些結構,如:string、list、set、hash、zset,但是我們卻很少能了解到Redis內部用的存儲結構,小編將在這篇文章和大家秀一下Redis中的一個內部結構——dict。
一、dict是什么
不知道大家在用Redis的時候有沒有注意到,我們在使用大多數Redis命令的時候,都會讓你輸入一個key,后面才會讓你輸入具體的值。
我們本篇文章所述的dict在Redis中最主要的作用就是用于維護Redis數據庫中所有Key、value映射的數據結構,也就是我們在輸入set、zadd等命令時輸入的key與后面值的映射。321,上代碼。代碼來源(dict.h)。 如下代碼所示,dict結構體里面有一個dictht 數組,dictht 里面的dictEntry 就是具體存放key、value映射關系的。
typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;
} dictEntry;
typedef struct dictht {
dictEntry **table;
unsigned long size; // hashtable 容量
unsigned long sizemask; // size -1
unsigned long used; // hashtable 元素個數 used / size =1
} dictht;
typedef struct dict {
dictType *type;
void *privdata;
dictht ht[2];// ht[0] , ht[1] =null
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
unsigned long iterators; /* number of iterators currently running */
} dict;
小貼紙:dictEntry 中用到了union聯合體這種結構。也就是多個變量的結構同時使用一塊內存區域,區域的取值大小為該結構中長度最大的變量的值。這有利于減少內存碎片,提高內存利用率,在Java中的壓縮指針技術就用到了聯合體。
二、dict數據結構
1.結構梳理
我們仔細看上面代碼中的結構,小編可以直接告訴你,其實它就是一個哈希表結構,在Java中相當于一個HashMap,因為Redis需要保證快速響應,所以選擇哈希表作為存儲結構是一個不錯的決定。我們這里只一起了解結構中存具體數據的部分。
- dictEntry:其實它就是一個鏈表結構,里面維護了key、value。
- dictht :它維護了一個dictEntry 指針數組。 雖然我們肉眼能看到定義的是指針的指針,dictEntry **table。但其實指針的指針是指向了dictEntry 數組指針的首地址。Redis源碼里大多會這么用 table[index]。指針這塊有點繞,可以暫時直接認為它就是一個指針數組。
- dict: dict里面維護了一個dictht ht[2] 數組,相當于兩個dictht 結構。為什么要存兩個dictht 結構呢。因為既然是哈希表那就要涉及到擴容,redis是單線程的,不可能一下子將所有的數據都轉移到新的哈希表中,這樣可能會造成服務長時間不可用,所以它退而求其次,選擇了"漸進式擴容"。
小貼紙:Redis中的漸進式擴容,采用的是在內存中放置兩個哈希表結構,無需擴容時,使用的是哈希表0,在擴容期間,將擴容標識設置為true,當有新數據進來的時候,發現正在擴容,就會在將新數據直接放入哈希表1。而表0中的數據會在每次有請求命令并且請求的數據在表0中時,將請求命令涉及到的數據直接掛到表1上。 在擴容期間如果執行查找命令會查找表0+表1的數據。
當然,Redis如果一直不執行命令的話。它也會有一個后臺定時任務,對字典進行主動搬遷,它不會對未完成的事置之不理
// 服務器定時任務
void databaseCron() {
...
if (server.activerehashing) {
for (j = 0; j < dbs_per_call; j++) {
int work_done = incrementallyRehash(rehash_db);
if (work_done) {
/* If the function did some work, stop here, we'll do
* more at the next cron loop. */
break;
} else {
/* If this db didn't need rehash, we'll try the next one. */
rehash_db++;
rehash_db %= server.dbnum;
}
}
}
}
2. 擴容條件
- 當hash表中元素的個數等于數組長度時,就會開始擴容,擴容的新數組是原數組的2倍。
- 當Redis發生其他情況沒有在元素個數等于數組長度時擴容,那么Redis會有一個強制擴容的條件,就是元素個數達到數組長度5倍時進行強制擴容。
/* Expand the hash table if needed */
static int _dictExpandIfNeeded(dict *d)
{
/* Incremental rehashing already in progress. Return. */
if (dictIsRehashing(d)) return DICT_OK;
/* If the hash table is empty expand it to the initial size. */
if (d->ht[0].size == 0) return dictExpand(d, DICT_HT_INITIAL_SIZE);
/* 元素個數大于等于數組長度&&(能擴容(bgsave時盡量不擴容)或元素大于5倍時強制擴容)
* static unsigned int dict_force_resize_ratio = 5;
*/
if (d->ht[0].used >= d->ht[0].size &&
(dict_can_resize ||
d->ht[0].used/d->ht[0].size > dict_force_resize_ratio))
{
return dictExpand(d, d->ht[0].used*2);
}
return DICT_OK;
}
3. 縮容條件
既然有擴容,當前就有縮容,要不占那么大內存不是浪費嗎?
- 當元素小于數組長度的10%時進行縮容。
int htNeedsResize(dict *dict) {
long long size, used;
size = dictSlots(dict);
used = dictSize(dict);
return (size > DICT_HT_INITIAL_SIZE &&
(used*100/size < HASHTABLE_MIN_FILL));
}
dict結構的實現相對來說比較簡單,本文就介紹到這。
原文鏈接:https://juejin.cn/post/7099287570235785223
相關推薦
- 2022-05-24 Asp.net?core?使用SignalR推送消息過程詳解_實用技巧
- 2022-05-19 Python?Timer和TimerFPS計時工具類_python
- 2022-04-10 Blazor數據綁定用法_基礎應用
- 2022-01-05 el-select使用了多選時,選中多個會撐開原始高度,樣式錯亂,使用tag展示,一行顯示全部內容,
- 2022-04-05 關于redis客戶端連接不上
- 2022-10-05 Python實現打印彩色字符串的方法詳解_python
- 2023-04-16 C#使用IronPython調用Python的實現_C#教程
- 2023-01-12 python列表添加元素append(),extend(),insert(),+list的區別及說明
- 最近更新
-
- 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同步修改后的遠程分支