redis - 为什么redis中hashmap的负载因子高达5

标签 redis hashmap load-factor

在算法类和授权书籍中,负载因子小于 1,就像 Java 一样,默认值为 0.75。但在redis源码中,负载因子是5。

54 /* Using dictEnableResize() / dictDisableResize() we make possible to
55  * enable/disable resizing of the hash table as needed. This is very important
56  * for Redis, as we use copy-on-write and don't want to move too much memory
57  * around when there is a child performing saving operations.
58  *
59  * Note that even when dict_can_resize is set to 0, not all resizes are
60  * prevented: a hash table is still allowed to grow if the ratio between
61  * the number of elements and the buckets > dict_force_resize_ratio. */
62 static int dict_can_resize = 1;
63 static unsigned int dict_force_resize_ratio = 5;

为什么会这样?

最佳答案

开始重新哈希的负载因子约为 1。 dict_force_resize_ratio 值是一项安全措施,即使禁用重新哈希,一旦达到该负载因子,它也会强制执行。

您可以在dict.c中的_dictExpandIfNeeded(dict *d)中看到这一点

/* If we reached the 1:1 ratio, and we are allowed to resize the hash
 * table (global setting) or we should avoid it but the ratio between
 * elements/buckets is over the "safe" threshold, we resize doubling
 * the number of buckets. */
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);
}

Redis 允许 ~1 开始重新哈希,因为重新哈希不是一次性完成的。这是通过维护两个哈希表逐步完成的。

参见dict.h:

/* This is our hash table structure. Every dictionary has two of this as we
 * implement incremental rehashing, for the old to the new table. */
typedef struct dictht {
    dictEntry **table;
    unsigned long size;
    unsigned long sizemask;
    unsigned long used;
} dictht;

typedef struct dict {
    dictType *type;
    void *privdata;
    dictht ht[2];
    long rehashidx; /* rehashing not in progress if rehashidx == -1 */
    unsigned long iterators; /* number of iterators currently running */
} dict;

dict.c中:

/* 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) {...

redis.conf 中还有一些针对 activerehashing 设置的额外见解。

# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in
# order to help rehashing the main Redis hash table (the one mapping top-level
# keys to values). The hash table implementation Redis uses (see dict.c)
# performs a lazy rehashing: the more operation you run into a hash table
# that is rehashing, the more rehashing "steps" are performed, so if the
# server is idle the rehashing is never complete and some more memory is used
# by the hash table.
#
# The default is to use this millisecond 10 times every second in order to
# actively rehash the main dictionaries, freeing memory when possible.
#
# If unsure:
# use "activerehashing no" if you have hard latency requirements and it is
# not a good thing in your environment that Redis can reply from time to time
# to queries with 2 milliseconds delay.
#
# use "activerehashing yes" if you don't have such hard requirements but
# want to free memory asap when possible.
activerehashing yes

关于redis - 为什么redis中hashmap的负载因子高达5,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59567447/

相关文章:

c# - StackExchange.Redis 在 for 循环上进行管道传输?

c# - Redis:当删除项目存在于多个列表并设置时

java - 如何将 Java Hashmap 保存为 sql 表中的属性并将其加载回来

java - 如何创建包含所有java类常量的HashMap或Arraylist

java - Hashmap loadfactor - 基于占用的桶数或所有桶中的条目数?

amazon-web-services - CodeIgniter 3 Redis 支持的 session 性能和可扩展性

redis - 使用前缀匹配模式的 redis 扫描是否扫描数据库中的所有键?

java - 根据具有长值的值对映射进行排序

java - HashMap 容量即使达到阈值也不会增加