4

使用 向 Redis 发出大量MGET请求(>2,000,000 个参数)redis-py时,我收到以下套接字错误:

ConnectionError: Error 104 while writing to socket. Connection reset by peer.

我已经从不同的客户那里尝试过,但问题仍然存在。我在这里读到可能存在窗口缩放错误,因此我尝试调整net.ipv4.tcp_wmemnet.ipv4.tcp_rmem设置较小的最大窗口,但这也不起作用。我在 Python 2.7.3、Ubuntu 12.04.1 LTS 和 Redis 2.6.4 上运行它。

4

1 回答 1

7

您无法使用单个 MGET 检索如此多的值。此命令并非旨在维持此类工作量。生成非常大的 Redis 命令是错误的想法:

  • 在服务器端,所有命令都应该适合输入缓冲区。该命令的所有结果都应该适合输出缓冲区。输入缓冲区限制为 1 GB。对于输出缓冲区,有软限制和硬限制,具体取决于客户端的性质。但是将缓冲区增长到接近这些限制确实是在寻找麻烦。Redis 只是在达到限制时关闭连接。

  • 在客户端,可能也有类似的缓冲区和硬编码限制。

  • Redis 是一个单线程事件循环。命令的执行是序列化的。因此,一个非常大的命令将使 Redis 对所有其他客户端都没有响应。

如果你想检索大量数据,你应该管道化几个 GET 或 MGET 命令。例如,以下代码可用于检索任意数量的项目,同时最大限度地减少往返次数和服务器端 CPU 消耗:

import redis

N_PIPE = 50 # number of MGET commands per pipeline execution
N_MGET = 20 # number of keys per MGET command

# Return a dictionary from the input array containing the keys
def massive_get( r, array ):
    res = {}
    pipe = r.pipeline(transaction=False)
    i = 0
    while i < len(array):
        keys = []
        for n in range(0,N_PIPE):
            k = array[i:i+N_MGET]
            keys.append( k )
            pipe.mget( k )
            i += N_MGET
            if i>=len(array):
                break
        for k,v in zip( keys, pipe.execute() ):
            res.update( dict(zip(k,v)) )
    return res

# Example: retrieve all keys from 0 to 1022:
pool = redis.ConnectionPool(host='localhost', port=6379, db=0)
r = redis.Redis(connection_pool=pool)
array = range(0,1023)
print massive_get(r,array)
于 2013-05-15T12:08:00.640 回答