python redis之链接池的原理

python redis之链接池的原理

 

转载地址python

什么是链接池

一般状况下, 当咱们须要作redis操做时, 会建立一个链接, 并基于这个链接进行redis操做, 操做完成后, 释放链接,redis

通常状况下, 这是没问题的, 但当并发量比较高的时候, 频繁的链接建立和释放对性能会有较高的影响并发

因而, 链接池就发挥做用了app

链接池的原理是, 经过预先建立多个链接, 当进行redis操做时, 直接获取已经建立的链接进行操做, 并且操做完成后, 不会释放, 用于后续的其余redis操做性能

这样就达到了避免频繁的redis链接建立和释放的目的, 从而提升性能了spa

 

原理

那么, 在redis-py中, 他是怎么进行链接池管理的呢code

链接池使用

首先看下如何进行链接池操做的对象

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 实例化的时候, 作了什么blog

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链接, 仅仅是设置最大链接数, 链接参数和链接类rem

StrictRedis 实例化的时候, 又作了什么

def __init__(self, ...connection_pool=None...): if not connection_pool: ... connection_pool = ConnectionPool(**kwargs) self.connection_pool = connection_pool

以上仅保留了关键部分代码

能够看出, 使用StrictRedis 即便不建立链接池, 他也会本身建立

到这里, 咱们尚未看到什么redis链接真实发生

继续

下一步就是set 操做了, 很明显, 这个时候必定会发生redis链接(要否则怎么set)

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的实例中, 有两个list, 依次是_available_connections_in_use_connections,

分别表示可用的链接集合正在使用的链接集合, 在上面的get_connection中, 咱们能够看到获取链接的过程是

  1. 从可用链接集合尝试获取链接,
  2. 若是获取不到, 从新建立链接
  3. 将获取到的链接添加到正在使用的链接集合

上面是往_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) 和 正在使用的链接列表从而实现链接池管理

相关文章
相关标签/搜索