2016年7月20日星期三

Redis 内存容量优化

在上一篇blog中(http://wadeling.blogspot.com/2016/07/redis.html),提到接手的一个redis服务,这个redis服务一开始是完全用string类型来存储key值,导致需要的内存容量非常的大。而且咨询使用方,有可能业务量还要几倍的上涨,而我们现在的机器只有16G内存,就算加内存,内存压力也太大了。于是有了内存优化的想法。
查询了网络上的一些优化文章,通过实验,发现还是有不少优化效果。具体思路就是把string类型的数据转成hash来存,同时保证每个hashkey里面的filed个数在一定范围内,这样redis会把hash的内存做优化处理,减小了内存的使用量。经过实验,100万个key,采用string类型存储,需要88M的内存,如果用hash来存,只需要45M内存。
优化方案如下:
1.查看redis的hash设置
通过cli方式查看:config get hash-max-ziplist-entries,值是512.
config get hash-max-ziplist-value,值是64.
即每个hashkey里面的field数目为512一下,value长度是64字节以内时,redis会对内存做优化。
2.对10万个key做分hash存储

//把md5字符串转成整数,具体方法是取前面8个字符,用base_convert转成10进制
$md5int = $this->md5str_to_int($md5str);

//3000为估算,即最后会有3000个hashkey,每个hashkey里面大概有300多个field,满足要求
$key = $md5int % 3000;

//hset来存入
$ret = $this->redis->hSet($key,$md5str,$value);


参考:
redis内存容量优化
Redis内存优化案例
instagram使用redis内存优化
redis官方内存优化方案

2016年7月12日星期二

redis内存容量估算

最近刚接手一个redis服务,由于是内部使用,所以在redis前端封装了一层代理,用于内部协议和redis协议的转化,并不复杂。但是使用方刚使用两天,就发现内存爆量了。具体现象是redis返回的错误:OOM command not allowed when used memory > 'maxmemory',使用方给出的请求量是:5000万key,每个key40字节(string类型),每个value8字节,这样算下来只要2.4G内存啊,怎么一下内存就爆了。
我也是刚接触redis,只好研究了一番,还好网上有一篇文章,详细说明了redis的容量估算问题,简单的说就是redis占用的内存除了业务数据之外,还有redis自己的数据结构也会占用一部分内存,所以实际占用内存会大于业务数据的。链接在此:http://www.searchdatabase.com.cn/showcontent_55189.htm
根据文章提供的公式,结合使用方提供的数据,估算的容量如下:
1.首先是计算公式:
string类型的内存大小 = 键值个数 * (dictEntry大小 + redisObject大小 + 包含key的sds大小 + 包含value的sds大小) + bucket个数 * 4

2.根据使用方提供的数据,占用的redis内存容量如下:
dictEntry大小: 16 字节
redisObject大小:16字节
key:40字节, sds对象:9 字节。总共是49字节,按jemalloc分配机制会占用到64字节。
value:8字节,sds对象:9字节,总共是17字节,按jemalloc分配机制会占用到32字节。
以上的内存占用量为:
 (16 + 16 + 64 + 32)* 5000*1000*10 = 6.4G

bucket个数大概为6000万(5000万向上取整到2的n次方,即2的26次方,6000多万)
bucket大小:6000万*4 = 240M左右。

所以总容量为6.4G左右,而redis的配置里面maxmemeroy只配置了4G,难怪要报错了。修改配置后,运行正常了。
从redis里面也可以看到峰值使用内存为6.44G, 和计算出来的容量是吻合的.