Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Achieving TB-Level Aggregate Bandwidth: How JuiceFS Optimized Distributed Cache Network

2025年09月22日に「Dev.to」が公開したITニュース「Achieving TB-Level Aggregate Bandwidth: How JuiceFS Optimized Distributed Cache Network」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

データ増加で分散キャッシュのネットワークがボトルネックになる中、JuiceFSはGolangの多重化やゼロコピー技術などで通信を最適化。CPU負荷を大幅に減らし、1.2TB/sの高速データアクセスを実現、大規模システムを安定稼働させる。

ITニュース解説

現代社会では、AIモデルの進化や様々なデジタルサービスの普及により、扱うデータ量が爆発的に増加している。これに伴い、複数のプログラムやユーザーが同じデータに頻繁にアクセスする状況が当たり前になった。このような状況で、システム全体の処理速度が低下しないようにするために、「分散キャッシュ」という技術が非常に重要な役割を果たす。分散キャッシュは、ネットワーク上の複数のサーバー(ノードと呼ぶ)にあるローカルな一時保存領域(キャッシュ)を一つにまとめ、まるで巨大な一つのキャッシュのように利用できるようにするものだ。これにより、データが必要な時に遠く離れたストレージから直接読み出すのではなく、より近くのキャッシュから高速に取得できるようになるため、データ読み込みの待ち時間が大幅に減り、全体的なシステム性能が向上する。

しかし、分散キャッシュの性能は、ノード間でデータをやり取りするネットワークの性能に大きく左右されるという課題がある。例えば、ネットワークのデータ転送能力(帯域幅)が不足していると、データがノード間を移動する速度が制限されてしまう。また、データがノード間を移動するのにかかる時間(ネットワーク遅延)が大きいと、せっかくキャッシュがあっても、その恩恵を十分に受けられない可能性がある。さらに、ネットワークを介したデータの送受信処理には、サーバーの計算資源(CPU)が消費されるため、このCPUの使用率が高くなりすぎると、システム全体の処理能力を制限するボトルネックとなってしまう。

このような課題に対応するため、JuiceFS Enterprise Editionの最新バージョン5.2では、分散キャッシュノード間のネットワーク通信に関して、複数の重要な最適化が導入された。この最適化の結果、システムの性能が劇的に向上し、特にクライアント側のCPU使用率は最適化前と比べて半分以下に削減され、キャッシュノード側のCPU使用率も3分の1まで低下した。これにより、システム全体のデータ読み取り能力は、合計で毎秒1.2テラバイト(TB/s)という非常に高い帯域幅を達成し、これは一般的なTCP/IPネットワークの物理的な限界に近い性能を示すものだ。この成果は、Google Cloud Platform(GCP)上で100台のサーバーがそれぞれ100ギガビット/秒(Gbps)のネットワークカードを使って構成された分散キャッシュクラスターで確認された。現状では最も普及しているTCP/IPプロトコルを最大限に活用しているが、将来的にはさらに高速な200Gbpsや400Gbpsのネットワークカードの性能を最大限に引き出すために、RDMA(Remote Direct Memory Access)のようなさらに高度な技術の導入も検討されている。

今回の最適化では、主にGolangというプログラミング言語で実装されたネットワーク処理の性能改善に焦点が当てられた。大規模なシステム環境では、何千ものクライアントが100台以上の分散キャッシュノードにアクセスすることがあり、これによりネットワーク接続の数が非常に多くなる。このような状況では、Golangのプログラムがネットワーク接続を管理・処理するための負荷(スケジューリングオーバーヘッド)が増大し、結果としてネットワーク帯域幅を効率的に使いきれないという問題が発生していた。

この問題を解決するために、JuiceFSでは「多重化」と「受信ウォーターマークの設定」という二つの主要な改善が施された。多重化とは、一つのネットワーク接続(TCPコネクション)の上で、複数のデータ要求を同時に送受信できるようにする技術のことだ。もし一つの接続で一つの要求しか処理できないと、同時に多くの要求を処理するためには、その分だけたくさんの接続を確立する必要がある。しかし多重化を用いることで、少ない接続数でより多くのデータを並行して処理できるようになり、システム全体の同時処理能力が向上し、サーバーが消費する資源やネットワークへの負担も軽減される。さらに、JuiceFSの多重化は、ネットワークのデータ転送量(トラフィック)に応じて、接続の数を自動的に増やしたり減らしたりする機能も備えている。これにより、要求が多い時には接続数を増やして帯域幅を最大限に利用し、要求が少ない時には接続数を減らして無駄な資源の消費やデータパケットの細分化(フラグメンテーション)を防ぐ。多重化のもう一つの利点は、小さなたくさんのデータパケットを一つにまとめて送る「小パケット結合」が可能になることだ。これにより、ネットワークを介した送受信の回数を減らし、さらにオペレーティングシステム(OS)がアプリケーションとネットワークカードの間でデータをやり取りする際の処理(システムコールやカーネル空間とユーザー空間の切り替え)のオーバーヘッドも削減される。具体的には、データを送る側では、複数の要求データを集めて合計4KBになるか、他に送るデータがなくなるまで待ってからまとめて送信し、受け取る側では、ネットワークカードから大量のデータを一括で読み込み、それを必要な分だけアプリケーションに渡すことで、効率的なデータ処理を実現している。

