【问题标题】:Fast way to insert 50 million records in Redis在 Redis 中插入 5000 万条记录的快速方法
【发布时间】:2019-06-17 04:50:40
【问题描述】:

我有一个大约 10 GB 的文本文件,包含 5000 万行。对于文件中的每一行,如果记录尚不存在,我将插入该记录,否则将与现有记录的 ID 和当前行 ID 进行比较,如果当前 ID 小于记录 ID,则更新.

目前,插入/比较记录大约需要 8 小时

文本文件中的示例数据:

Md5,Id
d41d8cd98f00b204e9800998ecf8427e,1000
e358efa489f58062f10dd7316b65649e,1001
626726e60bd1215f36719a308a25b798,1002
d41d8cd98f00b204e9800998ecf8427e,5002
d41d8cd98f00b204e9800998ecf8427e,0953
626726e60bd1215f36719a308a25b798,0152

我已经尝试实现生产者/消费者模式,但是生产者会太快并且消耗大量内存,从而导致 OutOfMemory 异常。

ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");

            IDatabase db = redis.GetDatabase();
            int lineCount = 0;
            foreach(var f in File.ReadLines(@"big_text_file.txt").Skip(1))
            {
                lineCount++;
                string[] lines = null;

                lines = f.Split(",")


                if (!db.KeyExists(lines[2]))
                {
                    db.StringSet(lines[2], lines[0]);
                }else //contains key
                {
                    var keypair = db.StringGet(lines[2]);
                    if(Convert.ToInt32(lines[0]) < Convert.ToInt32(keypair))
                    {
                        db.StringSet(lines[2], lines[0]);
                    }
                }

【问题讨论】:

  • 您能否将密钥保存在内存中,而不是检查数据库中的每条记录?你能做检查并插入两个单独的线程吗?
  • 如果我只使用 Hashset 将密钥存储在内存中,我最终会得到内存不足的错误。
  • 嗯,50M 乘以一个 MD5 哈希加上一点额外的大约是 2GB。这不应该是敌人。我相信有序列表更适合存储密钥。也许您必须实现自己的二进制搜索。

标签: c# redis


【解决方案1】:

您的代码有几个问题,您可以优化它们以使其运行得更快。

对 Redis 的请求过多。

如果键不存在,对于每条记录,您向 Redis 发送 2 个请求。如果键已经存在,则对于每条记录,您向 Redis 发送 3 个请求。因此,对于 5000 万条记录,您向 Redis 发送 100 - 1.5 亿条请求。会有很多往返时间。所以会很慢。

相反,您可以将代码包装到 Lua script 中,并且对于每条记录,只向 Redis 发送一次请求。

另外,你的代码不是原子的。如果有多个客户端向 Redis 发送请求,您的代码就会中断。但是,使用 Lua 脚本,您可以确保代码是原子的,这样您就可以进行秒级优化。

增加并发

您似乎使用单个线程/进程向 Redis 发送请求。 Redis 非常快,但是,您的客户端太慢了。所以你可以把你的记录分成几个部分。对于每个部分,创建一个新线程来向 Redis 发送请求。当然,你必须确保你的代码是线程安全的,检查第一次优化。

减少记录数

从您的示例中,您的记录有许多重复的 MD5 和不同的 ID。对 Redis 的这么多请求是无操作的,因为它们将被后续请求覆盖。因此,您可以进行(外部)排序,并在向 Redis 发送请求之前删除这些重复项。

【讨论】:

    【解决方案2】:

    你需要使用--pipe命令

    首先创建一个文件,其中包含以下格式的所有数据并将其保存为 data.txt

    SET Key0 Value0
    SET Key1 Value1
    ...
    SET KeyN ValueN
    

    然后你可以运行 --pipe 命令

    cat data.txt | redis-cli --pipe
    

    详细信息Redis Mass Insertation

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-10
      • 1970-01-01
      • 1970-01-01
      • 2017-01-31
      • 1970-01-01
      • 1970-01-01
      • 2017-08-21
      • 2017-01-27
      相关资源
      最近更新 更多