Cloudflare が、自社の DNS サービス群を支える内部基盤「Big Pineapple」で、キャッシュの持ち方を見直し、大きなメモリ削減を実現したと明かした。対象は 1.1.1.1 をはじめ、Gateway DNS、DNS Firewall、AS112 など、同社のDNS関連サービスを裏で支える仕組みだ。単なる省メモリの話ではなく、同時に処理速度も上がった点が面白い。サーバーを増やす話ではなく、既存の設計を細かく磨くだけでここまで変わる、というところにこの話の価値がある。
Cloudflare によると、Big Pineapple は任意の時点で 2500億件を超える DNS キャッシュエントリを保持している。DNS キャッシュは、過去に調べた名前解決の結果を覚えておき、次回以降の応答を速くする仕組みだ。Big Pineapple では、キャッシュが空の状態から始まり、DNS クエリが来るたびに項目が増えていく。上限に達したら、古いものや人気のないものから追い出していく。
ここで重要なのは、1件あたりの無駄が全体では巨大なコストになることだ。Cloudflare は「1エントリで 1 バイト無駄にすると、全体では 250GB 以上のメモリ損失になる」と説明している。しかも EDNS Client Subnet(ECS)を使う環境では、同じ名前でもクライアントのネットワークごとに答えが変わるため、キャッシュの件数もメモリ使用量も増える。ECS が多い拠点ほど、この最適化の効き目は大きい。
記事では、キャッシュが key-value pair として実装されていることも示している。key 側の CacheKey には、問い合わせ名 qname、種別 qtype、認証済みかどうかの authenticated、それに tag が入る。value 側の CacheEntry には、生成時刻、参照回数、TTL に加えて、answer / authority / additional の各 record、さらに error 情報などが入る。つまり単純なメモ欄ではなく、DNS 応答そのものをかなり厚く持っている。
Cloudflare はこの構造を Rust レベルで五段階にわたって見直した。その結果、1件あたりのメモリ使用量を 56% 削減できたという。さらに、要素の確保のしかたが効率化され、メモリアロケーションの回数が減り、局所性も良くなった。その結果、キャッシュへの挿入スループットは 43% 向上し、検索レイテンシは 19% 改善した。つまり、より小さくしたのに遅くならなかったどころか、むしろ速くなった。
削減できた総量は、およそ 100TB だ。Cloudflare はこれを、自社の Gen 13 サーバー 130 台分の RAM に相当すると説明している。こうした数字を見ると、キャッシュ最適化は地味に見えても、巨大な分散システムでは立派なインフラ投資の代わりになるのだと分かる。新しい機能を足すのではなく、既にあるものを削る。しかもサービスの体感を損なわない。そこがこの取り組みの核心だと思う。
この話でいちばん印象に残るのは、Cloudflare が盛っているわけではなく、むしろ逆に「1バイト単位の無駄」を真正面から扱っている点だ。普通はメモリ最適化というと、何か極端に特殊なケースを想像しがちだが、ここでは 2500億件という規模の前では、ほとんど何でも効いてしまう。1件あたり数バイトの削減が、全体で数十TB、100TB 級になる。巨大事業の最適化が、局所的には細かい工夫の積み重ねでしかないことがよく分かる。
同時に、こうした最適化は「節約できて偉い」で終わらない。メモリ使用量を減らすことは、サーバー台数の圧縮だけでなく、障害耐性や運用の自由度にも効くはずだと思う。余裕があれば、急なトラフィック増にも構えやすいし、データセンターごとに違うキャッシュ上限の調整もしやすくなる。しかも今回は遅くなるどころか速くなった。最適化が性能低下の代償ではなく、性能改善そのものになっているのが重要だ。ここは「コスト削減の小技」ではなく、設計品質の更新として見るべきだと思う。
ECS の説明が入っていたのも興味深い。DNS は本来、同じ名前に対して同じ答えを返すイメージが強いが、ECS が有効だと、ユーザーのネットワーク位置によって返答が変わる。そのためキャッシュは単純な「1問1答」では済まず、同じ問い合わせでも複数パターンを抱えることになる。Cloudflare が ECS-heavy な拠点で特に効果が大きいと書いているのは、ここが理由だ。
これは、キャッシュ最適化が単なるデータ構造の話ではなく、ネットワークの性質そのものに引きずられることを示している。CDN や DNS の世界では、正しさのために複数の答えを保持する必要がある場面がある。だからこそ、保持の仕方が重いとすぐに膨らむ。見た目は同じ「キャッシュ」でも、裏では地域差や応答差を丸ごと抱えているわけで、ここを軽くできるかどうかが実運用の差になる。DNS の世界が静的な辞書ではなく、かなり動的な仕組みだとあらためて感じる。
記事は「Rust-level memory optimizations」と言っているが、ここで大事なのは Rust だから自動的に速い、という話ではないことだと思う。むしろ、型の持ち方、所有のさせ方、アロケーションの回数、メモリ配置の密度といった、かなり実装寄りの工夫が効いている。安全な言語を使っていても、設計が雑ならメモリは食うし、遅くもなる。逆に言えば、Rust は細部を詰めたときにその効果が見えやすい土台でもある。
この点は、インフラ開発の評価軸にもつながる。クラウドのような巨大な基盤では、新機能の派手さより、無数の小さな改善の総和が競争力になる。外からは見えにくいが、100TB の削減と 43% / 19% の改善が同時に出るなら、内部ではかなり真面目に設計を見直したはずだ。こうした仕事は報われにくいが、会社のスケールが大きいほど効果も大きい。Cloudflare の記事は、その地味さと破壊力の両方をきれいに示していると思う。
参考: How we saved 100 terabytes of memory by optimizing 1.1.1.1’s DNS cache