关于Redis连接池的一些问题
使用连接池的好处暂且不说,本文主要探讨Redis连接池的原理方式
要使用Redis,首先应该建立一个Redis客户端,比如:
rds = redis.Redis(host='localhost', port=6379, db=0, max_connections=100)
在建立Redis客户端的时候,可以指定max_connections参数,这个参数指定了连接池中连接的数量
当读写Redis的时候,首先将传入的参数命令做一些处理,然后进入 execute_command 函数
这个函数显示了处理连接池的过程:
# COMMAND EXECUTION AND PROTOCOL PARSING def execute_command(self, *args, **options): "Execute a command and return a parsed response"
# pool是ConnectionPool类,用于管理连接池 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)
这里,展开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
这个方法也在ConnectionPool类里,可见,如果有可用的连接(connection),就把它放在正在使用的列表里返回,否则就调用
make_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)
可见,简单判断了一下创建的连接池是否超过了规定的数目,就调用了connection_class
connection_class也就是Connection类,也就是创建连接的地方
Connection这个类的构造函数中定义了一系列的和socket,TCP有关的参数
在make_connection方法里只是初始化了一下Connection类,还并没有创建socket连接
所以如果第一次连接的时候,在get_connection方法里add进的Connection的实例还没有连接过
连接是在execute_command方法里调用send_command方法的时候执行的:
def send_packed_command(self, command): "Send an already packed command to the Redis server" if not self._sock: self.connect() try: if isinstance(command, str): command = [command] for item in command: self._sock.sendall(item) except socket.timeout: self.disconnect() raise TimeoutError("Timeout writing to socket") except socket.error: e = sys.exc_info()[1] self.disconnect() if len(e.args) == 1: errno, errmsg = 'UNKNOWN', e.args[0] else: errno = e.args[0] errmsg = e.args[1] raise ConnectionError("Error %s while writing to socket. %s." % (errno, errmsg)) except: self.disconnect() raise
当调用self.connect()的时候,在这个方法里继续调用 _connect方法,在这个方法里创建了socket
所以,在调用完connect方法之后,Connection类的_sock对象就已经初始化完毕了
以后当再使用这个Connection实例的时候,由于socket已经初始化完成,就不必再继续创建socket了
通过socket的sendall方法,将命令发往redis服务器
在不出错的情况下,执行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)
这个方法将Connection实例从_in_use_connection列表转移到_available_connection列表
然后在parse_reponse方法里,将服务器返回的结果返回