我需要你的一些建议。我正在尝试使用 redis 和哈希(redis 类型)以非常节省内存的方式存储一些数据。有一些随机字符串列表(平均大小为 40 个字符,但在 rfc 中最大可能为 255 个字符)——它是文件 ID,例如我们有 100kk file_id 列表。我们还需要为每个 id 跟踪 2 个参数:download_count(int, incremented) 和 server_id -- tiny int, redis 配置添加:
hash-max-ziplist-entries 1024
首先我们拒绝按原样存储数据(palin 文本),巨大的开销:
file_id(40 byte) + download_count + server_id) * 100kk + redis pointers --no need to calculate at all.
其次,使用一些 128 位散列函数并按原样使用 redis 散列进行存储:但也有一些开销,但比 1 个少。
最后我们得到这样的东西,带有 redis 哈希:
hmset(bucket, server_id_field, value1, download_count_filed, value2),
server_id_field = crc32(file_id)
download_count_filed = crc32(file_id) + 1,
bucket = murmur2(file_id) div 10^5
所以总共有 100k 个桶,所以此时我们可以得到碰撞,例如:(白内障与 perit 碰撞)感谢 link ,并且数据到达相同的桶,但是字段有 crc32 哈希,理论上我们此时不能发生碰撞(概率较小),这个方案理论上可以像 64 位哈希一样抗碰撞吗?
但它并不是真正有效的内存方案,所以我们可以得到这样的东西(有一个字段):
hmset(bucket, crc32(file_id as server_id_and_download_count_field), value1+’--’+value2)
所以我们不能使用增量函数,但是我们减少字段和内存使用,并且需要一些 cpu 来解析结果并用新值更新它(增量下载计数),也许我们可以使用 lua 做一些内置的用这个操纵?
所以我的问题: 它是否具有很强的抗碰撞性(对于 100kk 数据),或者我们可能需要在字段中使用一些 64 位哈希函数(不是 crc32),但是什么时候我们将拥有 10 亿行足够强大的数据?
也许有更有效的方案?
谢谢!
最佳答案
Redis 哈希非常适合这种情况。看着 Redis doc for HSET我们看到了
HSET myhash field1 "Hello"
我们还应该记住,Redis 是关于字符串的。我建议您将 file_id
拆分为 X 个字符(例如 10 个)并将第一部分用作 myhash
,将其余部分用作 field1
。通过这种方式,您可以将所有以相同 X 字符开头的 file_id 折叠到一个哈希中,并且只需为此付费一次。因此,在您的 myhash
上测试不同的长度,看看哪个值对您有好处。
要做的第二件事是创建 "Hello"
,您的值。由于 Redis 喜欢字符串,因此您应该将所有数据编码为一个。从 server_id
开始,因为您知道它的字节大小,然后附加 download_count
。如果您使用的是 Python,则可以轻松地使用 struct.pack()
将其转换为字符串。
您还可以查看您的 file_id 中是否存在所有字符。如果这些只是一个子集,您也可以将它们编码成更密集的形式,并可能节省几个字符。
祝你好运!
关于Redis 高效存储数据(哈希),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28336194/