gpt4 book ai didi

python - Redis 队列 + python-rq : Right pattern to prevent high memory usage?

转载 作者:IT王子 更新时间:2023-10-29 05:55:20 24 4
gpt4 key购买 nike

我们目前正在将 Redis 与我们的 Heroku 托管的 Python 应用程序一起使用。

我们将 Redis 与 python-rq 纯粹用作任务队列,以提供延迟执行一些时间密集型任务。一项任务是从 PostgreSQL 数据库中检索一些数据并将结果写回它 - 因此 Redis 实例中根本没有保存任何有值(value)的数据。我们注意到,根据执行的作业量,Redis 正在消耗越来越多的内存(增长速度约为 10 MB/小时)。 CLI 上的 FLUSHDB 命令修复了这个问题(将其减少到 ~700kB 使用的 RAM)直到 RAM 再次满。

根据我们(未更改的标准)设置,作业结果保留 500 秒。随着时间的推移,一些作业当然会失败,它们会被移到失败队列中。

  • 我们必须采取哪些不同的措施才能使用稳定数量的 RAM 完成任务?
  • RAM 消耗从何而来?
  • 我可以完全关闭持久性吗?
  • 从文档中我知道 500 秒 TTL 意味着 key 随后“过期”,但并未真正删除。此时 key 是否仍然消耗内存?我能以某种方式改变这种行为吗?
  • 它是否与失败的队列有关(它显然没有附加到作业的 TTL,这意味着(我认为)这些作业将永远保留)?
  • 只是好奇:当纯粹将 RQ 用作队列时,Redis DB 中保存了什么?它是实际的可执行代码还是只是对可以找到要执行的函数的位置的引用?

很抱歉问了一些非常菜鸟的问题,但我对排队这个话题还很陌生,在研究了 2 天多之后,我已经到了不知道下一步该做什么的地步。谢谢,KH

最佳答案

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

核心问题

实际问题是我们忽略了在将对象保存到 PostgreSQL 数据库之前将其转换为字符串。如果没有这个转换,字符串表示最终会出现在数据库中(由于相应对象的 __str__() 函数返回我们想要的表示);然而,对于 Redis,整个对象被传递了。将其传递给 Redis 后,相关任务崩溃并显示 UnpickleError异常(exception)。这消耗了崩溃后未释放的 5 MB RAM。

其他操作

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

  • 我们通过调用 enqueue_call([...] result_ttl=0) 将任务结果的 TTL 设置为 0
  • 我们定义了一个自定义异常处理程序 - black_hole - 接受所有异常并返回 False。这可以防止 Redis 将任务移动到失败的队列,在那里它仍然会使用一些内存。异常情况会事先通过电子邮件发送给我们以进行跟踪。

一路走来的有用工具:

我们刚刚使用了 redis-cli .

  • redis-cli info | grep used_memory_human --> 显示当前内存使用情况。比较任务执行前后内存占用的理想选择。
  • redis-cli keys '*' --> 显示所有当前存在的键。这个概述让我了解到有些任务没有被删除,即使它们应该被删除(如上所述,它们因 UnpickleError 而崩溃,因此没有被删除)。
  • redis-cli monitor --> 显示 Redis 中发生的事情的实时概览。这帮助我发现来回移动的物体太大了。
  • redis-cli debug object <key> --> 显示键值的转储。
  • redis-cli hgetall <key> --> 显示键值的可读性更高的转储(对于将 Redis 纯粹用作任务队列的特定用例特别有用,因为任务似乎是由 python-rq 以这种格式创建的。

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

From the docs I know that the 500 sec TTL means that a key is then "expired", but not really deleted. Does the key still consume memory at this point? Can I somehow change this behavior?

实际上,正如文档所暗示的那样,它们已被删除。

Does it have something to do with the failed queue (which apparently does not have a TTL attached to the jobs, meaning (I think) that these are kept forever)?

令人惊讶的是,Redis 本身崩溃的作业并没有移到失败队列中,它们只是被“放弃”了,这意味着值仍然存在,但 RQ 并不像处理失败作业那样关心它。

相关文档

关于python - Redis 队列 + python-rq : Right pattern to prevent high memory usage?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21270783/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com