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

问题描述 投票:27回答:3

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

settings.朋友:

import redis

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

task1.朋友

import settings

connection = settings.get_redis_connection()

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

task2.朋友

import settings

connection = settings.get_redis_connection()

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

等等


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

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

谢谢

python python-2.7 redis
3个回答
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服务器打开了多少连接。


9
投票

您将使用基于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()

UPDATE

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


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是内存存储,因此在大多数可以想象的情况下都非常快。所以我宁愿在任务中寻找问题。

Update

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

import redis

connection = None

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

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

© www.soinside.com 2019 - 2024. All rights reserved.