草庐IT

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

coder 2023-07-17 原文

我们目前正在将 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/

有关python - Redis 队列 + python-rq : Right pattern to prevent high memory usage?的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby - 分布式事务和队列,ruby,erlang,scala - 2

    我有一个涉及多台机器、消息队列和事务的问题。因此,例如用户点击网页,点击将消息发送到另一台机器,该机器将付款添加到用户的帐户。每秒可能有数千次点击。事务的所有方面都应该是容错的。我以前从未遇到过这样的事情,但一些阅读表明这是一个众所周知的问题。所以我的问题。我假设安全的方法是使用两阶段提交,但协议(protocol)是阻塞的,所以我不会获得所需的性能,我是否正确?我通常写Ruby,但似乎Redis之类的数据库和Rescue、RabbitMQ等消息队列系统对我的帮助不大——即使我实现某种两阶段提交,如果Redis崩溃,数据也会丢失,因为它本质上只是内存。所有这些让我开始关注erlang和

  4. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

  5. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  6. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  7. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  8. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

  9. 「Python|Selenium|场景案例」如何定位iframe中的元素? - 2

    本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决

  10. python ffmpeg 使用 pyav 转换 一组图像 到 视频 - 2

    2022/8/4更新支持加入水印水印必须包含透明图像,并且水印图像大小要等于原图像的大小pythonconvert_image_to_video.py-f30-mwatermark.pngim_dirout.mkv2022/6/21更新让命令行参数更加易用新的命令行使用方法pythonconvert_image_to_video.py-f30im_dirout.mkvFFMPEG命令行转换一组JPG图像到视频时,是将这组图像视为MJPG流。我需要转换一组PNG图像到视频,FFMPEG就不认了。pyav内置了ffmpeg库,不需要系统带有ffmpeg工具因此我使用ffmpeg的python包装p

随机推荐