次に「受信ウォーターマーク設定」について説明する。Golangのネットワークフレームワークでは、OSの機能であるepollの「エッジトリガーモード」という方法でネットワーク接続の状態変化を監視するのが一般的だ。このモードでは、ソケット(ネットワーク接続の窓口)の状態が変わるたびに(例えば、データが到着した時など)OSがアプリケーションに通知するイベントが発生する。しかし、ごく少量のデータが頻繁に届くような状況では、このイベントが繰り返し発生し、CPUがその処理に多くの時間を費やしてしまうことがあった。そこで、ソケットの受信バッファに一定量のデータ(例えば512KB)が蓄積されるまでイベントを発生させない「SO_RCVLOWAT」という設定を導入した。これにより、OSからアプリケーションへの不要な通知の頻度を大幅に減らし、結果としてネットワークI/O処理に伴うCPUの負担を軽減することに成功した。実際、この設定を導入した後のテストでは、高負荷環境でのイベント発生数が以前の10分の1まで減少し、CPUのオーバーヘッドも大幅に改善されたことが確認されている。

さらに重要な最適化として、「ゼロコピー」技術が導入された。Linuxのネットワーク通信において、ゼロコピーとは、OSの内部(カーネル空間)とアプリケーションの領域(ユーザー空間)の間でデータが不要にコピーされることを防ぎ、CPUとメモリの消費を削減し、データ転送効率を向上させる技術のことだ。これは特に、大容量のデータを転送する際に非常に効果を発揮する。JuiceFSでは、主に「sendfile」と「splice」という二つのシステムコールを状況に応じて使い分けている。sendfileは、ファイルの内容をディスクから直接OSのバッファに読み込み、そこからネットワークソケットのバッファへ、アプリケーションのメモリ空間を経由せずに転送する仕組みだ。これにより、アプリケーションがデータを読み込み、再びOSに渡すという二重のコピー作業が不要になる。一方、spliceはさらに柔軟な機能で、OS内部でデータが移動できるため、ファイルからパイプ(一時的なデータの通り道)へ、そしてそのパイプからネットワークソケットへと、データが常にOSの内部空間に留まったまま転送される。これにより、データの実体がCPUによってコピーされることなく、単にデータの位置を示すポインタが操作されるだけで転送が完了するため、非常に高速かつ低負荷なデータ転送が実現される。例えば、クライアントがキャッシュノードにファイルデータを要求した場合、JuiceFSではsplice技術を使って、キャッシュデータをファイルからOSの内部バッファに読み込み、それをパイプを介してネットワークソケットバッファへと直接転送する。この一連の流れでは、データがアプリケーションのメモリ空間にコピーされることはなく、OSの内部だけで処理が完結するため、CPUによるデータコピーがゼロとなり、効率的なキャッシュサービスが提供される。

データの正確性と整合性を保証するために行われる「CRC(巡回冗長検査)」のプロセスも最適化された。以前のバージョンでは、分散キャッシュからデータブロックを読み出す際、ディスクからメモリへデータを読み込む時と、ネットワークでデータを送信する時の二回、CRCチェックが行われていた。これはデータの破損を二重にチェックする意味では安全だが、毎回計算を行うためCPUに余計な負担をかけていた。新しいバージョンでは、このCRCチェックのプロセスが見直された。送信側では、ディスクに保存されているCRC値をそのまま活用し、それを必要なデータブロック全体のCRC値として効率的に結合してネットワークパケットのヘッダに書き込む。受け取る側では、一度だけCRC計算を行い、送信側から送られてきたCRC値と比較する。これにより、CRC計算の回数を減らしつつ、データが途中で破損したり改ざんされたりしていないことを確実に保証できるため、CPUの消費を効果的に削減し、システム全体の性能向上に貢献している。

このように、データ量の爆発的な増加と高負荷なアクセスが常態化する現代において、分散キャッシュはコンピューティングとストレージをつなぐ重要な中間層としてその価値を増している。JuiceFSは、GolangのI/O処理メカニズムを深く掘り下げ、多重化による接続効率の向上、受信ウォーターマーク設定によるCPU負荷の軽減、ゼロコピー技術によるデータ転送の高速化、そしてCRCチェックプロセスの最適化といった多岐にわたる技術を組み合わせることで、高負荷な環境下でも安定して高速に動作する大規模分散キャッシュシステムを実現した。これらの実践的な経験は、同様の性能課題に直面している他のシステム開発者にとっても、貴重な知見となるだろう。

関連コンテンツ

関連IT用語