こんにちは。ABEMA 開発本部バックエンドチームで2ヶ月間、内定者バイトをしていた2024卒内定者の石上敬祐(@kei01234kei)です。

本記事では、私が内定者バイトのタスクの中で Redis リソースをチューニングし、あるワークロードの Redis コストを3割削減した話をご紹介します。

目次

  1. タスク背景
  2. スレッド数とスループットの関係
  3. Redis インスタンス台数と CCU(同時接続ユーザ数)の関係
  4. 参考: Memorystore for Redis のリソース設計における注意点
  5. まとめ
  6. 最後に

タスク背景

ABEMA では Redis のマネージドサービスとして、Google Cloud の Memorystore for Redis を使用しています。

Memorystore for Redis ではインスタンス1台当たりのメモリ容量が増える(正確には容量ティアが上がる)につれて、メモリ 1GB あたりの料金が安くなります。ABEMA のワークロードではコンシステントハッシュを用いた負荷分散手法を採用しており、インスタンス1台あたりのメモリ容量を増やし、代わりに台数を減らすことでコストを削減できる見込みがありました。

Memorystore for Redis の料金

Memorystore for Redis の料金

https://cloud.google.com/memorystore/docs/redis/pricing

しかし、Redis インスタンスの台数を減らす際に調査しないといけないことがありました。「Redis インスタンスの CPU 使用率がどれほど増加するか」についてです。

例えば Redis インスタンス台数を24台から6台に減らす場合、1台のインスタンスが捌かないといけない処理の量は4倍になり、単純計算で CPU 使用率も4倍になることが予想できるからです。 リクエスト数とインスタンス数の関係

スレッド数とスループットの関係

下の「容量ティアとスレッド数の関係」の表からも分かるように、容量ティアが M2 のスレッド数は1ですが、M3 のスレッド数は2、M4 のスレッド数は6と、容量ティアが上がるとスレッド数が増えます。しかし、大事なのは 「スレッド数が増えることによりスループットがどれほど増えるのか」です。では、実際にどの程度スループットが増えたのでしょうか。

容量ティアとスレッド数の関係 容量ティアとスレッド数の関係

https://cloud.google.com/memorystore/docs/redis/memorystore-for-redis-overview

そこで、M2、M3、M4容量ティアを対象に hset コマンドのスループットを redis-benchmark-go を使い計測、比較しました。

※ 本ワークロードでは hset コマンドが CPU に対して大きな負荷となっていたため、hset コマンドのスループットのみ計測しました。

M2 ティア

./redis-benchmark-go -h 10.0.224.3 -p 6379 -c 1024 -l hset __key__ f1 __data__
#################################################
Total Duration 501.991 Seconds
Total Errors 0
Throughput summary: 68877 requests per second
                    0 CSC Hits per second
                    0 CSC Evicts per second
Latency summary (msec):
          avg       p50       p95       p99
       14.859    14.455    17.503    28.719

M2 ティア、つまりスレッド数が1の Redis インスタンスにおける hset コマンドのスループットは 68,877 rps でした。

M3 ティア

./redis-benchmark-go -h 10.0.224.3 -p 6379 -c 1024 -l hset __key__ f1 __data__
#################################################
Total Duration 501.431 Seconds
Total Errors 0
Throughput summary: 113889 requests per second
                    0 CSC Hits per second
                    0 CSC Evicts per second
Latency summary (msec):
          avg       p50       p95       p99
        8.877     8.759    10.855    14.383

M3 ティア、つまりスレッド数が2の Redis インスタンスにおける hset コマンドのスループットは 113,889 rps でした。

M4 ティア

./redis-benchmark-go -h 10.0.224.3 -p 6379 -c 1024 -l hset __key__ f1 __data__
#################################################
Total Duration 501.368 Seconds
Total Errors 0
Throughput summary: 161774 requests per second
                    0 CSC Hits per second
                    0 CSC Evicts per second
Latency summary (msec):
          avg       p50       p95       p99
        6.021     6.143     7.551     8.399

