Redis 内存优化
我正在尝试在Redis中以非常节省内存的方式编码一些数据(实际上是一个非常大的字符串)。根据Redis的文档,里面提到“尽可能使用哈希”,并且说明了两个配置参数:
第一个是“hash-max-zipmap-entries”,我理解的意思是每个哈希键最多可以有多少个键(我理解对吗?)。
第二个是“hash-max-zipmap-value”,这个参数表示值的最大长度。它是指字段的长度还是值的长度呢?而且这个长度是以字节、字符还是其他什么单位来计算的?
我的想法是把这个字符串(它的长度是固定的)分成适合上述参数的数量,然后把它们存储为值。字段可以用序号来表示,以确保解码的一致性。
编辑:我进行了大量的基准测试,似乎将字符串编码为哈希能节省大约50%的内存。
这是我的基准测试脚本:
import redis, random, sys
def new_db():
db = redis.Redis(host='localhost', port=6666, db=0)
db.flushall()
return db
def db_info(db):
return " used memory %s " % db.info()["used_memory_human"]
def random_string(_len):
letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
return "".join([letters[random.randint(0,len(letters)-1)] for i in range(_len) ])
def chunk(astr, size):
while len(astr) > size:
yield astr[:size]
astr = astr[size:]
if len(astr):
yield astr
def encode_as_dict(astr, size):
dod={}
cnt = 0
for i in chunk(astr,size):
dod[cnt] = i
cnt+=1
return dod
db=new_db()
r = random_string(1000000)
print "size of string in bytes ", sys.getsizeof(r)
print "default Redis memory consumption", db_info(db)
dict_chunk = 10000
print "*"*100
print "BENCHMARKING \n"
db=new_db()
db.set("akey", r)
print "as string " , db_info(db)
print "*"*100
db=new_db()
db.hmset("akey", encode_as_dict(r,dict_chunk))
print "as dict and stored at value" , db_info(db)
print "*"*100
在我的机器上(32位的Redis实例)得到的结果是:
size of string in bytes 1000024
default Redis memory consumption used memory 534.52K
******************************************************************************************
BENCHMARKING
as string used memory 2.98M
******************************************************************************************
as dict and stored at value used memory 1.49M
我在询问是否有更有效的方法通过调整我提到的参数来将字符串存储为哈希。所以首先,我需要了解这些参数的具体含义……然后我会再进行基准测试,看看是否能获得更多的收益……
编辑2:我是不是傻?基准测试是正确的,但它只针对一个大字符串。如果我对多个大字符串重复测试,存储它们为大字符串显然是更好的选择……我觉得我得到这些结果的原因可能与Redis的内部机制有关……
4 个回答
可以看看这篇关于 Redis内存使用情况 的文章,里面有各种数据类型和它们占用内存的比较,讲得很清楚。
我试着去看Redis的文档,关于你提到的那些设置,真的不太好理解。不过我觉得你的计划听起来不是个好主意。他们说的哈希功能是为了节省小数据的内存。其实这些数据还是完全存储在内存里的。听起来他们是在减少一些开销,特别是当同一个字符串被添加到很多集合里时。可是你的字符串似乎不符合这些条件。我非常怀疑你用你这个方法能节省内存。
当然,你可以自己做个测试来看看效果。
其实,存储一个很大的字符串最有效的方法就是直接把它当作一个大字符串来存。用其他方式存储会增加额外的负担。你提到的那些优化主要是针对存储很多短字符串的情况,因为短字符串之间可能会有空隙,这样就会出现问题。
存储一个大字符串的性能可能没有存储小字符串那么好,因为需要找到更多连续的空间来放这个大字符串,但这通常不会对实际使用产生影响。