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

vgo*_*ani 28 python redis python-2.7

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

settings.py:

import redis

def get_redis_connection():
    return redis.StrictRedis(host='localhost', port=6379, db=0)
Run Code Online (Sandbox Code Playgroud)

task1.py

import settings

connection = settings.get_redis_connection()

def do_something1():
    return connection.hgetall(...)
Run Code Online (Sandbox Code Playgroud)

task2.py

import settings

connection = settings.get_redis_connection()

def do_something1():
    return connection.hgetall(...)
Run Code Online (Sandbox Code Playgroud)

等等


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

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

谢谢

ali*_*der 19

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)
Run Code Online (Sandbox Code Playgroud)

然后,您可以从池中检索连接,如下所示:

redis_conn = redis.Redis(connection_pool=redis_pool)
Run Code Online (Sandbox Code Playgroud)

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

redis-cli info
Run Code Online (Sandbox Code Playgroud)

检查" 客户端"部分,在该部分中您将看到" connected_clients "字段,该字段将告诉您在该时刻已向redis服务器打开了多少连接.


Dhr*_*hak 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)
Run Code Online (Sandbox Code Playgroud)

用法:

r_server = RedisWrapper().redis_connect(server_key='main_server')
r_server.ping()
Run Code Online (Sandbox Code Playgroud)

UPDATE

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


saa*_*aaj 6

这是来自奶酪店页面的报价。

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

pool = redis.ConnectionPool(host='localhost', port=6379, db=0)
r = redis.Redis(connection_pool=pool)
Run Code Online (Sandbox Code Playgroud)

此外,实例是线程安全的

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)
Run Code Online (Sandbox Code Playgroud)

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

  • OP未使用连接池!他正在从每个模块中产生一个新的连接(并且不显示是否在任何地方关闭该连接)。是的,问题可能在其他地方,但是连接(基于共享的代码)不是来自于池,也不是被关闭。 (2认同)