REDIS队列 Python-RQ:防止高内存使用的正确模式



我们目前正在使用redis与我们的heroku horoku hoted python应用程序一起使用。

我们将redis与python-rq纯粹用作任务队列,以延迟执行某些时间启动任务。一项任务是从PostgreSQL数据库中检索一些数据,并将结果写回其中 - 因此,在REDIS实例中根本没有保存有价值的数据。我们注意到,根据执行的作业数量,Redis消耗了越来越多的内存(增长 @ 〜10 MB/小时)。CLI上的flushdb命令将其修复(将其降低到〜700kb使用的RAM),直到RAM再次满。

根据我们的(不变的标准)设置,将工作结果保留500秒。随着时间的流逝,某些工作当然会失败,他们被移至失败的队列。

  • 我们必须做些什么才能通过稳定数量的RAM完成任务?
  • RAM消耗从何而来?
  • 我可以完全关闭持久性吗?
  • 从文档中,我知道500秒TTL意味着键是"过期"的,但并未真正删除。此时,钥匙仍然会消耗内存吗?我可以以某种方式改变这种行为吗?
  • 它与失败的队列有关(显然没有与工作相关的TTL,这意味着(我认为)这些是永远保存的)?
  • 只是好奇:当将RQ纯粹用作队列时,Redis DB中保存了什么?它是实际可执行代码还是仅引用可以找到要执行的函数的参考?

对不起,这是一个鲁尼什的问题,但是我是排队的话题的新手,在研究了2天以上之后,我到达了下一步我不知道要这样做的地步。谢谢,kh

在玩了两天后,我发现了这个问题。我想与您分享,以及有用的工具:

核心问题

实际问题是,我们已经忽略了将对象施加到字符串之前,然后将其保存到PostgreSQL数据库。没有这种铸件,字符串表示结束在DB中(由于相应对象的__str__()函数,完全返回了我们想要的表示形式);但是,对于redis,通过了 thoter 对象。将其传递给REDIS后,关联的任务崩溃了UnpickleError异常。这消耗了5 MB RAM,这些RAM在坠机后未释放。

其他操作

为了进一步减少内存足迹,我们实施了以下补充操作(请注意,我们将所有内容保存到单独的DB中,因此在我们的应用程序中根本不使用Redis Saves的结果):

  • 我们将任务结果的ttl设置为0,使用呼叫enqueue_call([...] result_ttl=0)
  • 我们定义了一个自定常处理程序-black_hole-进行所有异常并返回false。这样可以防止REDIS将任务移至失败的队列,在该队列中仍将使用一些内存。事先通过电子邮件发送给我们以跟踪它们。

一路上有用的工具:

我们刚刚与redis-cli一起工作。

  • redis-cli info | grep used_memory_human->显示当前内存使用情况。在执行任务之前和之后比较内存足迹的理想选择。
  • redis-cli keys '*'->显示存在的所有当前密钥。这个概述使我有一个见解,即使应该被删除,某些任务也没有被删除(如上所述,它们坠毁了一个undickleerror,因此没有被删除)。
  • >
  • redis-cli monitor->显示了Redis中发生的事情的实时概述。这帮助我发现来回移动的物体太大了。
  • redis-cli debug object <key>->显示钥匙值的转储。
  • redis-cli hgetall <key>->显示了密钥值的更可读的转储(对于纯粹用作任务队列的特定用例尤其有用,因为看来这些任务是由Python-RQ以这种格式创建的。

此外,我可以回答上面发布的一些问题:

从文档中,我知道500秒TTL意味着键是"过期"的,但并未真正删除。此时,钥匙仍然会消耗内存吗?我可以以某种方式改变这种行为吗?

实际上,它们被删除,就像文档所暗示的那样。

它与失败的队列有关(显然没有与工作相关的TTL,这意味着(我认为)这些是永远保存的)?

令人惊讶的是,Redis本身崩溃的工作没有被转移到失败的队列中,它们只是"放弃",这意味着值仍然存在,但RQ并不关心失败的工作的正常方式。p> 相关文档

  • redis命令:http://redis.io/commands
  • "黑洞"异常处理程序和python-rq中的request_ttl:http://python-rq.org/docs/

如果您使用的是http://python-rq.org/docs/exceptions/的"黑洞"异常处理程序,则还应在此处添加job.cancel()

def black_hole(job, *exc_info):
    # Delete the job hash on redis, otherwise it will stay on the queue forever
    job.cancel()
    return False

对我而言并不明显的东西是RQ作业具有'描述'和'数据'属性。如果未指定,则将描述设置为数据的字符串表示,在我的情况下,这是不必要的冗长。明确将描述设置为简短的摘要使我省去了开销。

enqueue(func, longdata, description='short job summary')

相关内容

  • 没有找到相关文章

最新更新