历史文章
Redis源码阅读之字典(一)
Redis Rehash是什么?
在我们日常使用redis的过程中,随着key不断的增加,dict的size也在不断的增加,当dict.used == dict.size或者used*100/size < HASHTABLE_MIN_FILL,HASHTABLE_MIN_FILL一般为10,也就是说,要么容量不够,要么容量使用率小于10%了,就会调用dictExpand进行重新分配内存,这个时候就会触发rehash了。但是rehash不行一次性就操作完成了,试想一下,如果一个dict里面含有数百万的key,rehash一次可能会很久,就可能造成服务假死的情况。所以rehashing是一个长时间的过程,每一次可能只进行几个key的迁移。
哪些操作会触发rehashing的step
dictRehashMilliseconds
redis server的定时任务会去执行dictRehashMilliseconds,但是都是传入的ms==1,主要是rehashing一下redis的dict和expired相关的键
dictAddRaw
在给dict增加key的时候,新增的key会直接放入dict.ht[1]中
dictGenericDelete
删除key时
dictFind
查找key
dictGetRandomKey 和 dictGetSomeKeys
获取随机key
dictScan
遍历dict
每次rehash的过程
源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
/* Performs N steps of incremental rehashing. Returns 1 if there are still
* keys to move from the old to the new hash table, otherwise 0 is returned.
*
* Note that a rehashing step consists in moving a bucket (that may have more
* than one key as we use chaining) from the old to the new hash table, however
* since part of the hash table may be composed of empty spaces, it is not
* guaranteed that this function will rehash even a single bucket, since it
* will visit at max N*10 empty buckets in total, otherwise the amount of
* work it does would be unbound and the function may block for a long time. */
int dictRehash(dict *d, int n) {
int empty_visits = n*10; /* Max number of empty buckets to visit. */
if (!dictIsRehashing(d)) return 0;
while(n-- && d->ht[0].used != 0) {
dictEntry *de, *nextde;
/* Note that rehashidx can't overflow as we are sure there are more
* elements because ht[0].used != 0 */
assert(d->ht[0].size > (unsigned long)d->rehashidx);
while(d->ht[0].table[d->rehashidx] == NULL) {
d->rehashidx++;
if (--empty_visits == 0) return 1;
}
de = d->ht[0].table[d->rehashidx];
/* Move all the keys in this bucket from the old to the new hash HT */
while(de) {
uint64_t h;
nextde = de->next;
/* Get the index in the new hash table */
h = dictHashKey(d, de->key) & d->ht[1].sizemask;
de->next = d->ht[1].table[h];
d->ht[1].table[h] = de;
d->ht[0].used--;
d->ht[1].used++;
de = nextde;
}
d->ht[0].table[d->rehashidx] = NULL;
d->rehashidx++;
}
/* Check if we already rehashed the whole table... */
if (d->ht[0].used == 0) {
zfree(d->ht[0].table);
d->ht[0] = d->ht[1];
_dictReset(&d->ht[1]);
d->rehashidx = -1;
return 0;
}
/* More to rehash... */
return 1;
}
|