python redisの接続プールの原理
4798 ワード
接続プールとは
通常、redis操作が必要な場合、接続が作成され、この接続に基づいてredis操作が行われ、操作が完了すると接続が解放されます.
一般的には問題ありませんが、コンカレント量が高い場合、頻繁な接続の作成と解放はパフォーマンスに大きな影響を及ぼします.
すると、接続プールが機能します
接続プールの原理は、予め複数の接続を作成することにより、redis操作を行うと、作成した接続を直接取得して操作し、操作が完了した後は解放されず、後続の他のredis操作に使用される
これにより、頻繁なredis接続の作成と解放を回避し、パフォーマンスを向上
げんり
では、redis-pyでは、どのように接続プール管理を行っているのでしょうか.
接続プールの使用
まず、接続プールの操作方法を見てみましょう.
原理解析
redis.ConnectionPoolがインスタンス化されたとき、何をしましたか
この接続プールのインスタンス化は、実際には実際のredis接続を行わず、最大接続数、接続パラメータ、接続クラスを設定するだけです.
StrictRedisがインスタンス化されたとき、また何をしましたか.
キー部分コードのみが保持されています
StrictRedisを使用して接続プールを作成しなくても、自分で作成することがわかります.
ここまで、redis接続の実際の発生はまだ見られません.
続行
次のステップは
やっと、ここで接続の作成を見ました.
ここで呼び出されたのは
使用可能な接続がある場合は、使用可能なリンクを取得し、ない場合は作成します.
やっと、ここで接続が作成されたのを見ました.
ConnectionPoolの例では、
それぞれ利用可能な接続セットから接続を取得しようと試みる .取得できない場合は、接続 を再作成します.取得接続を使用中の接続セット に追加する.
これは
接続プールオブジェクトは
まとめ
これで、接続プールの管理プロセスを一度実行し、ConnectionPoolは
通常、redis操作が必要な場合、接続が作成され、この接続に基づいてredis操作が行われ、操作が完了すると接続が解放されます.
一般的には問題ありませんが、コンカレント量が高い場合、頻繁な接続の作成と解放はパフォーマンスに大きな影響を及ぼします.
すると、接続プールが機能します
接続プールの原理は、予め複数の接続を作成することにより、redis操作を行うと、作成した接続を直接取得して操作し、操作が完了した後は解放されず、後続の他のredis操作に使用される
これにより、頻繁なredis接続の作成と解放を回避し、パフォーマンスを向上
げんり
では、redis-pyでは、どのように接続プール管理を行っているのでしょうか.
接続プールの使用
まず、接続プールの操作方法を見てみましょう.
rdp = redis.ConnectionPool(host='127.0.0.1', port=6379, password='xxxxx')
rdc = redis.StrictRedis(connection_pool=rdp)
rdc.set('name', 'Yi_Zhi_Yu')
rdc.get('name')
原理解析
redis.ConnectionPoolがインスタンス化されたとき、何をしましたか
def __init__(self, connection_class=Connection, max_connections=None,
**connection_kwargs):
max_connections = max_connections or 2 ** 31
if not isinstance(max_connections, (int, long)) or max_connections < 0:
raise ValueError('"max_connections" must be a positive integer')
self.connection_class = connection_class
self.connection_kwargs = connection_kwargs
self.max_connections = max_connections
この接続プールのインスタンス化は、実際には実際のredis接続を行わず、最大接続数、接続パラメータ、接続クラスを設定するだけです.
StrictRedisがインスタンス化されたとき、また何をしましたか.
def __init__(self, ...connection_pool=None...):
if not connection_pool:
...
connection_pool = ConnectionPool(**kwargs)
self.connection_pool = connection_pool
キー部分コードのみが保持されています
StrictRedisを使用して接続プールを作成しなくても、自分で作成することがわかります.
ここまで、redis接続の実際の発生はまだ見られません.
続行
次のステップは
set
操作です.明らかに、この時に必ずredis接続が発生します(そうでなければどうすればいいですか).def set(self, name, value, ex=None, px=None, nx=False, xx=False):
...
return self.execute_command('SET', *pieces)
execute_command
を見てみましょう def execute_command(self, *args, **options):
"Execute a command and return a parsed response"
pool = self.connection_pool
command_name = args[0]
connection = pool.get_connection(command_name, **options)
try:
connection.send_command(*args)
return self.parse_response(connection, command_name, **options)
except (ConnectionError, TimeoutError) as e:
connection.disconnect()
if not connection.retry_on_timeout and isinstance(e, TimeoutError):
raise
connection.send_command(*args)
return self.parse_response(connection, command_name, **options)
finally:
pool.release(connection)
やっと、ここで接続の作成を見ました.
connection = pool.get_connection(command_name, **options)
ここで呼び出されたのは
ConnectionPool
のget_ですconnection def get_connection(self, command_name, *keys, **options):
"Get a connection from the pool"
self._checkpid()
try:
connection = self._available_connections.pop()
except IndexError:
connection = self.make_connection()
self._in_use_connections.add(connection)
return connection
使用可能な接続がある場合は、使用可能なリンクを取得し、ない場合は作成します.
def make_connection(self):
"Create a new connection"
if self._created_connections >= self.max_connections:
raise ConnectionError("Too many connections")
self._created_connections += 1
return self.connection_class(**self.connection_kwargs)
やっと、ここで接続が作成されたのを見ました.
ConnectionPoolの例では、
_available_connections
、_in_use_connections
の2つのリストがあります.それぞれ
と
を表し、上のget_connection
では、接続を取得するプロセスが_in_use_connections
に接続を追加しました.この接続は使用中であることを示しています.それはいつ使用中の接続を使用可能な接続リストに戻したのですか.これは
execute_command
で、redis操作を実行するときにfinally
の部分で実行されるのを見ることができます.pool.release(connection)
接続プールオブジェクトは
release
メソッドを呼び出し、_in_use_connections
から_available_connections
に接続を戻します.これにより、後続の接続取得でこの接続を再使用できます.release
の方法は以下の通りである. def release(self, connection):
"Releases the connection back to the pool"
self._checkpid()
if connection.pid != self.pid:
return
self._in_use_connections.remove(connection)
self._available_connections.append(connection)
まとめ
これで、接続プールの管理プロセスを一度実行し、ConnectionPoolは
(_available_connections
)と
を管理することで接続プール管理を実現しました.