У нас есть производственная система, работающая в следующей конфигурации:
Ruby 2.5.1
Rails 5.2.2
Sidekiq 5.2.5
Sidekiq-cron 1.1.0
Redis 4.1.0
adapter: postgresql
pool: 10
reaping_frequency: 10
timeout: 5000
username: ...
password: ...
host: ...
Имеет 3 очереди (по умолчанию / высокий / средний приоритет), каждая из которых имеет 4 потока. Недавно мы добавили новое задание sidekiq cron, которое выполняется каждые 30 минут в верхней очереди, и через пару дней система просто заходит в тупик, и больше потоков не может быть создано для пулов соединений. Мы проследили его до «высокой» очереди, и это новое задание, когда в последний раз он зависал, в этой «высокой» очереди было 1900 потоков, почти все из которых выглядят как «пул соединений». kill -9
в процессе для очереди, и наш супервизор перезапускает ее, и все снова отлично в течение 5-7 дней, а затем снова выключается.
Это новое задание создает ряд новых списков в удаленной БД, у нас есть локальная модель ActiveRecord для локальных записей и модель суперкласса RemoteList. Мы используем RemoteModel.establish_connection...
. транзакция открыть, написать, написать ..., закрыть транзакцию, закрыть соединение. Мы общаемся с большим количеством удаленных БД, поэтому эта модель хорошо работает для нас.
Новый сотрудник неоднократно обращается к издателю списка, который использовался более 3 лет без блокировки. Мы видим, как один новый процесс пула соединений добавляется каждый раз, когда мы пишем в удаленную БД через издателя старого списка.
Я пробовал:
- Ручное получение соединения из пула и возврат как для самого ActiveRecord, так и для нашего суперкласса, один, оба, ни одного.
- Завершение блока в
ActiveRecord::Base.connection_pool.with_connection
Ничто из вышеперечисленного не оказывает никакого влияния, и число потоков просто увеличивается с каждым разделенным нами файлом, пока мы не достигнем тупика и больше не будет потоков. Похоже, что пожинает, вообще ничего не делает. Единственное, что отличается в этом работнике, это то, что он open3.capture3
обращается к программе 'C', чтобы выполнить деление файлов гораздо быстрее, чем мы можем сделать в ruby, но я вижу, что порожденная оболочка закрылась и завершилась, но все же мы получить эти потоки «пула соединений».
У кого-нибудь есть какие-нибудь хорошие идеи.
Спасибо
Kate
Список публикаций
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