大型MGET请求的连接重置

时间:2013-05-14 20:48:49

标签: python redis

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

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

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

1 个答案:

答案 0 :(得分:6)

您无法使用单个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)