【问题标题】:Ruby: What can cause execution of same codeblock to slowdown over time when ran over and over again?Ruby:当一遍又一遍地运行时,什么会导致相同代码块的执行随着时间的推移而减慢?
【发布时间】:2013-07-12 21:16:37
【问题描述】:

我的 rails 项目中有一个后台工作人员,它在 ruby​​ 中执行大量复杂的内存中数据聚合。我看到一个奇怪的行为。当我启动一个执行作业(数千个)的进程时,我发现随着时间的推移性能出现奇怪的下降。一开始,一个作业完成大约需要 300 毫秒,但在处理了大约 10.000 个作业后,执行时间将逐渐减少到 2000 毫秒左右。这对我来说是一个大问题,我对这怎么可能发生感到困惑。我没有看到内存泄漏(RAM 使用非常稳定),也没有看到任何错误。什么可能导致这种情况偏低,我应该从哪里开始寻找?

背景事实:

  • 在这项工作所做的事情中,它会对大量字符串进行大量正则表达式比较。除了对 redis 实例的读/写操作外,没有进行外部数据库调用。
  • 我曾尝试在不同的服务器/计算机上执行相同的操作,但症状都相同。
  • 如果我在进程开始表现不佳时重新启动该进程,则性能会立即恢复正常。
    • 我正在为作业处理器运行 ruby​​ 1.9.3p194 和 rails 3.2 和 sidekiq 2.9.0

【问题讨论】:

  • 如果您提供一些后台数据聚合过程的代码,可能会提供一些见解
  • 感谢您的提问,但很抱歉,我认为几乎不可能以一种能够真正提供有用见解的方式提供,因为它做了很多事情。这是一项顶级工作,执行整个管道数据清理和聚合。这就是为什么我没有问“我在这段代码中做错了什么”,而是问“一个进程(理论上)如何/如何随着时间的推移执行相同的代码变得越来越慢” - 因为除了内存泄漏,我什么都不知道,而且似乎没有。
  • 可能在数据缓存上存在一些 O(n) 或更差的性能问题 - 它可能足够小以至于您在检查一般内存问题时不会注意到 -例如,符号表中的一百万个符号可能只占用几 MB,但如果您遍历它们以检查数据结构中的键,您会注意到差异。例如。如果您对包含任意键(每个输入不同)的 JSON 哈希进行 symbolize_keys 处理,如果您的进程严重依赖符号查找的效率,您可能会在处理几千个后看到这种行为。 . .
  • 有趣!!!我实际上做了很多 - 也许你应该将该评论更改为答案而不是@Neil Slater BTW。在放什么)?能给个链接什么的吗?
  • 对我上面的评论的补充:我觉得我读你的评论有点太快了,我通常使用 symbolize_keys 和符号相当多,但是我认为我使用的键名是相当静态的。 ..

标签: ruby-on-rails ruby performance sidekiq


【解决方案1】:

很难从您的服务的有限描述中看出,但该行为与查找性能较差或您非常依赖的小型(即不泄漏)数据缓存一致,并且正在以适度的速度增长。一个人为的示例可能是“该工作人员迄今为止完成的工作”的列表,该列表在代码中的几个点按需排序。

其中一个缓存不受您的直接控制:Ruby 的符号表。查找符号类似于系统中符号数量的 O(log(n)),这很好。但是,如果您处理大量符号,这仍然会影响您,并且您的工作人员的每次迭代都可以生成新符号(例如,如果输入哈希中的键可以是任意数据,并且您使用 symbolize_keys 方法或调用 @987654322 @ 在很多不同的字符串上)。符号在 Ruby 进程中被永久缓存。理论上,几百万不会显示为内存泄漏。但是,如果您的代码总共可以从 10,000 个符号增加到 1,000,000 个,则所有符号生成和检查代码都会减慢一个固定的小幅度。如果你经常这样做,它可能会解释几百毫秒。

如果通过搜索可疑代码无济于事,那么找出问题的最佳选择是使用分析器。您应该收集表现良好和表现不佳的代码的概要文件,并将两者进行比较。

【讨论】:

    猜你喜欢
    • 2014-07-17
    • 1970-01-01
    • 1970-01-01
    • 2017-11-02
    • 1970-01-01
    • 2017-02-19
    • 1970-01-01
    • 2022-01-09
    相关资源
    最近更新 更多