SidekiqでRedisを利用する
最終更新 2018/10/20 編集者 Mike Perham
SidekiqはRedisにすべてのデータを保存します。
デフォルトでは、Sidekiqは localhost:6379
でRedisに接続しようとします。この設定は開発中であればうまく機能しますが、本番環境では少し調整が必要です。
環境変数 ENV を利用する
環境変数を使用してRedis URLを設定できます。これにより、Herokuでは非常に簡単にSidekiqの設定を行うことができます。
Redis server URLとして環境変数 REDIS_PROVIDER
を利用してください。そうすれば、Sidekiqはその値を使ってRedisに接続します。
heroku config:set REDIS_PROVIDER=REDISTOGO_URL
また、汎用的な環境変数 REDIS_URL
を利用することもできます。
イニシャライザーを利用する
Sidekiq.configure_server
と Sidekiq.configure_client
の両方を指定する点に注意が必要です。下記のコードを config/initializers/sidekiq.rb
に記載してください。
Sidekiq.configure_server do |config|
config.redis = { url: 'redis://redis.example.com:7372/0' }
end
Sidekiq.configure_client do |config|
config.redis = { url: 'redis://redis.example.com:7372/0' }
end
注意1:記載されたパラメーターはそのままRedisクライアントに渡されます
注意2:パラメーターのキーはシンボルである必要があります。
コネクションの完全な制御
redis-failoverやRedis Sentinel等を利用する場合は、事前にSidekiqへコネクションを渡すことができます。
redis_conn = proc {
Redis.new # do anything you want here
}
Sidekiq.configure_client do |config|
config.redis = ConnectionPool.new(size: 5, &redis_conn)
end
Sidekiq.configure_server do |config|
config.redis = ConnectionPool.new(size: 25, &redis_conn)
end
コネクションプールのサイズに注意してください。各プロセスで実行されるスレッド数に対して十分な接続数を確保する必要があります。コネクションは必要に応じて作成されるため、必要な数が不明な場合はより大きなサイズ(例:20〜30)を指定してもかまいません。Sidekiqサーバーには、少なくとも(concurrency + 5)個のコネクションが必要です。
クラウド環境でSidekiqを利用する
EC2やHerokuなどのクラウドベースシステムでは、予測できないネットワークパフォーマンスが問題を引き起こすことがあります。これらの環境でタイムアウトエラーが発生する場合は、ネットワークタイムアウトを少し緩やかに調整する必要があります。デフォルトは1秒です。
config.redis = { url: 'redis://...', network_timeout: 5 }
重要な注意:このタイムアウトの指定は一時しのぎです。 パフォーマンス劣化の根本的な解決策にはなっていない点にご注意ください。
Redisのタイムアウトエラーが表示される場合は、redis-cli
--latency
または --latency-history
オプションを使用して、Redisのレイテンシを確認する必要があります。
$ redis-cli --latency-history localhost
min: 0, max: 1, avg: 0.20 (1359 samples) -- 15.01 seconds range
min: 0, max: 1, avg: 0.18 (1356 samples) -- 15.01 seconds range
min: 0, max: 1, avg: 0.18 (1355 samples) -- 15.01 seconds range
min: 0, max: 1, avg: 0.17 (1359 samples) -- 15.01 seconds range
min: 0, max: 1, avg: 0.19 (1358 samples) -- 15.00 seconds range
min: 0, max: 1, avg: 0.18 (1353 samples) -- 15.01 seconds range
min: 0, max: 1, avg: 0.19 (1357 samples) -- 15.01 seconds range
上記の結果から、localhostで動くredis-serverへの平均レイテンシは0.2msまたは200マイクロ秒であることが分かります。これは素晴らしい結果です。
ユーザーの環境によっては、5秒を超える遅延が定期的に起きていることがあります。これはひどい結果です。
このようなひどいネットワークパフォーマンス下では、Sidekiqにできることは何もありません。別のRedisプロバイダーに移動するか、専用マシンで独自のRedisサーバーを実行してください。
Redisプロバイダーに連絡して、利用可能な選択肢について尋ねてもよいでしょう。
CLIENTコマンドを無効化する
一部のRedisサーバーでは、セキュリティ上の理由で(意図しないなCLIENT KILLなどを避けるため)すべてのCLIENTコマンドが無効になっています。
この場合、id
オプションを nil
に設定してSidekiqのCLIENT SETNAMEコマンドを無効にすることができます。
config.redis = { url: 'redis://...', id: nil }
アーキテクチャ
Redisではいくつかの異なるトポロジーを利用することができます。
- 単一ノード フォールトトレランスを提供しません
- Redis Sentinel フォールトトレランスを提供し、プライマリ障害が発生した場合にレプリカにフェールオーバーします
- Redis Cluster 多くのインスタンスにまたがるマルチマスターキースペース
クラスターは、キャッシュなど、マシン全体に均等に広がることができる大規模なデータセット用に設計されています。
Sidekiqには、常に変化するいくつかの非常にホットなキー(キューのことです)があるため、Sidekiqにはクラスターは適切ではありません。
Sentinelを使用するか、フェールオーバーのサポートが組み込まれているRedis SaaSを使用することをお勧めします。
チューニング
redis-cli info
コマンドを使用して、Redisに指定可能な設定を確認することができます。
メモリー
Redisは、すべてのデータがメモリに収まるときに最適に動作します。
RedisがSidekiqのデータをサイレントにドロップしないように、redis.confで maxmemory-policy noeviction
を設定する必要があります。
複数のRedisインスタンス
多くの人がRedisをキャッシュとして使用しますが(Railsのキャッシュストアとしてはうまく機能します)、Sidekiqをキャッシュとしてではなく永続ストアとして設定されているRedisインスタンスで実行することが重要です。
キャッシュとSidekiqの両方にRedisを使用する場合は、それぞれの用途に対して適切に構成された2つの異なるRedisインスタンスを使用することをお勧めします。
Redisの名前空間ではこの設定をすることができず、他の多くの問題も伴うため、個別のRedisインスタンスを使用した方がよいでしょう。
タイムアウト
Redisがネットワークタイムアウトするもっとも多い理由は下記の通りです。
- スワッピング RAMが不足していると、ディスクスワッピングが大きなレイテンシスパイクを引き起こします。 Redisを使用してキャッシュデータを保持するには大量のRAMが必要になる可能性があるため、必要に応じてSidekiqを別のRedisインスタンスを使用するように構成してください。
- コマンドの待ち時間 Redisコマンドによっては実行に非常に時間がかかります。後述するモニタリングに関するブログを読んでみてください。
ノート
-
redis-cli --help
を見てください。--latency-history
や--bigkeys
など、いくつかの便利なオプションが表示されるでしょう。 - redis-rdb-toolsには、ダンプされたRDBファイルを調査するためのいくつかのオプションがあります。
- Monitoring Redisでは、Redisを使用するときに監視する必要がある最も重要な事項を扱います。
- Datadogには、Redisの内部と監視に関する素晴らしいホワイトペーパーがあります。
- BRPOPLPUSHおよびその他のB*コマンドは ブロッキング です。 それらのコマンドによる大きなレイテンシスパイクは 正常 であり、特に問題はありません。