FAT47の底辺インフラ議事録

学んだことのメモ帳です

【メモ】MySQLでのswap発生とNUMAアーキテクチャ

DBサーバでとある日を境にswapが発生していることに気がつきました。

サーバはメモリ32GB搭載していて、そのうちの24GBをinnodb_buffer_pool_sizeに割り当てています。
他のthread毎のメモリ設定値を見てもおかしそうな点はなかったのでググってみました。

MySQL と NUMA アーキテクチャと Swap Insanity

MySQL InnoDBストレージエンジンのチューニング(後編)


なるほど…。
それぞれのCPUがローカルでメモリを管理しているので、
2CPU積んでいるサーバだと、AというCPUで実行されているスレッドが、BというCPUが確保しているメモリ領域にアクセスするには、AのCPUを経由しないといけないわけですね。
このメモリアクセスが不均一になる方式をNUMAアーキテクチャというみたいです。

NUMAアーキテクチャのメモリ管理が、ノードという単位でメモリをCPU毎に分割しているので、
MySQLinnodb_buffer_pool_sizeのように大量にメモリを割り当てると、

このようになるイメージです。
例えばこの状況で、Node0のメモリばかりが利用されていっぱいになってしまうと、
Node1にまだメモリの空きがあるにも関わらず、swapが発生してしまうというわけです。
この現象を"Swap Insanity"というようです。

今回はこの状態を回避するために、MySQLのメモリ確保のポリシーを変更します。

まずは現状を確認してみる。

# numactl --hardware
available: 2 nodes (0-1)
node 0 size: 4040 MB
node 0 free: 19 MB
node 1 size: 4011 MB
node 1 free: 22 MB
node distances:
node   0   1 
  0:  10  20 
  1:  20  10 

確かにノードは2つ存在しています。

このメモリの偏りを防止するには、メモリ確保のポリシーをinterleave(均一)にする必要があります。

現状のポリシー確認

# numactl --show | grep policy
policy: default

defaultのポリシーになっています。

MySQLプロセスのポリシーを確認すると、
defaultになっているのが確認できます。

# cat /proc/{myqslのPID}/numa_maps
2b0ee68c9000 default file=/usr/lib64/libaio.so.1.0.1 mapped=1 N0=1
2b0ee68ca000 default file=/usr/lib64/libaio.so.1.0.1
2b0ee6ac9000 default file=/usr/lib64/libaio.so.1.0.1 anon=1 dirty=1 N0=1
2b0ee6aca000 default anon=3 dirty=3 N0=3
7fff012a1000 default stack anon=16 dirty=16 N0=16

先程のリンクでMySQL5.5でメモリ確保ポリシーをinterleaveにするpatchが公開されているので、
そちらを利用します。

# vim /tmp/mysql55_numa.patch

内容

MySQLを停止させる

/etc/init.d/mysql stop

パッチ適用

# patch -u /usr/bin/mysqld_safe < /tmp/mysql55_numa.patch

MySQLを起動させる

/etc/init.d/mysql start

パッチ適用後の状態確認

# cat /proc/{myqslのPID}/numa_maps
2ba3ed1ca000 interleave=0-1 file=/lib64/libc-2.5.so
2ba3ed3ca000 interleave=0-1 file=/lib64/libc-2.5.so anon=4 dirty=4 N0=2 N1=2
2ba3ed3ce000 interleave=0-1 file=/lib64/libc-2.5.so anon=1 dirty=1 N1=1
2ba3ed3cf000 interleave=0-1 anon=7 dirty=7 N0=3 N1=4
7fffad110000 interleave=0-1 stack anon=17 dirty=17 N0=9 N1=8

第二フィールドがinterleave=0-1になったことが確認できます。

これでSwapが0になればめでたく解決ですが、
稼働中のDBなので、まだ停止させられてません…。
本番で設定でき次第結果を追記します。

以上メモでした。