Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure Redis connections with Rails 4, Puma and Sidekiq?

I am using Sidekiq (on Heroku with Puma) to send emails asynchronously and would like to use Redis to keep counters and cache models.

RedisCloud's free plan includes 30 connections to Redis. It is not clear to me how to manage:

  • redis connections used by Sidekiq
  • redis connections used in models (caching and counters)

Sidekiq Client size is configured like this:

Sidekiq.configure_client do |config|  
  config.redis = {url: ENV["REDISCLOUD_URL"], size: 3}
end

If I understood this correctly, Puma forks multiple processes, 2 in my case, which will result in:

2 (Puma Workers) * 3 (size) * 1 (Web Dyno) = 6 connections to redis used to push jobs.

Sidekiq Server

With Sidekiq taking 2 connections (or 5 in version 4), setting a concurrency of 10 would default in a server size of 12 or 15.

If I wanted to use all the remaining available connections (30 - 6 = 24), I could set :

Sidekiq.configure_client do |config|
  config.redis = { size: 19 }
end

Total redis connections would be 19 + 5 (Sidekiq 4) = 24, and use the default concurrency of 25 would be ok. As Mike Perham stated generally the concurrency must not be more than (server pool size - 2) * 2.

Now, where it starts to get confusing for me is the use of Redis out of Sidekiq.

# initializers/redis.rb

$redis = Redis.new(:url => uri)

Whenever I use Redis in a model or controller I call like so:

$redis.hincrby("mycounter", "key", 1)

As I understand it, all the puma threads wait on each other on a single Redis connection when $redis.whateverFunction is called.

In this answer What is the best way to use Redis in a Multi-threaded Rails environment? (Puma / Sidekiq), the recommended approach is using the connection_pool gem, related to the Sidekiq Wiki https://github.com/mperham/sidekiq/wiki/Advanced-Options#connection-pooling

require 'connection_pool'
$redis = ConnectionPool.new(size: 10) { Redis.new }

If I understand it right, it that case $redis.whateverFunction would have its own connection pool of 10, and sidekiq its own connection workers pool which would now be set out a new total of 20 redis connections ( 30 (available total) - 10 (redis model connections ), and Sidekiq client and server size would need to be changed.

How do you determine the size of the connection pool (here 10) needed for model/controller redis connections? Since Redis is single-threaded, how does increasing the connection pool actually increases redis operations performance?

Any thoughts on this would be of great help. Thx!

like image 825
stefano_cdn Avatar asked Jan 14 '16 17:01

stefano_cdn


1 Answers

Redis is single-threaded, but written in pure C, uses an event loop inside and handles connections asynchronously, so connection count does not affect it by much provided the same number of requests. It is capable of handling requests faster than your application can generate them because of network delay, ruby being slower than compiled and optimized C, etc, so you do not need to worry about it being single-threaded.

Increasing number of connections is beneficial for concurrent requests from different threads because there's no need to wait for response to be delivered over network to unlock connection, plus ruby can do parallel IOs.

Also you can tell if pool is too small when connection checkout times become worse than you expect/tolerate and corresponding thread/worker is idling while waiting for it, so benchmark your code and have a good look on your actual usage and behavior patterns.

On the other side i'd advise against using all of the connection count limit, there're times when you might need these extra connections. For example:

  • for graceful/"zero downtime" dyno restarts ("preboot") you need twice the connections, since old processes are still running for some time
  • keep at least one free connection for emergency debug as you may want to be able to connect from console/directly and see what data is inside when some unexpected highload comes
like image 172
Vasfed Avatar answered Oct 12 '22 12:10

Vasfed