M4 ティア、つまりスレッド数が6の Redis インスタンスにおける hset コマンドのスループットは 161,774 rps でした。

結果

hset コマンドにおいて、M2 ティアから M3 ティア、つまりスレッド数が1から2になることでスループットが 1.65倍 に、M2 ティアから M4 ティア、つまりスレッド数が1から6になることでスループットが 2.35倍 になることが今回の調査で分かりました。

Redis インスタンス台数と CCU(同時接続ユーザ数)の関係

例えば Redis インスタンス台数を24台から6台に減らす場合、1台のインスタンスが捌かないといけない処理の量は4倍になります。しかし、Redis インスタンスのスレッド数が1から6に増えるとスループットが2.35倍になり、実質的な CPU への負荷の増加は 4 / 2.35 = 1.7倍 になります。

Redis インスタンスのスレッド数を1から6に増やすとスループットが増加し、インスタンス台数を 1/4 にしても CPU への負荷の増加を1.7倍に抑えられることがわかりました。次に考えないといけないのは Redis インスタンスの台数です。課金額はインスタンスの台数とインスタンスの実行時間によって決まるからです。

そこで、CCU(同時接続ユーザ数)と Redis インスタンス台数の関係を調査します。

下図左側の場合、ある CCU の時点でメモリバウンドとなっていたものが、CPU バウンドになるような場合、インスタンス台数の算出に CPU とメモリの2つのリソースを考慮する必要があります。

しかし、下図右側の場合、CCU が増加しても一貫してメモリバウンドの負荷になっています。この場合、インスタンス台数の算出に必要なリソースはメモリリソースの1つだけになり、CCU ごとに必要な Redis インスタンス台数を簡単に求めることができます。 CPUバウンドとメモリバウンドのグラフ

ABEMA のワークロードでは、一貫してメモリバウンドの負荷となっており 、CCU ごとに必要な Redis インスタンス台数を簡単に求めることができました。

実際に求めた CCU と Redis インスタンス台数の関係は次のようなグラフになりました。 x 軸が CCU、y 軸がインスタンス台数です。 CCU と Redis インスタンス台数のグラフ

このグラフに沿って Redis インスタンス全体のメモリ容量はそのままに、1台当たりのメモリ容量を増やすことで、3割のコスト削減に成功しました。

参考: Memorystore for Redis のリソース設計における注意点

今回のタスクの中で学んだことですが、Memorystore for Redis のリソース設計では次の2点に注意する必要があります。

  • CPU 使用率はプライマリノードでは90%、レプリカノードでは50%に抑えないといけない

https://cloud.google.com/memorystore/docs/redis/general-best-practices#cpu_usage_best_practices

  • メンテナンス時にはメモリ使用率を50%に抑えないといけない

「メンテナンス更新時のシステムメモリ使用率は50%以下でなければなりません。」と公式ドキュメントには書いてあります。そのため、メンテナンス時にはインスタンスをスケールアップするか、そもそもメモリ使用率を50%以下に抑える想定でリソース設計をする必要があります。 https://cloud.google.com/memorystore/docs/redis/memory-management-best-practices#system_memory_usage_ratio

まとめ

Redis インスタンスのスレッド数が増えることでスループットが増えることを確認し、インスタンス数の減少による CPU への負荷の増加が許容範囲内であることも確認できました。これにより、Redis インスタンス1台あたりのメモリ容量を増やし、メモリ1GBあたりの単価を下げ、3割のコスト削減に成功しました。

最後に

ABEMA のバックエンドチームの皆さんをはじめ、私のメンターを務めてくださり、頻繁に壁打ちをしてくださった 坂田 淳樹 さん、タスクの中でたくさんの議論をし、洞察の機会を与えてくださった 江頭 宏亮 さん、そして unit1 のみなさんにはとても感謝をしています。ありがとうございました。今後も内定者バイトを通じて更なるスキルアップを目指して全力で頑張りたいと思います。

ABEMA のバックエンドチームの皆さん、2ヶ月間本当にありがとうございました!!