我们目前正在使用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')