关于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方法里,将服务器返回的结果返回

 

posted @ 2018-08-04 18:22  geeklove  阅读(4380)  评论(0编辑  收藏  举报