誕生から13年――Redisには新しいアーキテクチャが必要なのか?
Redisはインメモリデータストアの基盤となる技術であり、だからこそ、代替アーキテクチャが検討されることも少なくありません。数年前にはKeyDBがその話題を提起し、最近では新プロジェクト「Dragonfly」が「最速のRedis互換インメモリデータストア」であると主張しました。こうしたプロジェクトがもたらす興味深い技術やアイデアは、議論する価値があると私たちは考えています。Redis社としても、この種の挑戦は歓迎です。なぜなら、Redisが当初から掲げてきたアーキテクチャ設計原則(Salvatore Sanfilippo氏、通称antirezへの敬意を込めて)を再確認する機会になるからです。
私たちは常にイノベーションの機会を追求し、Redisのパフォーマンスと機能の向上に取り組んでいますが、本記事では、なぜRedisのアーキテクチャが今なおインメモリ・リアルタイムデータストア(キャッシュ、データベース、そしてその中間のすべて)において最高水準であり続けるのか、その視点と考察をお伝えします。
以下のセクションでは、比較で話題となっている速度とアーキテクチャの違いについて私見を述べます。記事の最後では、Dragonflyプロジェクトとのベンチマークおよびパフォーマンス比較の詳細を紹介していますので、皆さん自身でも検証・再現してみることをお勧めします。
速度
Dragonflyのベンチマークは、シングルコアしか利用できない単一プロセスのスタンドアロンRedisインスタンスと、VM/サーバー上の全コアを活用できるマルチスレッドのDragonflyインスタンスを比較したものです。残念ながら、この比較は実環境でのRedisの運用形態を反映していません。技術を提供する者として、自社技術が他社製品とどう比較されるのかを正確に把握したいものです。そこで私たちは公平と思われる比較を行いました。Dragonflyチームがベンチマークに使用した最大のインスタンスタイプAWS c6gn.16xlarge上で、40シャード構成のRedis 7.0クラスタ(インスタンスのコアの大部分を活用可能)とDragonflyを一連のパフォーマンステストで比較しました。その結果、64 vCPUのうち40個しか使用していないにもかかわらず、RedisはDragonflyより18%〜40%高いスループットを達成しました。
アーキテクチャの違い
背景
これらのマルチスレッドプロジェクトの作者たちによるアーキテクチャ判断の多くは、以前の仕事で経験した課題(ペインポイント)に影響されていると私たちは考えています。マルチコアマシン、時には数十コア・数百GBのメモリを搭載したマシン上で単一のRedisプロセスを実行しても、利用可能なリソースを十分に活かせないことは事実です。しかし、それはRedisが想定していた使い方ではなく、多くのRedisプロバイダーがサービス運用のために選択した方式にすぎません。
Redisは、単一クラウドインスタンス内であっても、マルチプロセス(Redis Clusterの利用)によって水平方向にスケールするように設計されています。Redis社はさらにこの概念を発展させ、Redis Enterpriseを構築しました。これは管理レイヤーを提供し、ユーザーが高可用性、即時フェイルオーバー、データ永続化、デフォルト有効のバックアップを備えた形でRedisを大規模に運用できるようにするものです。
ここでは、本番環境でRedisを運用するための優れたエンジニアリングプラクティスとは何かを理解してもらうため、私たちが内部で採用している原則の一部を紹介します。
アーキテクチャの原則
VMあたり複数のRedisインスタンスを実行する
VMあたり複数のRedisインスタンスを実行することで、以下のメリットが得られます。
- 完全なシェアードナッシング(shared-nothing)アーキテクチャにより、垂直・水平の両方向に線形スケールできる。垂直方向にしかスケールできないマルチスレッドアーキテクチャよりも、常に柔軟性が高くなります。
- レプリケーションが複数プロセスで並列に行われるため、レプリケーションの速度が向上します。
- 新しいVMのRedisインスタンスが複数の外部Redisインスタンスから同時にデータを受け取れるため、VM障害からの高速な復旧が可能になります。
各Redisプロセスのサイズを適切な範囲に制限する
私たちは単一のRedisプロセスが25GBを超えて成長しないよう制限しています(Redis on Flash使用時は50GB)。これにより以下のメリットがあります。
- レプリケーション、スナップショット、AOF(Append Only File)書き換えのためにRedisをforkする際、大きなメモリオーバーヘッドを払うことなく、コピーオンライトの恩恵を受けられる。「やらなければ誰かが代償を払う」のは事実です。詳細はこちらをご覧ください。
- 各Redisインスタンスが小さく保たれるため、クラスタ管理、シャード移行、リシャーディング、スケーリング、リバランシングを迅速かつ容易に行えます。
水平スケーリングこそが最重要
インメモリデータストアを水平方向にスケールできる柔軟性は極めて重要です。その理由をいくつか挙げます。
- 優れた耐障害性 ― クラスタのノード数が多いほど、クラスタは頑丈になります。例えば、3ノードクラスタで1ノードが劣化すると、クラスタ全体の1/3が機能しなくなりますが、9ノードクラスタなら影響はわずか1/9です。
- スケールの容易さ ― クラスタにノードを追加し、データセットの一部だけを移行する方が、より大きなノードを用意してデータセット全体をコピーする垂直スケーリングよりもはるかに簡単です(この長いプロセスの途中で起こりうる問題も考えてみてください)。
- 段階的なスケーリングはコスト効率が高い ― 特にクラウドでは垂直スケーリングは高額です。多くの場合、データセットに数GB追加したいだけで、インスタンスサイズを倍増させる必要があります。
- 高スループット ― Redisでは、小規模なデータセットで非常に高いネットワーク帯域幅や高PPS(packets per second)を要求する高スループットワークロードを扱う顧客を多数見てきました。1GBのデータセットで100万ops/sec以上というユースケースを想像してください。これを単一ノードのc6gn.16xlargeクラスタ(128GBメモリ、64 CPU、100Gbps、$2.7684/時)で実行するのではなく、3ノードのc6gn.xlargeクラスタ(各8GB、4CPU、最大25Gbps、$0.1786/時)で、20%未満のコストかつはるかに堅牢な構成で実行する方が合理的ではないでしょうか。コスト効率と耐障害性を維持しながらスループットを上げられるなら、答えは明らかです。
- NUMAの現実 ― 垂直スケーリングは、マルチコアと大容量DRAMを備えた2ソケットサーバーの運用を意味します。このNUMAベースのアーキテクチャは、Redisのようなマルチプロセッシングアーキテクチャにとっては、小さなノードのネットワークのように振る舞うため好都合です。しかしマルチスレッドアーキテクチャにとってNUMAは難しく、他のマルチスレッドプロジェクトでの経験では、NUMAによってインメモリデータストアのパフォーマンスが最大80%低下することがあります。
- ストレージスループットの限界 ― AWS EBSなどの外部ディスクは、メモリやCPUほど速くスケールしません。実際、クラウドサービスプロバイダーはマシンクラスごとにストレージスループットの上限を設けています。したがって、前述の問題を回避し、高度なデータ永続化要件を満たしながらクラスタを効果的にスケールする唯一の方法は、ノードとネットワーク接続ディスクを追加する水平スケーリングです。
- エフェメラルディスク ― エフェメラルディスクは、RedisをSSD上で実行する(DRAMの置き換えとしてSSDを使い、永続ストレージとしては使わない)優れた手段であり、Redisの速度を保ちながらディスクベースデータベースのコストメリットを享受できます(Redis on Flashでの実装方法をご覧ください)。繰り返しますが、エフェメラルディスクが限界に達したとき、クラスタをスケールする最善の、そして多くの場合唯一の方法は、ノードとエフェメラルディスクの追加です。
- 汎用ハードウェア ― 最後に、オンプレミスのデータセンター、プライベートクラウド、さらには小規模なエッジデータセンターで運用している顧客も多くいます。こうした環境では、64GB超のメモリと8CPU以上を搭載したマシンを見つけるのが困難なことがあり、やはりスケールする方法は水平方向しかありません。
まとめ
新しい波であるマルチスレッドプロジェクトがコミュニティにもたらす新鮮で興味深いアイデアや技術には感謝しています。io_uring(すでに調査を開始しています)、より現代的な辞書構造、スレッドのより戦術的な活用など、これらの概念の一部が将来Redisに取り入れられる可能性もあります。しかし、当面の間、Redisが提供するシェアードナッシング・マルチプロセスアーキテクチャという基本原則を放棄する予定はありません。この設計こそが、最良のパフォーマンス、スケーラビリティ、耐障害性を提供し、インメモリ・リアルタイムデータプラットフォームに求められる多様なデプロイメントアーキテクチャを支えているのです。
付録:Redis 7.0 vs Dragonfly ベンチマーク詳細
ベンチマーク概要
バージョン:
- Redis 7.0.0を使用し、ソースからビルドしました。
- Dragonflyは、https://github.com/Dragonfly/dragonfly#building-from-source の推奨に従い、6月3日時点のソース(hash=e806e6ccd8c79e002f721a1a5ecb847bd7a06489)からビルドしました。
目的:
- Dragonflyの結果が再現可能であること、およびその結果が取得された完全な条件を確認すること(memtier_benchmarkやOSバージョンの設定など一部情報が欠落していたため。詳細はこちら)。
- Dragonflyのベンチマーク条件に合わせて、AWS c6gn.16xlargeインスタンス上でOSS Redis 7.0.0クラスタが達成できる最高のパフォーマンスを測定すること。
クライアント設定:
- OSS Redis 7.0のソリューションでは、各memtier_benchmarkスレッドがすべてのシャードに接続するため、Redisクラスタへのオープン接続数をより多く必要としました。
- OSS Redis 7.0のソリューションでは、Dragonflyのベンチマーク条件に合わせるため、同じクライアントVM上で2つのmemtier_benchmarkプロセスを実行した場合に最良の結果が得られました。
リソース使用率と最適構成:
- OSS Redisクラスタは40プライマリシャード構成で最良の結果を達成しました。つまりVMには24個の予備vCPUが残っています。マシンをフル活用していませんでしたが、シャード数を増やしても効果はなく、むしろ全体的なパフォーマンスが低下しました。この挙動については現在調査中です。
- 一方、DragonflyのソリューションはVMの全64 vCPUを使い切り、100%の使用率に達しました。
- 両ソリューションとも、最良の結果を得るためにクライアント設定を調整しました。下記の通り、Dragonflyのデータの大部分を再現でき、pipeline=30の場合にはDragonflyの最高結果さえ上回りました。
- つまり、Redisで達成した数値にはさらに伸びしろがあるということです。
最後に、RedisとDragonflyのどちらもネットワークPPSや帯域幅がボトルネックになっていないことを確認しました。使用した2台のVM(クライアントとサーバー、いずれもc6gn.16xlarge)間で、ペイロード約300BのTCPにおいて10M PPS超、30 Gbps超を達成できることを確認済みです。
結果の分析
- GET pipeline 1(サブミリ秒):
- OSS Redis:4.43M ops/sec。平均値とp50の両方でサブミリ秒レイテンシを達成。平均クライアントレイテンシは0.383 ms。
- Dragonflyの主張:4M ops/sec。
- 私たちは平均クライアントレイテンシ0.390 msで3.8M ops/secを再現しました。
- Redis vs Dragonfly ― Redisのスループットは、Dragonflyの主張値より10%、再現できた結果より18%高い。
- GET pipeline 30:
- OSS Redis:22.9M ops/sec、平均クライアントレイテンシ2.239 ms。
- Dragonflyの主張:15M ops/sec。
- 私たちは平均クライアントレイテンシ3.99 msで15.9M ops/secを再現しました。
- Redis vs Dragonfly ― Redisは(再現結果比で)43%、(主張値比で)52%優れています。
- SET pipeline 1(サブミリ秒):
- OSS Redis:4.74M ops/sec。平均値とp50の両方でサブミリ秒レイテンシを達成。平均クライアントレイテンシは0.391 ms。
- Dragonflyの主張:4M ops/sec。
- 私たちは平均クライアントレイテンシ0.500 msで4M ops/secを再現しました。
- Redis vs Dragonfly ― Redisは19%優れています(Dragonflyの主張と同一の結果を再現)。
- SET pipeline 30:
- OSS Redis:19.85M ops/sec、平均クライアントレイテンシ2.879 ms。
- Dragonflyの主張:10M ops/sec。
- 私たちは平均クライアントレイテンシ4.203 msで14M ops/secを再現しました。
- Redis vs Dragonfly ― Redisは(再現結果比で)42%、(主張値比で)99%優れています。
各ケースで使用したmemtier_benchmarkコマンド:
- GET pipeline 1(サブミリ秒)
- Redis:
- 2X実行:memtier_benchmark –ratio 0:1 -t 24 -c 1 –test-time 180 –distinct-client-seed -d 256 –cluster-mode -s 10.3.1.88 –port 30001 –key-maximum 1000000 –hide-histogram
- Dragonfly:
- memtier_benchmark –ratio 0:1 -t 55 -c 30 -n 200000 –distinct-client-seed -d 256 -s 10.3.1.6 –key-maximum 1000000 –hide-histogram
- Redis:
- GET pipeline 30
- Redis:
- 2X実行:memtier_benchmark –ratio 0:1 -t 24 -c 1 –test-time 180 –distinct-client-seed -d 256 –cluster-mode -s 10.3.1.88 –port 30001 –key-maximum 1000000 –hide-histogram –pipeline 30
- Dragonfly:
- memtier_benchmark –ratio 0:1 -t 55 -c 30 -n 200000 –distinct-client-seed -d 256 -s 10.3.1.6 –key-maximum 1000000 –hide-histogram –pipeline 30
- memtier_benchmark –ratio 0:1 -t 55 -c 30 -n 200000 –distinct-client-seed -d 256 -s 10.3.1.6 –key-maximum 1000000 –hide-histogram –pipeline 30
- Redis:
- SET pipeline 1(サブミリ秒)
- Redis:
- 2X実行:memtier_benchmark –ratio 1:0 -t 24 -c 1 –test-time 180 –distinct-client-seed -d 256 –cluster-mode -s 10.3.1.88 –port 30001 –key-maximum 1000000 –hide-histogram
- Dragonfly:
- memtier_benchmark –ratio 1:0 -t 55 -c 30 -n 200000 –distinct-client-seed -d 256 -s 10.3.1.6 –key-maximum 1000000 –hide-histogram
- memtier_benchmark –ratio 1:0 -t 55 -c 30 -n 200000 –distinct-client-seed -d 256 -s 10.3.1.6 –key-maximum 1000000 –hide-histogram
- Redis:
- SET pipeline 30
- Redis:
- 2X実行:memtier_benchmark –ratio 1:0 -t 24 -c 1 –test-time 180 –distinct-client-seed -d 256 –cluster-mode -s 10.3.1.88 –port 30001 –key-maximum 1000000 –hide-histogram –pipeline 30
- Dragonfly:
- memtier_benchmark –ratio 1:0 -t 55 -c 30 -n 200000 –distinct-client-seed -d 256 -s 10.3.1.6 –key-maximum 1000000 –hide-histogram –pipeline 30
- Redis:
インフラ詳細
クライアント(memtier_benchmark実行用)とサーバー(Redis/Dragonfly実行用)には、両方とも同じVMタイプを使用しました。スペックは以下の通りです。
- VM:
- AWS c6gn.16xlarge
- aarch64
- ARM Neoverse-N1
- ソケットあたりのコア数:64
- コアあたりのスレッド数:1
- NUMAノード数:1
- AWS c6gn.16xlarge
- カーネル:Arm64 Kernel 5.10
- 搭載メモリ:126GB
-
Androidにクリーナーアプリは必要?ストレージ最適化の理由と使い方を徹底解説
Androidデバイスになぜクリーナーアプリが必要なのか、疑問に思っていませんか?この記事では、デバイスにクリーニングアプリを導入することがなぜ重要なのかを詳しくご紹介します。時間が経つにつれて、スマートフォンは動作が遅くなり、ストレージには不要なデータが溜まっていきます。これによりパフォーマンスが低下し、使わなくなったアプリやファイルがストレージを圧迫してしまいます。キャッシュや一時ファイルをこまめに手動で削除するのは現実的ではありませんし、たとえ削除しようとしても、すべてのファイルやキャッシュを見つけ出すのは容易ではありません。そこで役立つのが、Androidのジャンクファイルを自動で整理
-
Motorola Moto G6 - 3年間使い続けてわかったこと
私は自分の仕事の徹底ぶりにそれなりに誇りを持っている。その自己満足の一環として続けているのが、長期ハードウェアレビューシリーズだ。手に入れた機器を使い始め、2年、3年、ときには7年後に、その継続的な使用体験について記事にするというもの。かなり興味深い実験になるが、ある程度の忍耐が必要だ。そして何より、先入観を持って臨んではならない。 通常、この種の記事はノートパソコンが中心だったが、最近ではスマートフォンでも行うようになった。モバイルの世界にはそれほど詳しいわけではないが、まあいい。2019年の初頭、私はMoto G6を入手した。エントリーモデルのスマートフォンで、目的はサブ機としての利用とA