ソフトウェアエンジニアの 9sako6 です。 Ruby でソフトウェアを開発する際、パフォーマンス低下を引き起こすような良くない Redis のクエリが入り込まないよう RuboCop に見張ってもらうようにした話をします。
パフォーマンス低下の実例
私が開発に参加している Web サービスでは、Redis の不適切な使い方がボトルネックとなっていくつかのページのレイテンシーが高まっていました。
主に悪さをしていたのは KEYS
クエリです。
KEYS
クエリの平均処理時間は約 430 ms でした。これが Web ページのレイテンシーに含まれるのはかなり痛いです。
公式ドキュメント (https://redis.io/commands/keys/ )には、はっきりと本番環境での使用に注意するよう書いてあります。
Warning: consider KEYS as a command that should only be used in production environments with extreme care. It may ruin performance when it is executed against large databases. This command is intended for debugging and special operations, such as changing your keyspace layout. Don't use KEYS in your regular application code. If you're looking for a way to find keys in a subset of your keyspace, consider using SCAN or sets.
警告:KEYS は、実稼働環境において細心の注意を払ってのみ使用すべきコマンドであると考えてください。大規模なデータベースに対して実行した場合、パフォーマンスを低下させる可能性があります。このコマンドはデバッグや特殊な操作、例えばキースペースのレイアウトを変更するためのものです。通常のアプリケーションコードでKEYSを使わないでください。もし、鍵空間のサブセットでキーを見つける方法を探しているのであれば、SCANやsetsの使用を検討してください。
(翻訳:DeepL)
コードベースに再び KEYS
クエリが入り込まないよう、対策をしたいです。
レビューをしているとはいえ、開発メンバーは入れ替わりますし、全員が Redis に慣れているとも限らないので、RuboCop に見張ってもらうことにします。
静的解析で検知する
今回の問題を検知するために rubocop-redis を作りました。
Redis クライアントとして redis/redis-rb の使用を想定しています。
現在のところ、KEYS
クエリの使用を検知する Cop とSETEX
クエリの使用を促す Cop の 2 つだけ用意されています。
改善後
パフォーマンスに問題のあった箇所は現在、ボトルネックだった KEYS
クエリを使わない実装に書き換わっています。
KEYS
クエリの平均処理時間約 430 ms が丸々消え去っただけでなく、Redis サーバーの CPU 使用率も約 38% (ピーク時)から約 5%(ピーク時)まで低下しました。
知見を実装に落とし込み、世界と共有できる RuboCop の魅力を感じました。
謝辞
Cop 化のアイデアと実装上のアドバイスをくださった RuboCop core team の koic さんに感謝します。