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) 和 正在使用的连接列表从而实现连接池管理

python redis之连接池的原理的更多相关文章

  1. redis运用连接池报错解决

    redis使用连接池报错解决redis使用十几小时就一直报异常 redis.clients.jedis.exceptions.JedisConnectionException: Could not g ...

  2. nodejs + redis/mysql 连接池问题

    nodejs + redis/mysql 连接池问题 需不需要连接池 连接池的作用主要是较少每次临时建立连接所带来的开销.初步一看,nodejs运行单线程上,它不能同时使用多个连接,乍一看是不需要连接 ...

  3. Redis Java连接池调研

    Redis Java连接池调研 线上服务,由于压力大报错RedisTimeOut,但是需要定位到底问题出现在哪里? 查看Redis慢日志,slowlog get 发现耗时最大的也是11000us也就是 ...

  4. Redis缓存连接池管理

    import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.util.Assert;import ...

  5. DBCP数据源连接池实现原理分析

    前些天在调试公司系统的时候发现这样的一个问题:mysql数据库服务停止一段时间后再次重启后吗,tomcat服务无法请求数据库服务,调试了半天对这个问题进行定位解决,期间也搞了很多有关mysql数据库的 ...

  6. java客户端Jedis操作Redis Sentinel 连接池

    pom配置: <dependency> <groupId>org.springframework.data</groupId> <artifactId> ...

  7. redis mysql 连接池 之 golang 实现

    1 mysql 连接池代码 package lib import ( "database/sql" "fmt" "strconv" &quo ...

  8. python redis的连接及相关操作

    1.redis连接.及存取值 import redis r = redis.Redis(host='192.168.2.22',port=6379,db=2,password= 'redis') r. ...

  9. redis单机连接池

    一.配置文件 1. db.properties配置文件#IP地址 redis.ip = 127.0.0.1 #端口号 redis.port= #最大连接数 redis.max.total= #最大空闲 ...

随机推荐

  1. Babel编辑ES6代码

    1.安装babel依赖 npm install --save-dev @babel/core @babel/cli @babel/preset-env npm install --save @babe ...

  2. DH加密算法

    http://blog.csdn.net/zbw18297786698/article/details/53609794

  3. Mysql : Maximum execution time of 30 seconds exceeded

    在向Mysql数据库中插入数据时,提示Maximum execution time of 30 seconds exceeded.......翻译:最大运行时间超过30秒. 最后在php.ini中找到 ...

  4. [mysql]SQL语句-新增/修改 创建时间 更新时间

    SQL关键词 要注意大小写   已建表,之前没有创建时间列, 现新增1列创建时间,并设置默认值为当前时间 --添加CreateTime 设置默认时间 CURRENT_TIMESTAMP ALTER T ...

  5. 去除雨滴的滤镜 Derain in FFmpeg

    Remove the rain in the input image/video by applying the derain methods based on convolutional neura ...

  6. 微信小程序组件篇实战

    实现效果如下: 实现代码如下: index.wxml: <!--index.wxml--> <view class="container"> <vie ...

  7. java并发编程 线程间协作

    线程间协作 1. 等待和通知 等待和通知的标准形式 等待方: 获取对象锁 循环中判断条件是否满足,不调用wait()方法 条件满足执行业务逻辑 通知方: 获取对象所 改变条件 通知所有等待在对象的线程 ...

  8. 基于LVM(逻辑卷管理)的快照原理

    一.为甚么不管多大的逻辑卷进行备份,快照都会在几秒之内完成? 快照在拍摄的一瞬间,系统会记录那个时间点逻辑卷的状态.数据等,此时拍下的快照相当于一张白纸.如图所示 快照做好后,随着时间的推移,源卷里的 ...

  9. 【LeetCode】188、买卖股票的最佳时机 IV

    Best Time to Buy and Sell Stock IV 题目等级:Hard 题目描述: Say you have an array for which the ith element i ...

  10. PostgreSQL通过解析日志,获取数据库增量变化,pg_recvlogical

    1.首先用该工具来看我们的日志变化,需要先将test_decoding插件编译并安装(进入contrib,编译安装即可) 创建一个slot: SELECT * FROM pg_create_logic ...