【问题标题】:Redis memory optimizationRedis 内存优化
【发布时间】:2018-05-28 17:09:39
【问题描述】:

我正在尝试在 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

以及我机器上的结果(32bit 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 

我在问是否有更有效的方法将字符串存储为哈希,通过使用我提到的参数。所以首先,我必须知道它们的意思。然后我会再次进行基准测试,看看是否有更多的收获..

EDIT2:我是个白痴吗?基准测试是正确的,但它已被确认为一个大字符串。如果我对许多大字符串重复,将它们存储为大字符串是绝对的赢家。我认为我为一个字符串得到这些结果的原因在于 Redis 内部..

【问题讨论】:

  • 如果您在谈论加密哈希,则无法对其进行解码,因为无限数量的不同字符串映射到任何给定的哈希。
  • 加密哈希?我只是想在 Redis 哈希中有效地存储一个大字符串,方法是将其拆分为 Ai 块,其中 len(Ai)
  • 我对 Redis 一无所知,但是“hash”和“decode”通常意味着有人不了解哈希函数的工作原理。我不知道它是否适用于这种情况。
  • 好吧 :),Redis 哈希是由键标识的数据结构,具有字段和值。散列是在 Redis 内部完成的,以保存这些字段和值。有了它们,我可以解码回我的字符串..

标签: python optimization redis


【解决方案1】:

实际上,存储大字符串最有效的方法是使用大字符串——其他任何东西都会增加开销。您提到的优化是用于处理大量短字符串,其中字符串之间的空格可能会成为问题。

存储大字符串的性能可能不如小字符串,因为需要找到更多连续的块来存储它,但这不太可能真正影响任何事情。

【讨论】:

    【解决方案2】:

    我已尝试阅读有关您提到的设置的 Redis 文档,但这并不容易。但我觉得你的计划不是个好主意。他们描述的散列旨在为小值节省内存。这些值仍然完全存储在内存中。在我看来,当它们多次出现时,它们正在减少开销,例如,当一个字符串被添加到许多集合时。您的字符串不符合这些条件。我强烈怀疑你会使用你的方案节省内存。

    您当然可以对其进行基准测试。

    【讨论】:

      【解决方案3】:

      尝试查看Redis Memory Usage 文章,您可以在其中找到各种数据类型及其内存消耗的良好比较。

      【讨论】:

        【解决方案4】:

        当您将数据存储在哈希中时,每个值开销只需跳过约 100 个字节!

        因此,当您的字符串长度相当时,例如 100-200 字节,您可能会看到 30-50% 的内存节省,但对于整数,它的内存要少 10 倍!

        这里有几个链接:

        About 100 bytes overhead

        Different memory optimization comparision gist

        【讨论】: