python redis之连接池的原理

系统 1478 0

python redis之连接池的原理

 

转载地址

什么是连接池

通常情况下, 当我们需要做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连接(要不然怎么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 ) 和  正在使用的连接列表 从而实现连接池管理

 


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论