Prefix DelegationによりAWS内のAPIコールは軒並み減少
あるEC2インスタンスでは最大4つのENI(Elastic Network Interface:仮想ネットワークカードを表すVPC内の論理ネットワーキングコンポーネント)を持つことができ、各ENIの下には15個のIPv4アドレスを割り当てられる。minimum allocationが32に設定されている場合、Ciliumはノードのブートストラップ時に32個のPod用IPを事前割り当てする必要がある。
Prefix Delegation(以下、PD)がない場合、各ENI上のプライマリIPはAWSに予約されているためPodに割り当てられるセカンダリIPは14個にとどまり、目標を満たすには3つのENIが必要になる。一方で、PDを使えば、個々のセカンダリIPをアタッチする代わりに16個のIPを含む「/28」のprefixをENIにアタッチできるため、2つの/28プレフィックスを持つ単一のENIだけでminimum allocation=32という要件を満たせる。
ENIの作成・アタッチ・セカンダリIPの割り当てはそれぞれEC2 APIコールを必要とするため、PDは同じIPの目標に到達するために必要なEC2 APIコールの数を大幅に削減し、APIのスロットリングを減らしてノードの起動時間を改善する。
ただし、トレードオフの関係も存在する。prefixは連続したIPブロックを必要とするため、PDはIPの断片化を引き起こしうる。AWSはこの問題を緩和する仕組みを備えており、特定のサブネット配下のCIDR(ネットワークを柔軟に分割し、IPアドレスの範囲やブロックを指定する仕組み)をprefix専用として予約できる。予約されたCIDRからは単一のIP(ノードIPなど)を個別に割り当てることができなくなり、これによって断片化の懸念が緩和される。
ノードのブートストラップ中に実際に行われるEC2 APIコールは、新しいノードの検知時にENI状態を取得する「DescribeNetworkInterfaces」、prefixをアタッチする「AssignPrivateIpAddresses」、ローカルキャッシュを更新するための再度の「DescribeNetworkInterfaces」という3ステップだ。
ENIを作成するCreateNetworkInterfaceの呼び出しがないのは、最初のENIがEC2ノード作成時にAWSによって作成・アタッチされるためだ。EC2のmutating APIコールは読み取り専用APIより低いクォータ(秒間5リクエスト、バースト容量50リクエスト)に制限されており、単一のAWSアカウントではデフォルトで秒間5ノードの作成、短いバーストで最大50ノードまでしかスロットリングなしに対応できない計算になる。
ページネーションを伴うDescribe APIコールも、各リクエストがレート制限にカウントされるためスロットリング(受け付けるリクエスト数などに上限を設け、過剰なアクセスを一時的に制限・拒否する流量制御の仕組み)の一因になりうる。
実際の比較データでも効果は裏付けられた。DescribeNetworkInterfacesは1757回から1051回(40.2%減)、CreateNetworkInterfaceは1002回から52回(94.8%減)、AttachNetworkInterfaceは949回から54回(94.3%減)、ModifyNetworkInterfaceは900回から54回(94.0%減)と軒並み減少し、合計では4909回から1811回、63.1%の削減となった。
興味深いことに、AssignPrivateIpAddressesの呼び出しだけはPD使用時の方が301回から600回へと増えている。PDなしではCreateNetworkInterfaceの呼び出し自体がセカンダリIPを自動的に割り当ててアタッチするのに対し、PDでは1つのENIに複数のprefixをアタッチするためにAssignPrivateIpAddressesを都度呼ぶ必要があるためだ。
それでも他のmutating APIの呼び出し数と比べれば少なく、「AWSサポートはCreateNetworkInterfaceの制限よりAssignPrivateIpAddressesの制限を緩和することに前向きだ」とYifei Sun氏は付け加える。
移行の過程では、VPCによるDescribe APIコールのフィルタリング、冗長なDescribe API呼び出しの排除、DescribeNetworkInterfacesのページネーション最適化など、Cilium OSSコミュニティ側の改善も大きな助けになった。
本番のSparkクラスタでは、PDを有効にした上でminimum allocationとpre-allocationを増やし、EC2 APIのQPS制限・バースト制限をチューニングすることで、秒間約5ノードの安定したプロビジョニングと約8ノードのバースト対応を実現している。
