web-dev-qa-db-ja.com

Redisで接続プールを適切に使用するにはどうすればよいですか?

接続プールがどのように機能し、どのようにそれらを適切に使用するかは明確ではありません。私は誰かが詳しく説明できることを望んでいました。私のユースケースを下にスケッチしました:

settings.py:

import redis

def get_redis_connection():
    return redis.StrictRedis(Host='localhost', port=6379, db=0)

task1.py

import settings

connection = settings.get_redis_connection()

def do_something1():
    return connection.hgetall(...)

task2.py

import settings

connection = settings.get_redis_connection()

def do_something1():
    return connection.hgetall(...)

等.


基本的に、redis接続を返すsetting.pyファイルと、redis接続を取得して操作を実行するいくつかの異なるタスクファイルがあります。そのため、各タスクファイルには独自のredisインスタンスがあります(おそらく非常に高価です)。このプロセスを最適化する最良の方法は何ですか。この例で接続プールを使用することはできますか?このパターンを設定するより効率的な方法はありますか?

私たちのシステムでは、この同じパターンに従って12を超えるタスクファイルがあり、リクエストが遅くなっていることに気付きました。

ありがとう

28
vgoklani

Redis-pyは、接続を取得できる接続プールを提供します。接続プールは、必要に応じて使用できる接続のセットを作成します(完了したら、接続は接続プールに返され、さらに再利用されます)。接続を破棄せずにオンザフライで作成しようとすると(つまり、プールを使用しない、またはプールを正しく使用しないと)、接続数が多すぎて(接続制限に達するまで)再接続できなくなります。

Initメソッドで接続プールをセットアップし、プールをグローバルにすることを選択できます(グローバルが気に入らない場合は、他のオプションを見ることができます)。

redis_pool = None

def init():
    global redis_pool
    print("PID %d: initializing redis pool..." % os.getpid())
    redis_pool = redis.ConnectionPool(Host='10.0.0.1', port=6379, db=0)

その後、次のようなプールから接続を取得できます。

redis_conn = redis.Redis(connection_pool=redis_pool)

また、特定の場合にパフォーマンスを改善するため、redis-pyとともにhiredisを使用していると想定しています。既存のセットアップでredisサーバーに対して開かれている接続の数も確認しましたか? INFOコマンドを使用して、その情報を取得できます。

redis-cli info

connected_clients」フィールドが表示されるClientsセクションを確認します。このフィールドには、その時点でredisサーバーに対して開いている接続の数が表示されます。

19
ali haider

Redis-pyで記述されたsingleton(borg pattern)ベースのラッパーを使用します。これにより、すべてのファイルに共通の接続プールが提供されます。このラッパークラスのオブジェクトを使用するときは常に、同じ接続プールを使用します。

REDIS_SERVER_CONF = {
    'servers' : {
      'main_server': {
        'Host' : 'X.X.X.X',
        'PORT' : 6379 ,
        'DATABASE':0
    }
  }
}

import redis
class RedisWrapper(object):
    shared_state = {}

    def __init__(self):
        self.__dict__ = self.shared_state

    def redis_connect(self, server_key):
        redis_server_conf = settings.REDIS_SERVER_CONF['servers'][server_key]
        connection_pool = redis.ConnectionPool(Host=redis_server_conf['Host'], port=redis_server_conf['PORT'],
                                               db=redis_server_conf['DATABASE'])
        return redis.StrictRedis(connection_pool=connection_pool)

使用法:

r_server = RedisWrapper().redis_connect(server_key='main_server')
r_server.ping()

[〜#〜] update [〜#〜]

ファイルが異なるプロセスとして実行される場合は、接続をプールするredisプロキシを使用する必要があり、redisに直接接続する代わりに、プロキシを使用する必要があります。非常に安定したredis(およびmemcached)プロキシは、 twemproxy によって作成され、主な目的はオープン接続の削減です。

9
DhruvPathak

ここにチーズショップからの引用があります page

舞台裏では、redis-pyは接続プールを使用してRedisサーバーへの接続を管理します。 デフォルトでは、作成する各Redisインスタンスは、独自の接続プールを作成します。既に作成された接続プールインスタンスをRedisクラスのconnection_pool引数に渡すことで、この動作をオーバーライドし、既存の接続プールを使用できます。これを行うことで、クライアント側のシャーディングを実装したり、接続の管理方法をより細かく制御したりすることができます。

pool = redis.ConnectionPool(Host='localhost', port=6379, db=0)
r = redis.Redis(connection_pool=pool)

さらに、インスタンス スレッドセーフ

Redisクライアントインスタンスは、スレッド間で安全に共有できます。内部的には、接続インスタンスはコマンド実行中にのみ接続プールから取得され、直後にプールに返されます。コマンドの実行により、クライアントインスタンスの状態が変更されることはありません。

あなたは言う:

各タスクファイルには独自のredisインスタンスがあります(おそらく非常に高価です)。 ...私たちのシステムでは、この同じパターンに従って12を超えるタスクファイルがあり、リクエストが遅くなっていることに気付きました。

数十の接続がRedisサーバーの速度を低下させる可能性はほとんどありません。しかし、コードは舞台裏で接続プールを使用するため、問題は接続自体のどこかにあります。 Redisはインメモリストレージであるため、ほとんどの場合、非常に高速です。だから私はむしろタスクの問題を探したいです。

更新

@ user3813256のコメントより。はい、彼はタスクレベルで接続プールを使用します。 redisパッケージの組み込み接続プールを利用する通常の方法は、接続を共有することです。最も簡単な方法では、settings.pyは次のようになります。

import redis

connection = None

def connect_to_redis():
    global connection
    connection = redis.StrictRedis(Host='localhost', port=6379, db=0)

次に、アプリケーション呼び出しのブートストラップのどこかでconnect_to_redis。次に、タスクモジュールでimport connectionを使用します。

6
saaj