【问题标题】:Storing integers in a redis ordered set?在redis有序集中存储整数?
【发布时间】:2011-11-01 21:34:31
【问题描述】:

我有一个系统可以处理已转换为无符号长整数的键(通过将短序列打包成字节字符串)。我想尝试将这些存储在 Redis 中,并且我想以最好的方式做到这一点。我关心的主要是内存效率。

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

zadd myset 1.0 "123"

zadd myset 1.0 123

这意味着即使我知道我想存储一个整数,它也必须设置为一个字符串。我从文档中注意到,密钥只是存储为 char*s 并且像 SETBIT 这样的命令表明 Redis 并不反对在客户端将字符串视为字节串。这暗示了一种存储unsigned longs 的方式比存储它们的字符串表示形式更有效。

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

【问题讨论】:

    标签: redis


    【解决方案1】:

    感谢安德烈的回答。这是我的发现。

    直接存储整数

    Redis 键必须是字符串。如果你想传递一个整数,它必须是某种字符串。对于小的、定义明确的值集,Redis 会将字符串解析为一个整数(如果它是一个整数)。我的猜测是它会使用这个 int 来定制它的哈希函数(或者甚至根据值静态地标注一个哈希表)。这适用于小值(示例是 64 个条目的默认值,最大值为 512)。我会在调查期间测试更大的值。

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

    存储为字符串

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

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

    对于我的应用程序来说,存储字符串或整数实际上并没有太大区别。我想Redis中的结构无论如何都会经历某种对齐,所以无论如何可能会有一些预先浪费的字节。在任何情况下,该值都会被散列。

    使用 Python 进行测试,因此我能够使用 struct.pack 创建值。 long longs 有 8 个字节,相当大。鉴于整数值的分布,我发现存储字符串实际上可能是有利的,尤其是在以十六进制编码时。

    由于 redis 字符串是“Pascal 风格”:

    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 中的结构填充。这也将 Python CPU 推到了顶峰,使其有点缺乏吸引力。

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

    服务器的最终内存使用:1.28 GB RAM,1.32 虚拟。各种调整所产生的差异不超过 10 兆字节。

    所以我的结论是:

    不要费心编码成固定大小的数据类型。只需将整数存储为字符串,如果需要,可以使用十六进制。不会有太大的不同。

    参考资料:

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

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

    【讨论】:

    • 我在字符串中尝试了 zadd 1000000 次,在整数中尝试了 1000000 次。内存使用量几乎相同,甚至有时以整数存储使用更多内存。
    【解决方案2】:

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

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

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

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

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

    【讨论】:

    • 这是一个不错的建议。但这不会导致无法打印的字符,可能包括引号或空格吗?这可能会使发送变得困难。我会做一个实验,但我可以看到这可能是一个死胡同。
    • 我想你唯一需要逃避的就是空格,因为 Redis 会认为(从 2.4 版开始)它是另一个成员。其他所有内容都是有效的 UTF-8,所以它可以正常工作。
    猜你喜欢
    • 2019-10-13
    • 1970-01-01
    • 2015-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多