Go map[int64]int64 写入 redis 占用多少内存
我们在系统设计面试或者在实际工作中,免不了要进行一些估算。之前的文章里讲过一些技巧,今天来个实战。
这是我最近在做的一个工作,将内存中的一个超大的 map[int64]int64
写入到 redis,map 里的元素个数是千万级的。设计方案的时候,需要对 redis 的容量做一个估算。
如果不了解 redis 的话,可能你的答案是用元素个数直接乘以 16B(key 和 value 各占 8B)。我们假设元素个数是 5kw,那估算结果就是:5kw * 16B=50kk * 16B = 800MB。
答案是错的。
为了解决这个问题,需要深入地研究一下 redis 的数据结构。
整个 redis 数据库就是一个大的 map,它容纳了所有的 key,我们都知道 key 都是 string 类型,而 value 则有 string, list, set, hashmap, zset……等类型。
Redis 中的一个 k-v
对用一个 entry 项表示,其中每个 entry 包含 key、value、next 三个指针,共 24 字节。由于 redis 使用 jemalloc 分配内存,因此一个 entry 需要申请 32 字节的内存。这里的 key, value 指针分别指向一个 RedisObject:
redis entry
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:LRU_BITS;
int refcount;
void *ptr;
} robj;
RedisObject 对应前面提到的各种数据类型,其中最简单的就是 redis 内部的字符串了。它有如下几种编码格式:
SDS 编码(图片来自极客时间-redis 专栏)
图中的元数据包括 type,encoding,lru, refcount,分别表示数据类型,编码类型,最近一次访问的时间戳,引用次数。
当字符串是一个整型时,直接放在 ptr 位置,不用再分配新的内存了,非常高效。
解析一下 44 字节的原因:元数据和 ptr 共占 16 字节,加上 44 字节,再加上字符串末尾的 '