技术开发 频道

Redis数据库:内存容量的预估和优化

  zipmap

  这篇文章已经解释zipmap的效果,可以大量的节约内存的使用.对于一个普通的subkey和value,只需要额外的3个字节(keylen,valuelen,freelen)来存储,另外的hash key也只需要额外的2个字节(zm头尾)来存储subkey的个数和结束符.

Redis数据库:内存容量的预估和优化zipmap类型的内存大小 = hashkey个数 * (dictEntry大小 + redisObject大小 + 包含key的sds大小 + subkey的总大小) + bucket个数 * 4

开始容量预估测试,100个hashkey,其中每个hashkey里包含300个subkey, 这里key+value的长度为5字节

#! /bin/bash

redis
-cli info|grep used_memory:

for (( start = 100; start < 200; start++ ))
do
    
for (( start2 = 100; start2 < 400; start2++ ))
    do
         redis
-cli hset test$start a$start2 "1" > /dev/null
    done
done

redis
-cli info|grep used_memory:

  这里subkey是同时申请的的,大小是300 * (5 + 3) + 2 =2402字节,根据上面jemalloc size class可以看出实际申请的内存为2560.另外100hashkey的bucket是128.所以总的预估大小为

>>> 100 * (16 + 16 + 16 + 2560) + 128 * 4
261312

   运行一下上面的脚本

hoterran@~/Projects/redis-2.4.1$ bash redis-mem-test-zipmap.sh
used_memory:
555916
used_memory:
817228

   计算一下差值

>>> 817228 - 555916
261312

   是的完全一样,预估很准确.

  另外扯扯zipmap的一个缺陷,zipmap用于记录subkey个数的zmlen只有一个字节,超过254个subkey后则无法记录,需要遍历整个zipmap才能获得subkey的个数.而我们现在常把hash_max_zipmap_entries设置为1000,这样超过254个subkey之后每次hset效率都很差.

354     if (zm[0] < ZIPMAP_BIGLEN) {
355         len = zm[0];                       //小于254,直接返回结果
356     } else {
357         unsigned char *p = zipmapRewind(zm);   //遍历zipmap
358         while((p = zipmapNext(p,NULL,NULL,NULL,NULL)) != NULL) len++;
359
360         /* Re-store length if small enough */
361         if (len < ZIPMAP_BIGLEN) zm[0] = len;
362     }

   简单把zmlen设置为2个字节(可以存储65534个subkey)可以解决这个问题,今天和antirez聊了一下,这会破坏rdb的兼容性,这个功能改进推迟到3.0版本,另外这个缺陷可能是weibo的Redis机器cpu消耗过高的原因之一.

0
相关文章