概要
メモリの基本を理解することで、運用しているサーバーで障害が起きた際に原因調査と解決ができるようになるため、ここではサーバー構成で重要なメモリの基本的な仕組みをみていきます。
メモリの仕組み
プログラムを実行するには、変数や配列が必要です。そのような情報はメモリ上に置かれます。
他にもアプリケーションのプログラム自体や、外部関数のライブラリなどもプロセスのメモリに置かれます。
共有メモリ
多くのアプリケーションが共通で利用するデータを保存する領域のこと。
共有メモリの注意点
DBMSのメモリ消費量が大きく見える最大の理由は、共有メモリが各プロセスで重複して表示されるため実際のメモリ量よりも大きく見えます。
また、そのほかにも、共有ライブラリも同様に重複して表示される場合があります。
DBMSのメモリ構造
DBMSは大量のキャッシュ領域を持つのが特徴です。大きなシステムでは数十GB,数百GBといったサイズのメモリをキャッシュとして使用します。キャッシュを使う理由は可能な限りDISKへのI/Oを減らすためです。マルチプロセスであれば共有メモリに、マルチスレッドのDBMSであればヒープ領域に置かれています。
プロセスやスレッドが使用する部分
プロセスやスレッドが増えれば、その数に応じてメモリの合計量も変わります。また、DBMSには大規模なソート作業などでメモリを大量に必要とすることもあります。
仮想メモリと物理メモリ
OSの重要な機能として仮想メモリがあります。実際に使える物理メモリ以上のメモリをアプリケーションに提供します。
物理メモリ以上にプロセスがメモリを使用したらメモリの内容を一時的にディスクに保存します。その領域のことをスワップデバイスやスワップ領域と呼ばれます。メリットとしてメモリを多く使えますが、スワップ領域へのデータの保存はディスクへの書き込みになるため処理が遅くなりボトルネックになります。
(決まった大きさであるページ単位でデータをディスクを利用してメモリとやり取りする仕組みをページング方式といいます 参考: https://wa3.i-3-i.info/word13352.html)
スワップ領域からのデータの読み込みにかかる時間
具体的な待ち時間として、SQLが1MBのメモリを必要するとした場合、1ぺーじが4KBのOSの場合、スワップ領域に対して256ページのI/Oが必要です。各ページが一回のI/Oを必要とし、一回のI/Oが10msかかるとすると、256*10msで約2.6秒かかります。
ページングによる負のスパイラルも
処理に時間がかかりサーバーにリクエストがたまるとスレッドやプロセスが増えて使用メモリ量が増え、メモリが足りないがためにページングが発生してさらにスローダウンしてリクエストがたまるという負のスパイラルが発生する可能性もあります。
I/O性能にも重要なファイルキャッシュ
DBMSからディスクに書き込みをすると、基本的にファイルキャッシュにそのデータが載ります。DBMSがディスクからの読み込みをした場合もファイルキャッシュに載ります。DBMSが読み込みをした際にファイルキャッシュにデータがあればディスクにはアクセスしません。
書き込みとファイルキャッシュ
書き込みもファイルキャッシュに書き込んで、バックグランドでデーモンがディスクに書き込むことで処理を高速化しています。
確実にデータを書き込みたい場合はファイルキャッシュを使わずダイレクトI/Oでディスクに書き込む方式もあります。
ページの割り当ての仕組みとラージページ
ページ
ページとは、OSとCPUが扱うメモリの管理単位のこと。
プロセスは物理メモリやスワップ領域上にあるメモリ領域をページとして割り当てられることによって一時的な作業領域としてメモリを利用できるようになります。
プロセスがページを利用できるまでの仕組み〜デマンドページング〜
プロセスはメモリが必要になると、いったんmmapなどのシステムコールを発行して仮想メモリ領域を確保します。その後、プロセスが事前に確保された仮想メモリ領域にアクセスすると物理メモリやスワップ領域にあるページをプロセスに割り当てられます(デマンドページング)
プロセスがページを要求した場合のメカニズム
プロセスに割り当てられている仮想メモリ領域内の仮想メモリアドレスを元にしてページテーブルにアクセスします。ページテーブルから該当する変換情報であるPTG(Page Table Entry)を元にCPU装置の一つであるMMU(Memory Management Unit)が仮想メモリアドレスを物理メモリアドレスに変換します。その次に変換された物理メモリアドレスを元に該当の物理メモリのページにアクセスし、物理メモリがプロセスのページとして割り当てられます。
ラージページ
最近では数百GBの物理メモリを搭載している大型のDBサーバが増えてきて、キャッシュ領域が大きくなることによりパフォーマンス向上が見込めるようになった一方、新たな問題も起きています。
一つ目に、カーネルが使用するCPU使用率が常に高い状態にある傾向が見られることです。物理メモリが増えたことでページテーブルもそれに比例して大きくなり必要なPTEを探し出すためにCPUが多く消費されるのが原因です。
二つ目として、ページテーブル肥大化に伴いページテーブル本体が利用するメモリ上のサイズが大きくなりメモリ不足に陥ることがあります。
これらの課題を解決するためにラージページという仕組みが開発されました。
より大きなサイズ(2M〜数GB)のページを利用することでページテーブルの肥大化を防ぐことでPTE検索を効率化でき、またページテーブル保存のためのメモリサイズも小さくすることができるようになりました。
メモリ情報の見方
プロセス単位でメモリ情報確認
pmap
プロセスがどのように仮想メモリ空間を使っているかを表示するコマンドです。
OSレベルのメモリ情報の見方
free
物理メモリの状況を要約して表示します。
DBサーバーのメモリ設定
DMBSのキャッシュサイズ
キャッシュサイズを徐々に変えて確認します。一定サイズ以上になると性能が上がらなくなるのでそこを最大値としてキャッシュサイズをチューニングします。
DBMS全体のメモリ量の概算
SQLを実行する1プロセス(スレッド)あたりのメモリ使用量が共有メモリや共有ライブラリなどをのぞいて100MBとすると、DBMS全体では
実行バイナリ+DBMSのキャッシュ+プロセス(スレッド)数×100MB
バッチ処理など本数は少ないけど大量の処理を必要とするアプリケーションの場合には
上の式にソート用の領域のサイズを足すことで概算します。
上の概算を元に、パフォーマンステストでキャッシュヒット率やプロセスやスレッドによるメモリ消費量を実際に確認しながら調整していきます。
サーバーとDBの接続設定のコツ
プロセスやスレッドの事前起動やコネクションプーリングを用いることでコネクションにかかる時間を節約します。
コネクション数としては最小値と最大値を同じにすることでコネクションの開閉によるコストの節約をすることができます。
まとめ
プロセス中のメモリの構成からDBMSのメモリ構造、OSの重要な機能の一つである仮想メモリと物理メモリの機能、
さらにはI/O効率化のためのキャッシュの仕組みなどをみていきました。
有限なメモリ量をモニタリングしつつキャッシュなどを使って効率的なI/Oを実現することで
早いレスポンスを実現していくことが大事だとわかりました。