Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use RAILS_MAX_THREADS for client pool size #3807

Merged
merged 1 commit into from
Mar 27, 2018

Conversation

cupakromer
Copy link
Contributor

This is a follow up to #2985 (52828e4) adding similar support for the client connection pool. For Rails servers, Sidekiq is not loaded from the CLI so the prior change to support setting the concurrency via RAILS_MAX_THREADS is not applied to the web server process. This means for Rails servers which do not configure a custom size through an initializer they will run with the default connection pool size of 5.

When the Rails server runs the initial Redis connection may be made through Sidekiq::Client (e.g. from ActiveJob::QueueAdapters::SidekiqAdapter). This causes the redis_pool to be initialized without any options, setting the pool size to the default of 5.

.gem/ruby/2.5.0/gems/sidekiq-5.1.1/lib/sidekiq.rb:125:in `redis_pool'
.gem/ruby/2.5.0/gems/sidekiq-5.1.1/lib/sidekiq/client.rb:42:in `initialize'
.gem/ruby/2.5.0/gems/sidekiq-5.1.1/lib/sidekiq/client.rb:131:in `new'
.gem/ruby/2.5.0/gems/sidekiq-5.1.1/lib/sidekiq/client.rb:131:in `push'
.gem/ruby/2.5.0/gems/activejob-5.1.5/lib/active_job/queue_adapters/sidekiq_adapter.rb:20:in `enqueue'
.gem/ruby/2.5.0/gems/activejob-5.1.5/lib/active_job/enqueuing.rb:51:in `block in enqueue'
.gem/ruby/2.5.0/gems/activesupport-5.1.5/lib/active_support/callbacks.rb:108:in `block in run_callbacks'
.gem/ruby/2.5.0/gems/activejob-5.1.5/lib/active_job/logging.rb:15:in `block (3 levels) in <module:Logging>'
.gem/ruby/2.5.0/gems/activejob-5.1.5/lib/active_job/logging.rb:44:in `block in tag_logger'
.gem/ruby/2.5.0/gems/activesupport-5.1.5/lib/active_support/tagged_logging.rb:69:in `block in tagged'
.gem/ruby/2.5.0/gems/activesupport-5.1.5/lib/active_support/tagged_logging.rb:26:in `tagged'
.gem/ruby/2.5.0/gems/activesupport-5.1.5/lib/active_support/tagged_logging.rb:69:in `tagged'
.gem/ruby/2.5.0/gems/activejob-5.1.5/lib/active_job/logging.rb:44:in `tag_logger'
.gem/ruby/2.5.0/gems/activejob-5.1.5/lib/active_job/logging.rb:14:in `block (2 levels) in <module:Logging>'
.gem/ruby/2.5.0/gems/activesupport-5.1.5/lib/active_support/callbacks.rb:117:in `instance_exec'
.gem/ruby/2.5.0/gems/activesupport-5.1.5/lib/active_support/callbacks.rb:117:in `block in run_callbacks'
.gem/ruby/2.5.0/gems/activesupport-5.1.5/lib/active_support/callbacks.rb:135:in `run_callbacks'
.gem/ruby/2.5.0/gems/activejob-5.1.5/lib/active_job/enqueuing.rb:47:in `enqueue'
.gem/ruby/2.5.0/gems/activejob-5.1.5/lib/active_job/enqueuing.rb:18:in `perform_later'

For the majority of cases, a client pool size of 5 is sufficient. However, servers which utilize a high number of threads, with large job payloads, and which may experience some network latency issues can see Timeout::Error crashes. This may be further exacerbated by the ~2-20x performance decrease through ActiveJob (#3782). Rails addresses this general type of connection issue for the main database by suggesting that the DB pool size match the number of threads running. This change applies that logic to the default client pool size by leveraging the same environment setting; this way there's a connection available per thread.

This may also have the side effect of a slight performance boost, as there is less of a chance that threads will be blocked waiting on connections. The trade-off is that there may be a memory profile increase to handle the additional Redis connections in the pool; note the pool only creates new connections as necessary to handle the requests.

Resolves #3806

This is a follow up to sidekiq#2985 (52828e4) adding similar support for the
client connection pool. For Rails servers, Sidekiq is not loaded from
the CLI so the prior change to support setting the concurrency via
`RAILS_MAX_THREADS` is not applied to the web server process. This means
for Rails servers which do not configure a custom size through an
initializer they will run with the default connection pool size of 5.

When the Rails server runs the initial Redis connection may be made
through `Sidekiq::Client` (e.g. from [`ActiveJob::QueueAdapters::SidekiqAdapter`](https://github.com/rails/rails/blob/v5.1.5/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb#L20)).
This causes the `redis_pool` to be initialized without any options,
setting the pool size to the default of 5.

    .gem/ruby/2.5.0/gems/sidekiq-5.1.1/lib/sidekiq.rb:125:in `redis_pool'
    .gem/ruby/2.5.0/gems/sidekiq-5.1.1/lib/sidekiq/client.rb:42:in `initialize'
    .gem/ruby/2.5.0/gems/sidekiq-5.1.1/lib/sidekiq/client.rb:131:in `new'
    .gem/ruby/2.5.0/gems/sidekiq-5.1.1/lib/sidekiq/client.rb:131:in `push'
    .gem/ruby/2.5.0/gems/activejob-5.1.5/lib/active_job/queue_adapters/sidekiq_adapter.rb:20:in `enqueue'
    .gem/ruby/2.5.0/gems/activejob-5.1.5/lib/active_job/enqueuing.rb:51:in `block in enqueue'
    .gem/ruby/2.5.0/gems/activesupport-5.1.5/lib/active_support/callbacks.rb:108:in `block in run_callbacks'
    .gem/ruby/2.5.0/gems/activejob-5.1.5/lib/active_job/logging.rb:15:in `block (3 levels) in <module:Logging>'
    .gem/ruby/2.5.0/gems/activejob-5.1.5/lib/active_job/logging.rb:44:in `block in tag_logger'
    .gem/ruby/2.5.0/gems/activesupport-5.1.5/lib/active_support/tagged_logging.rb:69:in `block in tagged'
    .gem/ruby/2.5.0/gems/activesupport-5.1.5/lib/active_support/tagged_logging.rb:26:in `tagged'
    .gem/ruby/2.5.0/gems/activesupport-5.1.5/lib/active_support/tagged_logging.rb:69:in `tagged'
    .gem/ruby/2.5.0/gems/activejob-5.1.5/lib/active_job/logging.rb:44:in `tag_logger'
    .gem/ruby/2.5.0/gems/activejob-5.1.5/lib/active_job/logging.rb:14:in `block (2 levels) in <module:Logging>'
    .gem/ruby/2.5.0/gems/activesupport-5.1.5/lib/active_support/callbacks.rb:117:in `instance_exec'
    .gem/ruby/2.5.0/gems/activesupport-5.1.5/lib/active_support/callbacks.rb:117:in `block in run_callbacks'
    .gem/ruby/2.5.0/gems/activesupport-5.1.5/lib/active_support/callbacks.rb:135:in `run_callbacks'
    .gem/ruby/2.5.0/gems/activejob-5.1.5/lib/active_job/enqueuing.rb:47:in `enqueue'
    .gem/ruby/2.5.0/gems/activejob-5.1.5/lib/active_job/enqueuing.rb:18:in `perform_later'

