NUMA は、複数の CPU を搭載するシステムにおいて採用されている物理的なメモリ設計です。この設計では、各 CPU が直接アクセスできるメモリ領域(ローカルメモリ)を持つ一方で、他の CPU に接続されたメモリ領域(リモートメモリ)には間接的にしかアクセスできません。本セッションでは、このような設計がとられる理由の具体的な説明はありませんでしたが、CPU とメモリを結ぶバスの共有を制限することで動作クロックを向上させる技術として用いられているようです。
この「直接アクセス可能な CPU とメモリの対」(= NUMA ノード)について実際のコンピューター内部の写真を用いて、各 NUMA ノード間に物理的な距離が存在することを視覚的に説明していました。さらに同じ NUMA ノード内のメモリアクセスと異なるノード間のメモリアクセスでは、ベンチマーク結果で明確なレイテンシー差が見られることが示され、これがクラウド上で動作するアプリケーションのパフォーマンスにも影響を及ぼすと強調されていました。
NUMA は各社クラウドベンダーが採用しているサーバーにも採用されていますが、 NUMA に関するスペックはドキュメントに書かれていないことも少なくありません。例として挙げられていた AWS のインスタンスではドキュメントの記載がなく、実際に起動した後に lscpu コマンドを用いて NUMA ノードの配置について確認する方法が紹介されていました。例えば m5a.12xlarge では3ノード、m7g.16xlarge では1ノードといった具体的な情報が共有されました。NUMA ノードの数は、CPU のアーキテクチャや利用するインスタンスのサイズによって異なるため、利用するインスタンスの選定においても NUMA の特性を意識する必要があることを喚起していました。
何も考慮せずにサービスをデプロイした場合、Pod が複数の NUMA ノードを跨いで配置されてしまいパフォーマンス劣化を招く可能性があります。これを効率よく適切に取り扱うための CPU Manager や Topology Manager といった Kubernetes の機能が紹介され、これらの機能を活用することで NUMA の影響を軽減できることが説明されました。
また、大きいインスタンスを使用すると NUMA ノードも増加する傾向にあるため、NUMA ノードを跨ぐことによるパフォーマンス劣化のリスクが高まります。OS カーネルや kubelet などのオーバーヘッドも考慮しつつ、可能な限り小さいインスタンスの利用を推奨していました。
このセッション全体を通して、普段私たちが利用している AWS のようなクラウド環境でも NUMA のような低レイヤーな技術を意識する必要があるという事実に改めて驚かされました。NUMA という効率良く高速化を行うためのハードウェア設計に触れることで、CPU やメモリの設計技術そのものにも興味が湧きました。また、クラウドを利用しているからといってこれらの技術が完全に抽象化・隠蔽されるわけではなく、むしろパフォーマンスを最大限に引き出すためには、そうした特性を理解し、適切に対処すべきであるという重要な気付きを得られました。実際に Kubernetes で運用する際の具体的な対処法も学ぶことができたため、今後、より効率的にコンピューティングリソースを利用できるプラットフォームを目指して取り組んでいきたいと思います。
まず Pod の可用性に関しては、ノードの起動が遅いという問題に対し、従来の Cluster Autoscaler に代わり Karpenter を導入することで、ノードの起動時間を大幅に短縮し、迅速なスケーリングを実現しました。また、CoreDNS の Pod が頻繁に CPU Throttling を起こしていた問題に対しては、CPU Limit を設定しないという大胆なアプローチを採用し、 CoreDNS の Pod の安定稼働が可能になったとのことでした。
続いてメンテナンスに関しても、多数のアドオンを手動でアップグレードしていたため運用負荷が高いという問題がありました。スモークテストを実施し、正常であれば次のステップへ進み、異常があれば自動でロールバックする仕組みを導入し、アドオンのアップグレードをほぼ自動化することで、運用負荷を大幅に軽減することができました。また、Managed Node Group (MNG) で管理するとノードの再起動が必要となる課題に対しは、Karpenter を導入することで、ロールアウトやアップグレードの自動化と無停止での実行を可能にしました。