【问题标题】:High number of new Threads (10k's every 60 seconds) causing memory issues大量新线程(每 60 秒 10k)导致内存问题
【发布时间】:2018-06-09 23:12:06
【问题描述】:

我有一个 Ruby 应用程序,它每 60 秒为每个用户获取最近的消息。由于消息托管在远程 API 上,因此这是目前最实用的方法:

while true
  fetch_recent_messages do |result|
    # Handle result
  end

  sleep 60
end

def fetch_recent_messages()
  Thread.new do
    sleep_duration = 60 / @fetch_users.count

    for fetch_user in @fetch_users
      Thread.new do
        @api_manager.fetch_recent_messages_for_user(fetch_user)
        yield result
      end

      sleep sleep_duration
    end
  end
end
  1. fetch_recent_messages() 每 60 秒调用一次。
  2. @fetch_users 循环通过,在每次迭代中休眠适当的时间,因此该函数需要大约 60 秒才能在所有用户中调用 fetch_recent_messages_for_user()。这有助于分散网络和 CPU 负载。
  3. @fetch_users 循环的迭代初始化一个新线程,在该线程上执行 API 调用,然后将结果返回到 while 循环。

关键是每个 API 请求都会初始化一个新线程,以允许它们彼此异步发生。可能有大量用户,比如 10k,因此重要的是所有用户的获取消息请求都能够在相同的 60 秒内得到处理。这对于我的服务器上的 CPU/内存使用来说很好。

我注意到此应用的内存使用量在很长一段时间内自发地上升或下降,并且无法将其与任何特定行为相关联。这可能在以 15% 的 CPU 使用率运行 24 小时或更长时间后发生 - 它会突然跃升至 30%,然后一段时间后可能会上升到 40% 或再次下降。它似乎没有模式。除了创建新线程以观察性能之外,我最终将所有内容都注释掉了,这似乎是导致内存问题的原因。

我想知道在 Ruby 中是否存在维护大量线程的问题,以及我是否应该以不同的方式处理它们,或者可能以不同的方式执行此任务。

【问题讨论】:

    标签: ruby multithreading server


    【解决方案1】:

    对于大多数实现线程的语言,阈值低得惊人(我不知道,可能有数百个,取决于很多事情),超过这个阈值额外的线程就会出现问题。 (Erlang / Elixir 进程是一个戏剧性的例外。)

    我建议每隔一段时间检查一下你的系统,看看有多少线程在任何时候处于活动状态。

    此外,对于像这样在程序的生命周期中使用很多很多线程的用途,线程池通常用于大幅减少在创建和销毁线程。使用这些池,您可以拥有固定数量的线程,一旦它们的工作完成就可以重复使用这些线程。

    这里是 Ruby 中一种线程池实现的文档链接:https://github.com/ruby-concurrency/concurrent-ruby/blob/master/doc/thread_pools.md。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-13
      • 2015-10-18
      • 1970-01-01
      • 2018-04-23
      • 1970-01-01
      • 2011-10-27
      相关资源
      最近更新 更多