Redis Set中成员占用的字节数

Sha*_*awn 3 c++ memory hashset nosql redis

我使用Redis作为内存中的hashset.在我将一个1M 8字节密钥(二进制)插入一个Set后,我发现Redis USED_MEMORY达到约100M,这意味着一个成员需要100个字节?为什么?

或者我如何配置Redis以节省内存使用量.

Did*_*zia 7

首先,您应该始终详细说明此类问题的设置,因为内存布局取决于操作系统,内存分配器,平台和Redis版本.

在带有Redis 2.4的64位Linux机器上,1M项8字节键的容量为87 MB.

与密钥的大小相比似乎很多,但是支持对其项目的有效访问的任何动态数据结构都涉及开销.您的物品越小,开销越大.

使用Redis,使用单独的链接哈希表实现大型集合.每个条目由以下结构表示:

typedef struct dictEntry {
    void *key;
    void *val;
    struct dictEntry *next;
} dictEntry;
Run Code Online (Sandbox Code Playgroud)

因为内存分配器(jemalloc)不支持24字节类,所以使用32个字节.在这个结构中,val被设置为NULL(这是一个集合),并且键指向一个对象,定义如下:

typedef struct redisObject {
    unsigned type:4;
    unsigned storage:2;     /* REDIS_VM_MEMORY or REDIS_VM_SWAPPING */
    unsigned encoding:4;
    unsigned lru:22;        /* lru time (relative to server.lruclock) */
    int refcount;
    void *ptr;
} robj;
Run Code Online (Sandbox Code Playgroud)

这种结构只需16个字节.它指向关键数据本身,由这个可变长度结构表示:

struct sdshdr {
    int len;
    int free;
   char buf[];
};
Run Code Online (Sandbox Code Playgroud)

密钥是8个字节,加上一个nul char,因此每个密钥的大小为17个字节.下一个分配类是带有jemalloc的32个字节,因此这个结构需要32个字节.

总而言之,每件物品都要花费:32 + 16 + 32 = 80字节.它们有1M个.为哈希表本身添加一些空间(包含至少1M指向dictEntry结构的指针),你得到的结果非常接近我们可以在这个平台上测量的87 MB.

优化大型内存的占用空间并非易事.当集合很小(默认情况下少于512个项目)并且键实际上是整数时,Redis会执行优化.在此处查看更多信息.

一种可能的优化是增加set-max-intset-entries参数,并将该组拆分为多个部分.例如,可以对项目键进行散列以在各种集合上分发项目.而不仅仅是myset,你有myset:0,myset:1,myset:2 ... myset:n.要检查给定项目是否是设置,在密钥上计算哈希值以找到正确的myset:X条目,然后检查此特定条目.目的是使所有这些集合的大小保持在set-max-intset-entries参数之下,以便从内存优化中受益.当然,它使得在集合上完成的所有操作更加复杂,因此它实际上是复杂性和内存占用之间的权衡.