2013-05-14 39 views
3

當使用redis-py製作大MGET請求Redis的(> 2000000個參數),我得到以下套接字錯誤:連接復位請求

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上運行。

回答

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) 
+0

謝謝,這非常有幫助。 – thyme

+1

謝謝。我認爲如果i> len(array):應該改爲if> = len(array): 否則,當len(array)是N_MGET的倍數時,它將顯示以下錯誤。在這種情況下20. redis.exceptions.ResponseError:'mget'命令的參數數量錯誤 –

+0

已修復,謝謝! –