如何在redis中正确使用连接池?

时间:2015-07-27 21:04:38

标签: python python-2.7 redis

我不清楚连接池是如何工作的,以及如何正确使用它们。我希望有人可以详细说明。我在下面勾画了我的用例:

settings.py:

import redis

def get_redis_connection():
    return redis.StrictRedis(host='localhost', port=6379, db=0)

task1.py

import settings

connection = settings.get_redis_connection()

def do_something1():
    return connection.hgetall(...)

task2.py

import settings

connection = settings.get_redis_connection()

def do_something1():
    return connection.hgetall(...)

基本上我有一个返回redis连接的setting.py文件,以及几个获取redis连接的不同任务文件,然后运行操作。因此每个任务文件都有自己的redis实例(可能非常昂贵)。什么是优化此过程的最佳方式。是否可以在此示例中使用连接池?有没有更有效的方法来设置这种模式?

对于我们的系统,我们有相同模式的十几个任务文件,我注意到我们的请求变慢了。

由于

3 个答案:

答案 0 :(得分:17)

Redis-py为您提供了一个连接池,您可以从中检索连接。连接池创建一组连接,您可以根据需要使用这些连接(完成后 - 将连接返回到连接池以供进一步重用)。尝试在不丢弃它们的情况下即时创建连接(即不使用池或不正确使用池)将使您与redis的连接过多(直到达到连接限制)。

您可以选择在init方法中设置连接池并使池全局化(如果全局不舒服,您可以查看其他选项)。

redis_pool = None

def init():
    global redis_pool
    print("PID %d: initializing redis pool..." % os.getpid())
    redis_pool = redis.ConnectionPool(host='10.0.0.1', port=6379, db=0)

然后,您可以从池中检索连接:

redis_conn = redis.Redis(connection_pool=redis_pool)

另外,我假设您正在使用hiredis和redis-py,因为它应该在某些情况下提高性能。您是否还检查了使用现有设置打开redis服务器的连接数,因为它很可能非常高?您可以使用INFO命令获取该信息:

redis-cli info

检查客户端部分,您会在其中看到“ connected_clients ”字段,该字段将告诉您当时已向redis服务器开放的连接数。

答案 1 :(得分:8)

你应该使用基于redton-py的单例(borg模式)包装器,它将为你的所有文件提供一个公共连接池。 每当你使用这个包装类的对象时, 它将使用相同的连接池。

REDIS_SERVER_CONF = {
    'servers' : {
      'main_server': {
        'HOST' : 'X.X.X.X',
        'PORT' : 6379 ,
        'DATABASE':0
    }
  }
}

import redis
class RedisWrapper(object):
    shared_state = {}

    def __init__(self):
        self.__dict__ = self.shared_state

    def redis_connect(self, server_key):
        redis_server_conf = settings.REDIS_SERVER_CONF['servers'][server_key]
        connection_pool = redis.ConnectionPool(host=redis_server_conf['HOST'], port=redis_server_conf['PORT'],
                                               db=redis_server_conf['DATABASE'])
        return redis.StrictRedis(connection_pool=connection_pool)

用法:

r_server = RedisWrapper().redis_connect(server_key='main_server')
r_server.ping()

<强>更新

如果您的文件作为不同的进程运行,您将必须使用redis代理,它将为您汇集连接,而不是直接连接到redis,您将不得不使用代理。 一个非常稳定的redis(和memcached)代理是由twitter创建的twemproxy,主要目的是减少开放连接。

答案 2 :(得分:5)

这是来自奶酪店page的引用。

  

在幕后,redis-py使用连接池来管理与Redis服务器的连接。 默认情况下,您创建的每个Redis实例将依次创建自己的连接池。您可以通过将已创建的连接池实例传递给Redis类的connection_pool参数来覆盖此行为并使用现有连接池。您可以选择执行此操作以实现客户端分片,或者对如何管理连接进行更精细的控制。

pool = redis.ConnectionPool(host='localhost', port=6379, db=0)
r = redis.Redis(connection_pool=pool)

此外,实例are thread-safe

  

可以在线程之间安全地共享Redis客户端实例。在内部,连接实例仅在命令执行期间从连接池中检索,并在之后直接返回到池。命令执行永远不会修改客户端实例上的状态。

你说:

因此每个任务文件都有自己的redis实例(可能非常昂贵)。 ...对于我们的系统,我们有相同模式的十几个任务文件,并且我注意到我们的请求变慢了。

几十个连接几乎不可能减慢Redis服务器的速度。但是因为你的代码在幕后使用了连接池,所以问题就在于连接本身。 Redis是内存存储,因此在大多数可以想象的情况下都非常快。所以我宁愿在任务中寻找问题。

更新

来自@ user3813256的评论。是的,他在任务级别使用连接池。使用redis包的内置连接池的常规方法是共享连接。最简单的方法是,settings.py可能如下所示:

import redis

connection = None

def connect_to_redis():
    global connection
    connection = redis.StrictRedis(host='localhost', port=6379, db=0)

然后在你的应用程序调用{​​{1}}的引导中的某个地方。然后在任务模块中使用import connect_to_redis