在redis有序集中存储整数?

时间:2011-11-01 21:34:31

标签: redis

我有一个处理已经转换成无符号长整数的键的系统(通过将短序列打包成字节串)。我想尝试将它们存储在Redis中,我希望尽可能以最佳方式进行。我关心的主要是记忆效率。

通过在线REPL播放,我注意到以下两个是相同的

zadd myset 1.0 "123"

zadd myset 1.0 123

这意味着即使我知道我想存储整数,也必须将其设置为字符串。我从文档中注意到,密钥只是存储为char*,而SETBIT之类的命令表明Redis不反对将字符串视为客户端中的字节串。这暗示了存储unsigned long s的效率略高于其字符串表示形式。

在排序集中存储unsigned long的最佳方法是什么?

2 个答案:

答案 0 :(得分:11)

感谢Andre的回答。以下是我的发现。

直接存储

Redis键必须是字符串。如果要传递整数,则必须是某种字符串。对于小的,定义良好的值集,Redis会将字符串解析为整数(如果是1)。我的猜测是它会使用这个int来定制它的哈希函数(甚至可以根据值静态地维护哈希表)。这适用于较小的值(示例是64个条目的默认值,值最多为512)。我会在调查过程中测试更大的值。

http://redis.io/topics/memory-optimization

存储为字符串

另一种方法是压缩整数,使其看起来像一个字符串。

看起来可以使用任何字节字符串作为键。

对于我的应用程序的情况,它实际上没有存储字符串或整数的那么大的差异。我想Redis中的结构无论如何都经历了某种对齐,所以无论如何可能会有一些预先浪费的字节。无论如何都要对值进行哈希处理。

使用Python进行测试,因此我可以使用struct.pack创建值。 long long的重量为8个字节,非常大。鉴于整数值的分布,我发现存储字符串实际上是有利的,特别是在以十六进制编码时。

由于redis字符串是“Pascal-style”:

struct sdshdr {
    long len;
    long free;
    char buf[];
};

并且考虑到我们可以在那里存储任何东西,我做了一些额外的Python来将类型编码为最短的类型:

def do_pack(prefix, number):
    """
    Pack the number into the best possible string. With a prefix char.
    """ 

    # char
    if number < (1 << 8*1):
        return pack("!cB", prefix, number)

    # ushort
    elif number < (1 << 8*2):
        return pack("!cH", prefix, number)

    # uint
    elif number < (1 << 8*4):
        return pack("!cI", prefix, number)

    # ulonglong
    elif number < (1 << 8*8):
        return pack("!cQ", prefix, number)

这似乎是一个微不足道的挽救(或根本没有)。可能是由于Redis中的struct padding。这也驱使Python CPU通过屋顶,使其有点没有吸引力。

我正在使用的数据是200000个z consecutive integer => (weight, random integer) × 100,加上一些倒排索引(基于随机数据)。 dbsize会产生1,200,001个密钥。

服务器的最终内存使用:1.28 GB RAM,1.32 Virtual。无论如何,各种调整都不会超过10兆字节。

所以我的结论是:

不要将编码麻烦为固定大小的数据类型。如果需要,只需将整数作为字符串存储在十六进制中。它不会产生那么大的差异。

参考文献:

http://docs.python.org/library/struct.html

http://redis.io/topics/internals-sds

答案 1 :(得分:1)

我不确定这个答案,它更像是一个建议而不是其他任何东西。我必须试一试,看看它是否有效。

据我所知,Redis仅支持UTF-8字符串。

我建议抓取你的长整数的位表示并相应地填充它以填充最近的字节。将每组8个字节编码为UTF-8字符串(以8x * utf8_char *字符串结尾)并将其存储在Redis中。他们未签名的事实意味着你不关心第一位,但如果你这样做,你可以在字符串中添加一个标志。

检索数据后,你必须记住再次将每个字符填充到8个字节,因为如果字符可以用较少的字节存储,UTF-8将使用较少的字节表示。

最终结果是存储最多8 x 8字节字符而不是(可能)最多64 x 8字节字符。