4

MGETを使用して Redis (>2,000,000 引数) に大きなリクエストを行うredis-pyと、次のソケット エラーが発生します。

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

さまざまなクライアントからこれを試しましたが、問題は残ります。ここで、ウィンドウのスケーリングのバグが発生している可能性があることを読んだので、調整して最大ウィンドウを小さくしようnet.ipv4.tcp_wmemとしましたが、これもうまくいきnet.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 に答える