首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Sidekiq,线程耗尽. Rails离开而不捕获connection_pool线程

Sidekiq,线程耗尽. Rails离开而不捕获connection_pool线程
EN

Stack Overflow用户
提问于 2019-05-21 15:50:32
回答 2查看 891关注 0票数 3

我们有一个生产系统运行在以下配置中:

代码语言:javascript
复制
Ruby 2.5.1
Rails 5.2.2
Sidekiq 5.2.5
Sidekiq-cron 1.1.0
Redis 4.1.0
代码语言:javascript
复制
  adapter: postgresql
  pool: 10
  reaping_frequency: 10
  timeout: 5000
  username: ...
  password: ...
  host: ...

它有3个队列(默认/高/med优先级),每个队列都有4个线程。我们最近增加了一个新的added作业,它在高队列中每30分钟运行一次,几天后,系统就陷入僵局,无法为连接池生成更多的线程。我们已经追踪到'high‘队列和这个新作业,上次它挂起这个'high’队列时有190个线程,几乎所有线程看起来都是‘连接池’。队列进程上的kill -9和我们的主管重新启动它,这一切都是伟大的5-7天,然后再次停机。

这个新任务在远程DB中创建了许多新的列表,我们有本地记录的本地ActiveRecord模型和超类RemoteList模型。我们使用RemoteModel.establish_connection...。事务打开,写,写.,关闭事务,关闭连接。我们与大量的远程DB交谈,因此这个模型对我们来说很好。

新员工不断地向列表发布者发出呼叫,该列表发布者已经使用了3+多年,没有发布锁。我们可以看到,每次通过旧列表发布服务器向远程DB写入时,都会添加一个新的连接池进程。

我试过:

  1. 手动从池中获取连接并返回,对于ActiveRecord本身和我们的超类,一个、两个都没有。
  2. ActiveRecord::Base.connection_pool.with_connection中包装块

上面的任何一个都没有任何影响,并且线程计数只是随着我们拆分的每个文件而不断增长,直到我们到达死锁,并且没有更多的线程。收割一点也不像在做什么。这个工作程序唯一的不同之处在于,它调用open3.capture3到一个'C‘程序,以便比我们在ruby中所能做的更快地进行一些文件分割,但是我可以看到,生成的shell已经关闭并完成了,但是我们仍然得到了这些’连接池‘线程。

外面的任何人都有好主意。

谢谢凯特

列表发布

代码语言:javascript
复制
CoreDBListModel.semaphore.synchronize do
    begin

      .... setup removed....
      CoreDBListModel.establish_connection(@config['database'])

      CoreDBListModel.transaction do
        core = CoreDBListModel.where(:description => list.list_id).first
        core.pending = true
        core.name = list.name
        core.tags = category.name
        core.pcount = list.count
        core.active = list.deleted ? 2:0
        core.save

        ... make list insert data.....
        mass_insert = "INSERT INTO #{mapping['table']} (data_id, data, fulldata) VALUES #{inserts.join(", ")}"
        CoreDBListModel.connection.execute(mass_insert)

      # Mark as completed
        core.pending = false
        core.save

      end

    rescue => e
      @code = 500
      @message = "Failed - #{e.message}, #{e.backtrace[0]}"
      Rails.logger.error("CoreDBList() - Publishing failed - #{list.list_id}")
      Rails.logger.error("CoreDBList() - Publishing failed - #{e.message}")
      Rails.logger.error("CoreDBList() - Publishing failed - #{e.backtrace.first(10).join("\n")}")
    ensure
      begin
        # Close our DB connection
        CoreDBListModel.connection.close
      rescue
      end
    end
  end

在下面添加了一个包含更多细节的答案,但基本上问题似乎与Rails有关,在5.1.6和5.2.1之间。如果我们回到5.1.6,问题就解决了。

https://github.com/rails/rails/issues/36333

EN

回答 2

Stack Overflow用户

发布于 2019-05-21 17:43:19

首先,确定线程泄漏的速度--它是在每个任务运行时发生,还是在一段时间内偶尔发生?如果前者-您很幸运,并且可以尝试通过日志记录ObjectSpace.each_object(Thread).count (注意,这是一个沉重的功能,可能不适合在生产中的高负载)在您的代码中的几个点,试图检测哪里的线程泄漏。

怀疑是Open3.capture3 --它启动两个线程来读取进程的stdin/stdout,另一个线程用于读取进程退出状态,如果在C代码中不使用单独的stderr,我建议切换到capture2,看看线程是否泄漏速度慢了1/3倍。我记得popen3和子进程没有使用stderr,或者没有打开/关闭std流,或者没有读取stdin,现在我已经记不起细节了。

票数 1
EN

Stack Overflow用户

发布于 2019-05-23 10:08:43

这不是一个答案,而是一个关于这个问题的更新,今天上午,我们的一个服务器再次发生故障,其中一个31000+线程运行在一个侧翼任务上。

看起来这是Rails ActiveRecord的一个问题,我们可以用一些测试代码成功地将沉睡的线程抛在后面。它是“CoreDBListModel.connection.close”,它使连接池进入睡眠状态,但由于其状态,它从未收获过。

看起来,当我们从Rails 5.1.5迁移到5.2.1时,问题就开始了,如果我们回过头来看这个问题,这个问题在Rails 6中似乎也存在,因为其他人也提出了类似的问题,名称略有不同,但问题相同:

https://github.com/rails/rails/issues/36333

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56242038

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档