У меня также возникают проблемы с пулом соединений при попытке запустить приложение Sinatra / ActiveRecord в многопоточном режиме в контейнере Glassfishv3. Приложение включает блок «before» с ActiveRecord::Base.connection
для принудительного получения подключения, принадлежащего потоку, и блок «after» с ActiveRecord::Base.clear_active_connections!
для освобождения этого подключения.
Многопоточный режим
Я испробовал множество вариантов ActiveRecord 3.0.12 и 3.2.3, JNDI с пулом соединений Glassfish, просто используя пул соединений ActiveRecord или даже обезьяны, исправляющие пул соединений ActiveRecord, чтобы полностью обойти его, используя пул Glassfish непосредственно.
При тестировании с использованием простого многопоточного сборщика HTTP все варианты, которые я пробовал, приводили к ошибкам с большим процентом неудачных запросов при увеличении рабочих потоков в сборщике HTTP.
В AR 3.0.12 типичной ошибкой является то, что пул Glassfish выдает исключение тайм-аута (для чего бы то ни было, мой пул AR-подключений больше, чем мой Glassfish-пул; я понимаю, что AR будет объединять объект адаптера соединения, а arjdbc будет получить и выпустить реальные связи за кулисами).
С AR 3.2.3 я получаю более зловещую ошибку. Приведенная ниже ошибка возникла в результате теста, в котором не использовался JNDI, а просто использовался пул соединений ActiveRecord. Это одна из лучших конфигураций, в которой около 95% запросов выполняются нормально. Запросы об ошибках завершаются с этим исключением:
org.jruby.exceptions.RaiseException: (ConcurrencyError) Detected invalid hash contents due to unsynchronized modifications with concurrent users
at org.jruby.RubyHash.keys(org/jruby/RubyHash.java:1356)
at ActiveRecord::ConnectionAdapters::ConnectionPool.release(/Users/pat/app/glassfish/glassfish3/glassfish/domains/domain1/applications/lookup_service/WEB-INF/gems/gems/activerecord-3.2.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:294)
at ActiveRecord::ConnectionAdapters::ConnectionPool.checkin(/Users/pat/app/glassfish/glassfish3/glassfish/domains/domain1/applications/lookup_service/WEB-INF/gems/gems/activerecord-3.2.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:282)
at MonitorMixin.mon_synchronize(classpath:/META-INF/jruby.home/lib/ruby/1.9/monitor.rb:201)
at MonitorMixin.mon_synchronize(classpath:/META-INF/jruby.home/lib/ruby/1.9/monitor.rb:200)
at ActiveRecord::ConnectionAdapters::ConnectionPool.checkin(/Users/pat/app/glassfish/glassfish3/glassfish/domains/domain1/applications/lookup_service/WEB-INF/gems/gems/activerecord-3.2.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:276)
at ActiveRecord::ConnectionAdapters::ConnectionPool.release_connection(/Users/pat/apps/glassfish/glassfish3/glassfish/domains/domain1/applications/lookup_service/WEB-INF/gems/gems/activerecord-3.2.3/lib/active_record/connection_adapters/abstrac/connection_pool.rb:110)
at ActiveRecord::ConnectionAdapters::ConnectionHandler.clear_active_connections!(/Users/pat/apps/glassfish/glassfish3/glassfish/domains/domain1/applications/lookup_service/WEB-INF/gems/gems/activerecord-3.2.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:375)
...
однопоточный режим
Потеряв уверенность в общей безопасности потоков ActiveRecord (или arjdbc?), Я отказался от использования многопоточного и сконфигурированного warbler ActiveRecord и JRuby-Rack для создания пула времени выполнения JRuby , эмулируя несколько однопоточных процессов Ruby так же, как Unicorn, Thin и другие типичные серверы Ruby.
В config / warble.rb:
config.webxml.jruby.min.runtimes = 10
config.webxml.jruby.max.runtimes = 10
Я перезапустил свой тест, используя на этот раз JNDI, и все запросы были выполнены без ошибок!
Мой пул соединений Glassfish имеет размер 5. Обратите внимание, что количество рабочих циклов jruby больше, чем размер пула соединений. Вероятно, нет смысла делать пул времени выполнения JRuby больше пула соединений с базой данных, поскольку в этом приложении каждый запрос использует соединение с базой данных, но я просто хотел убедиться, что даже при конфликте за соединения с базой данных я не получил время. ошибки, которые я видел в многопоточном режиме.
Эти проблемы параллелизма неутешительны, если не сказать больше. Кто-нибудь успешно использует ActiveRecord при умеренном параллелизме? Я знаю, что в приложении Rails нужно вызывать config.threadsafe!
, чтобы избежать глобальной блокировки. Глядя на код, он, похоже, не изменяет никаких настроек ActiveRecord; Есть ли какая-то конфигурация ActiveRecord, которой я не занимаюсь?