【问题标题】:Storing 30M records in redis在redis中存储30M条记录
【发布时间】:2018-12-02 20:59:27
【问题描述】:

我想知道存储这些数据的最有效方式。

我每天需要跟踪 30-5000 万个数据点。它需要非常快的读/写,所以我正在使用redis。

数据只需要持续24小时,到时候就会EXPIRE

数据看起来像这样的键/值hash

{
  "statistics:a5ded391ce974a1b9a86aa5322ea9e90": {
    xbi: 1,
    bid: 0.24024,
    xpl: 25.0,
    acc: 40,
    pid: 43,
    cos: 0.025,
    xmp: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    clu: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}

我已经用很多 x 替换了实际的字符串,但这是字符串的正确长度。

到目前为止,根据我的计算......这将使用数百 GB 的内存。这看起来对吗?

这主要是重要的临时日志记录数据,但不足以支持写入磁盘或故障转移。我很乐意将它放在一台机器上,如果这有助于使这更容易的话。

在这种情况下减少内存空间的最佳方法是什么?有没有更好的方法可以做到这一点? redis是否支持单实例300GB?

【问题讨论】:

  • 你将如何使用这个数据集?
  • @for_stack 它将每 1 秒批量写入一次,并以更高的频率进行大量读取。它只需要被写入,读取,然后删除。没有修改或类似的东西。如果它们没有在 24 小时内阅读,那么它们就会过期
  • 在读取数据的时候,你只是将每条日志作为一个整体读取,或者需要逐个访问日志的各个字段,例如只读取每个日志的pid
  • 我需要访问每个键(以及与HGETALL 关联的所有值)。我一次不需要超过 1 个,而且它们是随机访问的(我无法预测何时会询问哪个)

标签: redis


【解决方案1】:

在 redis.conf 中 - 将 hash-max-ziplist-value 设置为比字段 'xmp' 的长度大 1。然后重启redis,看看你的内存明显下降。

默认值为 64。当您在哈希中修改或添加新字段时,增加它会增加 CPU 利用率。但是您的用例似乎是仅创建的,在这种情况下,增加设置不应该有任何缺点。

【讨论】:

    【解决方案2】:

    这将使用数百 GB 的内存。这看起来对吗?

    是的

    redis是否支持单实例300GB?

    是的

    有没有更好的方法可以做到这一点?

    您可以尝试以下方法:

    避免使用哈希

    由于您始终使用HGETALL 获取日志的所有字段,因此无需将日志另存为HASHHASHSTRING 消耗更多的内存。

    您可以将所有字段序列化为字符串,并将日志保存为键值对:

    SET 'statistics:a5ded391ce974a1b9a86aa5322ea9e90' '{xbi: 1, bid: 0.24024, and other fields}'
    

    @Sripathi Krishnan 的回答提供了另一种避免 HASH 的方法,即配置 Redis 将 HASH 编码为 ZIPLIST。如果您不与其他应用程序共享您的 Redis,这是一个好主意。否则,此修改可能会给其他人带来问题。

    压缩数据

    为了减少内存使用,您可以尝试压缩您的数据。 Redis可以存储二进制字符串,所以可以使用gzip、snappy等压缩算法将日志文本压缩成二进制字符串,保存到Redis中。

    通常,输入越大,压缩效果越好。所以你最好压缩整个日志,而不是一个一个地压缩每个字段。

    副作用是日志的生产者和消费者需要消耗一些 CPU 来压缩和解压缩数据。但是,通常这不是问题,而且会减少一些网络带宽。

    批量写入和批量读取

    正如我上面提到的,如果你想获得更好的压缩,你应该获得更大的输入。所以如果可以批量写入多条日志,可以对这批日志进行压缩,以获得更好的压缩效果。

    1. 将多条日志压缩成一个批次:compress(log1, log2, log3) -> batch1: batch-result
    2. 将批处理结果作为键值对放入Redis:SET batch1 batch-result
    3. 为批次建立索引:MSET log1 batch1 log2 batch1 log3 batch1

    当你需要获取日志时:

    1. 搜索索引获取批处理键:GET log1 -> batch1
    2. 获取批处理结果:GET batch1 -> batch-result
    3. 解压批处理结果,从结果中查找日志

    最后一种方法是最复杂的一种,额外的索引会消耗一些额外的内存。但是,它可以大大减少数据的大小。

    还有这些方法能达到什么效果,很大程度上取决于你的日志。你应该做很多基准测试:)

    【讨论】:

    • 顺便说一句,这对二进制字符串很疯狂,我不知道。有什么特殊的数据类型吗?
    • @Tallboy Redis' STRING 类型是二进制安全的。您可以使用STRING 命令保存二进制字符串,例如SET key binary-string, GET key
    猜你喜欢
    • 2017-08-21
    • 2021-10-13
    • 2022-09-25
    • 2019-08-10
    • 2011-03-11
    • 2021-12-21
    • 1970-01-01
    • 2014-09-09
    • 1970-01-01
    相关资源
    最近更新 更多