NUMA 環境下でのバッファ プールの拡張と縮小

このトピックでは、NUMA (non-uniform memory access) を使用した場合に、バッファ プールのメモリ ページがどのように割り当てられるかについて説明します。この情報は、SQL Server が NUMA を使用する方法と、バッファ ノード オブジェクトのカウンタを解釈する方法を理解するのに役立ちます。

メモリの配分

物理的な NUMA ノードには、それぞれ 1 つの SQL Server メモリ ノードがあります。メモリ ノードは互いに独立して拡大しますが、メモリを均等に分割します。SQL Server でのローカル メモリと外部メモリの配分を示すために、このトピックでは 16 GB のメモリが搭載されているコンピュータを例として使用します。Windows を含むその他のアプリケーションが各ノードのメモリの一部を消費し、SQL Server がバッファ プール以外のプロセス用にメモリの一部を割り当て、バッファ プール用には 10 GB のメモリが残っています。バッファ プール メモリは 4 つの物理 NUMA ノード、N0、N1、N2、N3 の間で分割されます。それぞれのノードには以下のローカル メモリが搭載されています。

  • N0 – 1 GB

  • N1 – 3 GB

  • N2 – 3 GB

  • N3 – 3 GB

上記の構成では、すべてのノードで最終的に 2.5 GB のメモリが割り当てられますが、ノード N0 にはこのノード自体のメモリ 1.0 GB と他のノードのメモリ 1.5 GB が割り当てられることになります。

起動時のメモリ割り当て

NUMA を使用すると、初期の空きメモリがノード間に均一に配分されていない場合でも、SQL Server には非 NUMA システムと同等の割合でオペレーティング システムからメモリを割り当てられます。バッファ プールは、各ノード用にできるだけ多くのローカル メモリを取得しようとしますが、現在の Windows には特定のノードからメモリを割り当てるための API がないため、これは困難です。

SQL Server にメモリが割り当てられる際、一部のノードには他の NUMA ノードのページ (外部ページと呼びます) が多数割り当てられることがあります。しかし、これらのページは、所有元のノードに頻繁に委譲されてそのノードのローカル メモリになるため、割り当て増加の際には使用されません。max server memory の値に達したとき、一部のノードで外部メモリが使用されている可能性がありますが、いったんメモリ ターゲットに達すると、バッファ プールではローカル メモリも外部メモリも同じように扱われます。たとえば、メモリが不足している状況でも、ローカル メモリ ページを解放する前に外部メモリ ページを解放するようなことはありません。

特定ノードへのメモリの制限

使用可能な NUMA ノードのサブセットで動作するように SQL Server が構成されていても、バッファ プールがそれらのノード上のメモリだけを使用するように自動的に制限されることはありません。このような場合には、max server memory オプションを使用してバッファ プールを制限します。max server memory の詳細については、「サーバー メモリ オプション」を参照してください。

ノードからのメモリの解放

NUMA を使用する場合、max server memorymin server memory の値は、各 NUMA ノード間で均等に分割されます。たとえば、4 つのノードがあるシステムで max server memory を 16 GB に設定すると、バッファ プールは各ノードに 4 GB のメモリを割り当てます。affinity mask の設定を変更してノードの 1 つをオフラインにすると、max server memory の設定が残りのノード間で再配分されます。たとえば、上記の 4 つのノードの例で 2 つのノードをオフラインにすると、解放された 8 GB のメモリは残りのノード間で均等に配分されます。バッファ プールは外部ページを使用できるため、残っているノード上に十分なメモリがないと、リモート メモリが使用されます。動作していないノードのメモリを SQL Server で使用しないようにするには、ノードをオフラインにした後で max server memory の設定を減らす必要があります。

外部ページ

ノードは互いにほぼ独立して機能します。ノードのすべてのメモリ割り当てと割り当て解除は、そのノードに関連付けられているメモリを使用して行われます。しかし、ノード N1 上で実行しているワーカーが既にノード N2 のメモリ上にあるデータベース ページにアクセスする必要がある場合は、ローカルでないメモリにアクセスします。

バッファ プール内のローカル メモリと外部メモリの監視

バッファ プールは、Buffer Node オブジェクトを参照することで監視できます。SQL Server 用のバッファ プール内の合計メモリは、Buffer Manager オブジェクトの Target pages カウンタとして表示されます。各ノードのバッファ プール内のメモリは、Buffer Node オブジェクトの Target pages カウンタとして表示されます。他のノードのメモリは、Foreign pages カウンタとして表示されます。詳細については、「SQL Server: Buffer Node オブジェクト」および「SQL Server: Buffer Manager オブジェクト」を参照してください。

各ノード自体のメモリのチェックポイント

各メモリ ノードにはノード自体のレイジー ライタ スレッドがあります。このスレッドは、暗黙のチェックポイントと明示的なチェックポイントの両方で呼び出されます。SMP (対称型マルチプロセッシング) コンピュータにはチェックポイント スレッドが 1 つしかないため、NUMA を使用してスレッドが複数になると、チェックポイントの実行速度が向上します。

テーブル スキャン動作

ノード N1 上で実行されるテーブル スキャンは、複数のノードの CPU 上で並行してスキャンが実行されていない限り、ノード N1 に関連付けられているメモリだけに書き込みます。単一のノードだけでスキャンが実行されている場合は、そのノードのバッファ ページだけが使用されます。これにより、アプリケーションのワークロードを分割することができます。