Cloudflareは2026年9月18日、キャッシュへのリクエストを振り分ける社内サービス「Pingora Backend Router(PBR)」の改修で、全世界の使用メモリを100TB超減らしたと発表した。8月に報じたDNSキャッシュの再設計とは別の施策で、今回はキャッシュの担当サーバーを決めるハッシュ点数を90%減らし、各点の保存形式も小さくした。偏りを抑えるために増やしていた点が、実は増やしすぎだったという話だ。ただし、振り分け先を変えれば、そこに必要なデータがない場合もある。削減を本番で成立させるには、数式と同じくらい移行の設計が必要だった。
膨らんだのはキャッシュの振り分け表
PBRでメモリを圧迫していたのは、コンシステントハッシュを担うライブラリ「pingora-ketama」のデータ構造だった。一部では6GBに達していたという。8月の「Big Pineapple」がDNS応答の保存方法を見直したのに対し、PBRは、どのサーバーへリクエストを送るかを決める表を縮めた。
コンシステントハッシュは、サーバーが増減しても担当の変更を局所的に抑えられる振り分け方式だ。サーバーとURLなどのキーを数値へ変換し、円環状の範囲へ置く。リクエストの位置から一定方向にたどった先の点を使えば、担当サーバーが決まる。キャッシュ可能なリクエストをURLで同じ場所へ寄せることで、必要なデータを探し当てやすくなる。
ところが、サーバーごとに点を一つ置くだけでは、隣り合う点の間隔に大きな差が出る。広い区間を受け持つサーバーへ仕事が偏るため、実際には一台を多数の点で表し、小さな担当区間を足し合わせる。これが偏りを抑える仕組みである。
Pingoraの従来の基準は、重み1当たり160点だ。Cloudflareはディスク容量に応じた重みを掛け、大容量サーバーへ多くのリクエストを割り当てていた。さらに、法令順守の要件や有効なキャッシュ機能によって使えるサーバーが変わるため、条件の組み合わせごとに別のハッシュリングを持つ。その数は数十に及ぶ。
一台の重みが増えるたび、複数のリングで点が増える。偏りを減らすための余裕が、全サーバーで保持する大きなメモリ負担になっていた。
10万点で得ていた精度はどれほどか
Cloudflareは説明用に、重みを625とした例を挙げている。従来の倍率160を掛けると、一台当たり10万点になる。ただし、これは計算を分かりやすくするための例で、すべての本番サーバーに同じ重みが付いているという意味ではない。
点数と偏りの関係を読む指標が「変動係数」だ。ここでは、サーバーの担当範囲がどれだけ散らばるかを、その期待値に対する比率で表す。最大の偏りを保証する値ではない。
著者が公開した補足解説「Consistent Hashing Proofs」には、同じ重みのサーバーがN台あり、それぞれk点を持つ場合の式がある。
変動係数 = √((N − 1) / (N × k + 1))
ハッシュ点が独立に一様分布する連続空間を仮定した式である。これにN=100を代入すると、点を増やす効果がどの程度かを同じ条件で比べられる。
| 一台当たりの点数k | 担当範囲の変動係数(理論値) |
|---|---|
| 160 | 約7.866% |
| 10000 | 約0.995% |
| 100000 | 約0.315% |
同じ重みの100台を仮定すると、1台当たりのハッシュ点数を1万から10万へ増やしても、担当範囲の変動係数は約0.995%から約0.315%へ下がるだけで、差は約0.680ポイントとなる。
表は2026年9月に公開された著者の式から算出し、百分率の小数第3位へ丸めた。差は丸め前の値で計算している。点数を10倍にしても、改善幅は同じ割合では増えない。この理論値は32ビット空間での衝突を含まず、実際のアクセス数やCPU負荷の測定結果でもない。人気のURLにアクセスが集中したり、リクエストごとの処理量が違ったりする問題は、担当範囲の均等化だけでは解けない。
しかも、実装には理論と異なる上限がある。PBRが使うハッシュ値は32ビットなので、異なる点が同じ数値になる「衝突」が起こる。公開コードも、同じハッシュ値の点を並べ替えた後に重複を除く処理を持つ。生成した点が、すべて独立した区間を増やしてくれるわけではない。
Cloudflareのシミュレーションでは、2048台の構成で一台当たりの点数を1万から10万へ増やす区間に、かえって分布の誤差が増す様子が現れた。同社は理論とシミュレーションを踏まえ、無視できない偏りの増加を招かずに生成点数を90%減らせると判断した。
この結果から「一台1万点が常に最適」とは言えない。補足解説は、重みが異なる場合には全点数と各サーバーの点数を使う別の式を示している。著者自身も、複数点の衝突まで含めた式は導けていないと記す。導入先で必要なのは、台数と重みの分布に照らした評価である。
Rustで1点を8バイトから6バイトへ
もう一つの変更は、ハッシュ点一つの格納幅を8バイトから6バイトへ縮めたことだ。従来は32ビットのハッシュ値と32ビットのサーバー索引を持っていた。PBRが一つのリングで扱うサーバー数なら16ビットの索引で足りる、という判断から索引を小さくした。
ただ、索引の型を小さくするだけでは、通常のRustのメモリ配置で構造体は8バイトのままになる。32ビット値の配置境界をそろえるアラインメントの都合で、余白が入るためだ。新実装はPointV2([u8; 6])という6バイトの配列へ値を詰め、読み出す際に整数へ戻す。これで一つの点を保存する幅は25%減る。
ここで、25%と90%の対象を分けておく必要がある。25%は一つの点の格納幅、90%は生成する点数の削減率だ。どちらもPBR全体の使用メモリがその割合で減ったという数字ではない。Cloudflareが本番の成果として報告した100TB超は、旧リングを撤去した後のPBRの使用量と、数週間前の使用量を比較したものだ。
公開実装には、この変更を使う際の境界も表れている。リンク先のコードでは、新方式は任意のCargo機能v2の下にあり、従来方式のV1が既定のままだ。通常のContinuum::newも従来方式を選ぶ。
新方式を使うには機能を有効にしたうえで、new_with_versionへV2 { point_multiple }を渡し、重み当たりの点数を指定する。ライブラリを更新するだけで、既存の振り分けが一斉に変わる設計ではない。旧方式と新方式を併存させられることが、次の移行を支えている。
振り分け表を替えるだけでキャッシュが冷える
ハッシュリングを作り直すと、同じURLでも別のサーバーが選ばれる。以前の担当にデータが残っていても、新しい担当にはまだないかもしれない。全世界で一斉に切り替えれば、キャッシュミスが重なり、コンテンツの取得元であるオリジンサーバーへの通信が急増するおそれがある。
そこでPBRは一時的に新旧のリングを両方メモリへ置いた。各リクエストにどちらを使うかは既存の移行機構で決め、リクエストのハッシュに対して選択が安定するようにした。異常があれば、PBRを再デプロイせず、旧リングで振り分ける経路へ戻せる。
展開は小規模な検証拠点から始め、より大きなデータセンター群へ順に広げた。その際、新リングへ送るトラフィックの割合と、移行を許す拠点を別々に制御したという。世界全体へ同じ割合を適用するだけでは、あらゆる場所で同時にキャッシュの担当が変わる。拠点を区切れば、影響を限定しながら挙動を確かめられる。
Cloudflareは振り分け先の記録や新旧リングの利用状況に加え、接続エラーも追跡した。使用メモリと起動時間を確認し、キャッシュの挙動やオリジンへの通信量も監視している。移行率が100%になってから不要な旧リングを外し、ようやく大きなメモリ削減が表れた。
つまり、削減したいメモリを移行期間中は余分に持つ必要があった。公開ライブラリは新旧リングを構築する手段を提供するが、Cloudflare社内と同じ拠点別の展開や監視まで自動で備わるわけではない。
他の運用環境で試すなら、点数を減らしたときの担当範囲の偏りと、切り替え時のキャッシュミスを別々に確かめたい。Cloudflareはオリジン流量の許容閾値や、利用者の応答時間が何%改善したかまでは示していない。負荷分散に必要な精度を保ち、データの所在が変わる期間を支えられれば、振り分け表に費やしていたRAMを他の処理へ回せる。



