Redis-py连接池的实现
Posted 魔笛手CTO
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis-py连接池的实现相关的知识,希望对你有一定的参考价值。
说起连接池,可能很多人直接望而却步,觉得好复杂,还是直接调用别人现成的好了,其实都是连接池也是扮猪吃老虎。
但是之前看redis-py连接池的实现,觉得好简单,但是却又很巧妙,正好最近又在研究redis-py的连接池,将连接池相关的实现抽象出来,简单说明一下。
通过类图可以看到,主要有三个类,Redis对外提供服务,内部维护一个ConnectionPool类,最底层的Connection负责与redis服务的通信。
理解了层级关系,现在我们看代码。
class Connection:
def __init(self, **db_info):
"""初始化需要一些redis服务器的连接信息,此处以db_info代替"""
self._sock = None
pass
def connect(self):
"""供上层调用"""
if not self._sock:
self._connect()
pass
def _connect(self):
"""同redis服务器建立socket"""
self._sock = socket(**db_info)
def disconnect(self):
"""关闭socket连接,此处很巧妙"""
"""连接对象不会销毁,内部的socket会被销毁"""
self.socket = None
def send_command(self, **args):
if not self._socket:
self.connect()
self._sock.sendall(**args)
def read_response(self):
return self._sock.readall()
class ConnectionPool:
def __init__(self, **pool_config, **db_info):
"""实例化需要连接池配置(如连接池大小),数据库连接信息"""
self.reset()
def reset(self):
"""初始化内部维护的连接"""
self._available_connections = []
self._in_use_connections = set()
def make_connection(self):
"""创建新的连接对象"""
conn = Connection(**db_info)
def get_connection(self):
"""获取一条连接,供上层调用"""
if self._available_connections:
conn = self._available_connections
else:
conn = self.make_connection()
self._in_use_connections.add(conn)
return conn
def release(self, connection):
"""释放单个连接对象到连接池"""
self._in_use_connections.remove(connection)
self._available_connections.append(connection)
def disconnect(self):
"""将关闭所有在用的,可用的连接对象"""
all_conns = chain(self._available_connections,
self._in_use_connections)
for connection in all_conns:
connection.disconnect()
class Redis:
"""redis对象,实例化之后内部同时实例化一个连接池对象"""
def __init__(self, **pool_config, **db_info):
self.pool = ConnectionPool(**pool_config, **db_info)
def execute_command(data):
"""从连接池取出一条连接,发送信息,释放给连接池"""
connection = self.pool.get_connection()
try:
connection.send_command(data)
except:
connection.disconnect()
pool.release(connection)
当然关于上面的代码遗漏了redis的通信协议和很多的防御代码 ,比如检测父子进程是否共用一个相同的描述符等,但是我觉的把redis-py连接池的关键表达出来了。
连接池内部维护两个集合,一个可用的连接集合,一个在用的连接集合,当上层获取连接的时候,从可用集合拿出一个返回,同时加到在用集合。
还有一个很巧妙的细节,就是连接在传递数据出错的时候,不是销毁连接对象,而是销毁连接对象内部的socket。因为连接对象一旦实例化就没有足够的理由去销毁它,即使出错也是socket连接出错,销毁socket就好了,避免了连接对象的频繁生成、销毁。
以上是关于Redis-py连接池的实现的主要内容,如果未能解决你的问题,请参考以下文章
安装redis-py并连接Redis服务器设置和获取redis的二进制数据