如何高效的向 Redis 插入 Billion 数据?

How to insert Billion of data to Redis efficiently?

我有大约 20 亿个键值对,我想将它们高效地加载到 Redis 中。我目前正在使用 Python 并使用 redis-py 记录的 Pipe。我怎样才能加快以下方法的速度?

import redis

def load(pdt_dict):
    """
    Load data into redis.

    Parameters
    ----------
    pdt_dict : Dict[str, str]
        To be stored in Redis
    """
    redIs = redis.Redis()
    pipe = redIs.pipeline()
    for key in pdt_dict.keys():
        pipe.hmset(self.seller + ":" + str(key), pdt_dict[key])
    pipe.execute()

关于问题和示例代码的几点。

  1. 流水线不是灵丹妙药 - 在使用之前您需要了解它的作用。流水线的作用是批量发送多个操作,它们来自服务器的响应也是如此。您获得的是每个操作的网络往返时间被批处理的网络往返时间所取代。但是无限大小的批处理确实会消耗资源——你需要保持它们的大小足够小才能有效。根据经验,我通常尝试将每个管道的目标定为 60KB,并且由于每个数据都不同,因此管道中的实际操作数量也不同。假设您的密钥及其值是 ~1KB,您需要每 60 次左右的操作调用 pipeline.execute()

  2. 除非我严重误解,这段代码不应该运行。您正在使用 HMSET 就好像它是 SET,所以您基本上缺少哈希的字段-> 值映射。哈希 (HMSET) 和字符串 (SET) 是不同的数据类型,因此应相应地使用。

  3. 看起来好像这个小循环负责整个 "Billion of data" - 如果是这样的话,不仅您的服务器 运行 宁代码是疯狂地交换除非它有很多 RAM 来保存字典,否则它也会非常低效(不管 Python 的速度如何)。您需要通过 运行 宁此过程的多个实例来并行化数据插入。

  4. 您是否远程连接到 Redis?如果是这样,网络可能会限制您的表现。

  5. 考虑您的 Redis 设置 - 假设这确实是一个瓶颈,也许这些可以 tweaked/tuned 以获得更好的性能。

我希望你已经在 redis python 软件包旁边安装了 hiredis python 软件包。请参阅 https://github.com/andymccurdy/redis-py#parsers 它也应该会提升您的性能。

self.seller做了什么?也许这是一个瓶颈?

如@Itamar 所说,尝试定期执行管道

def load(pdtDict):
    redIs = redis.Redis()
    pipe = redIs.pipeline()
    n = 1
    for key in pdtDict.keys():
        pipe.hmset(self.seller+":"+str(key),pdtDict[key])
        n = n + 1
        if (n % 64) == 0:
            pipe.execute()
            pipe = redIs.pipeline()

要向 Redis 提供大量数据,请考虑使用 here 中描述的 Redis 批量插入功能。

为此,您需要能够访问 redis-cli。

您可以在管道模式下使用 redis-cli,首先您准备一个文件,例如(注意这些行应该由 cr/lf 终止或由 -d <dilimiter> 选项设置):

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

然后将其通过管道传输到 redis-cli:

cat data.txt | redis-cli --pipe

https://redis.io/topics/mass-insert

另一个考虑因素是,如果满足以下条件(来自 Redis Labs),在管道构造中设置 transaction=False 有助于提高性能:

For situations where we want to send more than one command to Redis, the result of one command doesn’t affect the input to another, and we don’t need them all to execute transactionally, passing False to the pipeline() method can further improve overall Redis performance.