web-dev-qa-db-ja.com

マルチスレッドRails環境でRedisを使用する最良の方法は何ですか?(Puma / Sidekiq)

私のアプリケーションでは、Sidekiqキューとモデルキャッシングの両方にRedisを使用しています。

RedisにヒットするモデルがWebアプリケーション(Puma経由で実行される)とSidekiq内のバックグラウンドジョブの両方から呼び出されることを考えると、モデルでRedis接続を利用できる最善の方法は何ですか?

私は現在、イニシャライザでこれを行っています:

Redis.current = Redis.new(Host: 'localhost', port: 6379)

そして、単にRedis.current.get/Redis.current.set(および類似)コード全体...

Redisクライアントは、モニターを使用して一度に1つのコマンドしか実行しないため、これは、私が理解している限り、スレッドセーフである必要があります。

現在、SidekiqはRedisへの独自の接続プールを持っています。

Sidekiq.redis do |conn|
   conn.get
   conn.set
end

私が理解しているように、Redisにヒットしたときに単一の接続で互いに待機している複数のスレッドに複数のワーカーがないため、これはRedis.currentを使用するアプローチよりも優れています。

ただし、Sidekiq.redisから取得したこの接続をモデルで使用できるようにするにはどうすればよいですか? (すべてのメソッド呼び出しでパラメーターとして渡す必要はありません)

そのブロック内でRedis.currentを設定することはできません。グローバルなので、同じ接続を使用しているすべてのユーザーに戻ります(さらに、それらをランダムに切り替え、スレッドセーフではない場合もあります)。

Sidekiq.Redisから取得した接続をスレッドローカル変数に格納し、そのスレッドローカル変数をどこでも使用する必要がありますか?

その場合、「プーマ」のコンテキストで何をしますか?スレッドローカル変数を設定するにはどうすればよいですか?

これについての考えは大歓迎です。

ありがとうございました!

30
Daniel Magliola

アプリケーションコードには別のグローバル接続プールを使用します。 redis.rbイニシャライザーに次のようなものを入れます。

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

これで、アプリケーションコードのどこでも、次のことができます。

REDIS.with do |conn|
  # some redis operations
end

Puma/Sidekiqワーカー間で共有する接続は最大10です。あなたが正しく注記しているように、すべてのスレッドが単一のRedis接続を介して戦うことはないため、これによりパフォーマンスが向上します。

このすべてはここに文書化されています: https://github.com/mperham/sidekiq/wiki/Advanced-Options#connection-pooling

39
Mike Perham