NUMAとメモリとゲームとサーバ


艦これ」といえばDMMのゲームと言われるほどにまでなりましたが、「城コレ」が今度は控えているようです。約30万人の方が事前登録してくださったという嬉しい悲鳴がところどころで聞かれます。そしてツチノコ部隊も全体の安定稼働へ向けて色々と対応しています。ところで、こういうオンラインゲームは、可愛いキャラクターもさることながら、ブラウザの裏でインターネット越しに必死に動いている「黒子」のようなものたちがいます。いわゆる「ゲームサーバ」と呼ばれるものです。

ゲームサーバは、その基本構成としておおまかに「アプリ(フロント)サーバ」と「データベース(バックエンド)サーバ」に分かれます。今日はその中でも「データベースサーバ」についてのお話です。

DMMでは大抵のデータベースサーバにLinuxとMySQLを使っています。そのデータベースエンジンにInnoDBというのがありまして、設定項目としてメモリ上にバッファをするという設定を行うことができます。

innodb_buffer_pool_size = 100G

例えば、メモリを128GB搭載したサーバでバッファ用に100GBのメモリを割り当てるとします。さて、実際のメモリの割当はどのようになるでしょうか。最近のXeonを搭載したサーバとして考えてみます。実はCPUの個数により、そのメモリの割り当てられ方が変わってきます。というのも、昔と違い今はメモリのコントローラがCPUに内蔵されているからなのです。

  • シングルCPU構成の場合

すべてのメモリがCPUと直接つながっているので、特に気にする事はありません。

  • マルチCPU構成の場合

CPU0とCPU1…とにそれぞれメモリがつながっています。例えば先ほど128GBとしたメモリが2CPU環境にあるとしましょう。そうするとCPUにごとに64GBのメモリがつながっている事になります。標準ではLinuxはプロセス毎にそのプロセスが動いているCPUにつながったメモリを利用しようとします。つまり、先ほどの100GB割り当てが、MySQLのプロセスが動いている片方のCPUに偏ってしまうのです。その結果、片方のメモリがMySQLに食いつぶされ、そこにもともといたデータがSWAPに吐き出されます。もう片方のCPUにつながっているメモリに空きがあっても、です。

少し詳しい話にしましょう。最近の共有型のマルチプロセッサシステムアーキテクチャは、NUMA(Non-Uniformed Memory Access)というものです。これは、CPUとメモリのまとまりを「ノード」と呼びます。先の例では、CPUと64GB分のメモリのまとまりが”ノード”です。

Linux OS上でプロセスが起動すると、そのプロセスはCPUに割り当てられます。CPUとメモリがまとまっているので、プロセス自体のデータは同じNUMAノードのメモリに置かれます。
先の例の2CPUの環境MySQLが起動したあとメインスレッドがCPU0に割り当てられたとして、そのCPUにぶら下がる64GBのメモリにMySQLのデータが置かれます。しかし、バッファデータのサイズだけで100GBあるので、NUMAノードの64GBをいずれ食いつぶします。そうなると、同じNUMAノード上にある他プロセスのデータがメモリから溢れます。他NUMAノードのメモリはデフォルトではOSが割り当てをしない状態になっているため、あふれたものはスワップへ送られます。もともと64GBのメモリ上にあるものなのでスワップアウトするデータ量も大きくなる傾向があります。なので実際のところスワップが埋まってしまう可能性が非常に高いです。

では、どうすればこの偏りやスワップアウトを抑えることができるのか。

numactl --interleave=all ${CMD}

NUMAをOSからコントロールするnumactlというコマンドがあります。
–interleaveオプションは割り当てるNUMAノードを指定します。上記の例では”all”となっているため、すべてのNUMAノードに割り当てを行うことを意味します。

cat /proc/`pidof ${PROCESS}`/numa_maps

こちらのコマンドで、NUMAに対するプロセスの状況が見られます。
とはいえ、見るのは大変なので、下記のページを参考に、Perlスクリプトを使ってみましょう。
http://blog.jcole.us/2010/09/28/mysql-swap-insanity-and-the-numa-architecture/
numa-maps-summary.pl というスクリプトです。って、実はこれ2010年の記事なんですよね。知りませんでした。

実際にスワップアウトしてスワップを喰い潰してしまったサーバがこちら

[root@srv3053 ~]# perl numa-maps-summary.pl < /proc/`pidof mysqld`/numa_maps;free
N0        :     16132628 ( 61.53 GB)
N1        :     12288264 ( 46.88 GB)
active    :     26922666 (102.70 GB)
anon      :     28420892 (108.42 GB)
dirty     :     28420892 (108.42 GB)
mapmax    :          157 (  0.00 GB)
mapped    :         1373 (  0.01 GB)
             total       used       free     shared    buffers     cached
Mem:     132112264  126602604    5509660          0     142040   10854736
-/+ buffers/cache:  115605828   16506436
Swap:      2097136    2097136          0

同じサーバで、numactlを設定したのがこちら

[root@srv3053 ~]# perl numa-maps-summary.pl < /proc/`pidof mysqld`/numa_maps;free
N0        :     14679063 ( 56.00 GB)
N1        :     13763886 ( 52.51 GB)
active    :     26950881 (102.81 GB)
anon      :     28441601 (108.50 GB)
dirty     :     28441601 (108.50 GB)
mapmax    :          158 (  0.00 GB)
mapped    :         1410 (  0.01 GB)
             total       used       free     shared    buffers     cached
Mem:     132112264  125522400    6589864          0     141764    9805148
-/+ buffers/cache:  115575488   16536776
Swap:      2097136          0    2097136

設定前はNUMAノード分の64GBに近く偏っていたものが、設定後は分散されているのがわかります。
上記のようにプロセスがどかっと大きなメモリを割り当てることでスワップアウトしてしまう現象を”Swap Insanity”といいます。
そして先のブログ記事にもありますが、mysqldのinitスクリプトを改造して、numactlを埋め込んでしまうという手を使うことで、回避ができます。

«
»

Comments

  • BIOSのInterleave設定について

    この設定をOnにすることでNUMAを無効化できます。

    なんですが、

    ESXi、Hyper-V、KVM等ではOff(NUMA有効)が推奨されています。

    ハイパーバイザー側でインテリジェントにCPUに近いメモリへデータを配置できるようになっているからとのことです。

    すべてのメモリ空間でNUMAを無効とするよりは必要な空間だけNUMAを無効として処理させたほうが効率が良いからですね。

    ちなみにnumactlはある特定のプロセスだけNUMAを無効にすることが可能です。

    とshinonomeが言ってました。

  • 添付ファイルはNUMAを無効化した際のベンチマーク結果です。

    無効化すると結構なパフォーマンス低下が観測されています。

    全体を無効とするのではなく必要なプロセスだけ処理する形が望ましいのです。

    グラフ出展元:http://en.community.dell.com/cfs-file/__key/telligent-evolution-components-attachments/13-4491-00-00-20-24-87-40/12g_5F00_bios_5F00_tuning_5F00_for_5F00_performance_5F00_power.pdf

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

Optionally add an image (JPEG only)