For the majority of cases, a client pool size of 5 is sufficient.
However, servers which utilize a high number of threads, with large job
payloads, and which may experience some network latency issues can see
`Timeout::Error` crashes. This may be further exacerbated by the ~2-20x
performance decrease through `ActiveJob` (sidekiq#3782). Rails addresses this
general type of connection issue for the main database by suggesting
that the DB pool size match the number of threads running. This change
applies that logic to the default client pool size by leveraging the
same environment setting; this way there's a connection available per
thread.

This may also have the side effect of a slight performance boost, as
there is less of a chance that threads will be blocked waiting on
connections. The trade-off is that there may be a memory profile
increase to handle the additional Redis connections in the pool; note
the pool only creates new connections as necessary to handle the
requests.

Resolves sidekiq#3806
@mperham mperham merged commit b23c0ec into sidekiq:master Mar 27, 2018
@mperham
Copy link
Collaborator

mperham commented Mar 27, 2018

Really solid work. 🤘

@cupakromer cupakromer deleted the use-rails_max_threads-for-pool branch March 27, 2018 23:01
tahb added a commit to DFE-Digital/teaching-vacancies that referenced this pull request Feb 28, 2019
* Everything uses 5 threads by default
* We can change this setting by a variable if we really need to make tweaks (due to memory usage investigation in this case)
* This will reduce Sidekiq from the default 10 concurrency to 5 which is the default active record pool size.
* RAILS_MAX_THREADS variable used as the configurable variable for this. Sidekiq have done so here sidekiq/sidekiq#3807
tahb added a commit to DFE-Digital/teaching-vacancies that referenced this pull request Mar 1, 2019
* Everything uses 5 threads by default
* We can change this setting by a variable if we really need to make tweaks (due to memory usage investigation in this case)
* This will reduce Sidekiq from the default 10 concurrency to 5 which is the default active record pool size.
* RAILS_MAX_THREADS variable used as the configurable variable for this. Sidekiq have done so here sidekiq/sidekiq#3807
tahb added a commit to DFE-Digital/teaching-vacancies that referenced this pull request Mar 4, 2019
* Everything uses 5 threads by default. Before this change Sidekiq was
using 10 workers which was more than the 5 default active record
connections. This can lead to database connection issues for Sidekiq.
From our autoscaling work we know that we are comfortable with each
container having 5 puma threads and 5 db connections so we need Sidekiq
to follow along for stability
* We can change this setting by a variable if we really need to make tweaks (due to memory usage investigation in this case), I'd suggest we update variables.tf in a more permenant change rather than through .tfvars which suggests it's safe to tweak with per each environment
* This will reduce Sidekiq from the default 10 concurrency to 5 which is the default active record pool size.
* RAILS_MAX_THREADS variable used as the configurable variable for this. Sidekiq have done so here sidekiq/sidekiq#3807
erbridge pushed a commit to DFE-Digital/teaching-vacancies that referenced this pull request Apr 24, 2019
* Everything uses 5 threads by default. Before this change Sidekiq was
using 10 workers which was more than the 5 default active record
connections. This can lead to database connection issues for Sidekiq.
From our autoscaling work we know that we are comfortable with each
container having 5 puma threads and 5 db connections so we need Sidekiq
to follow along for stability
* We can change this setting by a variable if we really need to make tweaks (due to memory usage investigation in this case), I'd suggest we update variables.tf in a more permenant change rather than through .tfvars which suggests it's safe to tweak with per each environment
* This will reduce Sidekiq from the default 10 concurrency to 5 which is the default active record pool size.
* RAILS_MAX_THREADS variable used as the configurable variable for this. Sidekiq have done so here sidekiq/sidekiq#3807
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants