参考: Notes on Redis Memory Usage
- 测试环境
- redis版本
- redis_version:2.4.4
- 操作系统(uname -a)
- Linux CentOS 2.6.32-220.13.1.el6.x86_64 #1 SMP Tue Apr 17 23:56:34 BST 2012 x86_64 x86_64 x86_64 GNU/Linux
- python版本(python –version)
- Python 2.6.6
Strings
测试脚本
#!/bin/env python import redis import uuid import time r = redis.Redis(host='localhost', port=6379, db=0) for num_strings in (100000,): r.flushall() time.sleep(1.0) initial_size = r.dbsize() initial_info = r.info() for i in xrange(0, num_strings): r.set(str(uuid.uuid4()), time.time()) #r.setex(str(uuid.uuid4()), time.time(), 100000) final_size = r.dbsize() final_info = r.info() print "For %s strings." % (num_strings,) print "Keys: %s => %s" % (initial_size, final_size) print "Memory: %s => %s" % (initial_info['used_memory'], final_info['used_memory']) print "Memory per key: %d"%((int(final_info['used_memory']) - int(initial_info['used_memory'])) / num_strings)
- 测试结果
- set
- 每个key-value占用138字节,可见redis本身的维护开销为89字节
- setex
- 每个key-value占用180字节,可见redis本身的维护开销为131字节,启用过期时间需要42字节开销(这是因为redis使用新的链表保存设置了过期时间的条目)。
Sets
测试脚本
#!/bin/env python import redis import math import time r = redis.Redis(host='localhost', port=6379, db=0) set_capcity = int(r.config_get("set-max-intset-entries")["set-max-intset-entries"]) def set_name(i, num_strings, set_capcity): set_num = math.ceil(num_strings/float(set_capcity)) return "s%d"%(i%set_num) for num_strings in (100000,): r.flushall() time.sleep(1.0) initial_size = r.dbsize() initial_info = r.info() for i in xrange(0, num_strings): #r.sadd("s", str(i)) r.sadd(set_name(i, num_strings, set_capcity), str(i)) final_size = r.dbsize() final_info = r.info() print "For %s strings." % (num_strings,) print "Keys: %s => %s" % (initial_size, final_size) print "Memory: %s => %s" % (initial_info['used_memory'], final_info['used_memory']) print "Memory per key: %d"%((int(final_info['used_memory']) - int(initial_info['used_memory'])) / num_strings)
测试结果
- 启用压缩
- 每个value占用4字节
- 不启用压缩
- 每个value占用39字节
注意: redis的set仅当值为整型,压缩才会生效。
内存预留
除非你能够保证你的机器总是有一半的空闲内存,否则别使用快照方式持久化数据或者通过执行BGREWRITEAOF压缩aof文件。 redis在执行bgsave时,会进行一次fork,fork后的进程负责将内存中的数据写入磁盘,由于fork采用Copy-On-Write,两个redis进程共享内存中的数据。redis如果有数据更新,则会将对应的共享内存页创建一份副本再更新,当更新操作足够频繁时,共享的内存空间会迅速地副本化,导致物理内存被耗光,系统被迫动用交换空间,从而导致redis服务极不稳定,整个系统堵塞在磁盘io上。