mod_perl2+Sledgeでテストを繰り返しているのですが、各プロセスでのメモリ消費量が激しく気になります。
特に多くのperlモジュールをロードする場合、プロセスサイズが肥大化するので随時チェックしています。
mod_perlのメモリ消費状況を知る
今回は INCDiffを使って、startup.plを精査しつつ mod_perl2を抱えたhttpdのメモリ消費量をチェックしました。
httpd.confの設定
httpd.confはpreforkモードで使っていてプロセスの塩梅は以下です
StartServers 20
MinSpareServers 20
MaxSpareServers 50
ServerLimit 1000
MaxClients 1000
# MaxRequestsPerChild 100
MaxRequestsPerChild 1000
MaxRequestPerCHildがやや多めなのですが、mod_perl2 のメモリ消費量検証用ということで多くしています。
コメントアウトしていますが、常用では100を設定しています。
httpdが「起動」している状態の メモリ使用状況
# vmstat
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 4672652 373464 1781576 0 0 0 1 2 2 0 0 100 0 0
httpdを停止します。
# service httpd stop
httpd を停止中: [ OK ]
httpdが「停止」している状態の メモリ使用状況
# vmstat
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 5610844 373464 1781332 0 0 0 1 2 2 0 0 100 0 0
httpdが抱えていたメモリを逆算します。
freeが 4672652 から 5610844 に増えていますので、httpdが抱えていたメモリは
938192 (約916.2MB)
この916.2MBをどう使っているのか。
重要な点は共有メモリか、各プロセスが独自にそれぞれメモリを消費しているかで、効率の度合いが変わってくる点です。
共有メモリの利用率が高ければ 効率的にメモリを使えますので、起動プロセス数を増加できます。
共有メモリか、プライベートなメモリかを測定するperlスクリプトを利用して計測します。
このプログラムを利用して、メモリを計測すると以下の結果が出ました。
# shared_memory_size.pl `pgrep httpd`
PID RSS SHARED
4719 57988 46392 (80%)
4721 69024 46260 (67%)
4722 67740 45948 (67%)
4723 69256 45276 (65%)
4724 68772 45948 (66%)
4725 68360 45884 (67%)
4726 68276 46188 (67%)
4728 68972 46260 (67%)
4729 69924 45944 (65%)
4730 69564 45884 (65%)
4731 69728 46260 (66%)
4732 68712 45948 (66%)
4733 68748 46260 (67%)
4734 68792 46256 (67%)
4735 70572 45948 (65%)
4737 69092 46188 (66%)
4738 68412 45948 (67%)
4739 69696 46184 (66%)
4740 69004 46256 (67%)
4744 67352 46188 (68%)
4746 67116 45948 (68%)
4751 66608 45948 (68%)
4752 66892 45948 (68%)
4755 65280 46260 (70%)
4782 64092 46260 (72%)
4785 63876 46260 (72%)
4786 63720 46260 (72%)
4788 62784 46260 (73%)
4790 61736 46260 (74%)
4791 63404 46260 (72%)
4794 61432 46260 (75%)
4797 60604 46188 (76%)
4799 60648 46260 (76%)
4804 58880 46288 (78%)
4808 60236 45900 (76%)
4815 58368 46228 (79%)
4816 58940 46228 (78%)
4829 57608 46228 (80%)
4842 55128 46228 (83%)
4843 55124 46224 (83%)
4844 55128 46228 (83%)
4845 55128 46228 (83%)
4848 55124 46224 (83%)
4849 55128 46228 (83%)
4850 55128 46228 (83%)
4851 54780 46156 (84%)
4855 54696 46156 (84%)
4856 54608 46232 (84%)
4857 54604 46232 (84%)
4858 54604 46232 (84%)
4859 54604 46232 (84%)
それぞれ、「プロセスのID」、「各プロセスの全体メモリ」、「その中の共有メモリ」、「プロセス内の共有メモリの割合(%)」になります。
内訳は
になります。
httpdの起動数が最大50ですのえ、これを細かく計算すると (830.5 / 50) 1プロセス辺り、平均で
16.61MB
のプライベートメモリを利用している計算になります。
4GBのメモリを搭載しているサーバで、webサーバ専用であれば、このプロセスサイズのhttpdを扱う場合
- OS、その他のメモリ 1GB
- httpd用のメモリ 3GB
と仮定し、
3GB = 共有メモリ(約100MB) + ( プライベートメモリ(@16.61MB) x 174 )
になるので、最大プロセス数を174までは理論上は起動できることになります。
※174という数字は参考値として捉えています。この数値ですと、全く余裕がない設定なので、実際はプロセス数を50前後から少しづつ増やしていっています。
まとめ&mod_perlはメモリを食います
mod_perlの設定では、perlモジュールのロードによるメモリ消費量が一番クリティカルだと思います。
このコントロールを意識しないと、どんなに良い性能のサーバでもスワップが起こってしまいます。
対象方法としては、以下でしょうか。
なるべく共有メモリを使う
- startup.plでのモジュール読み込みで共有メモリになるべく多くのモジュールをロードさせます
プライベートメモリの肥大化を防ぐ
MaxRequestPerChildの方は、防ぐというよりも増加したメモリを強制的にkillしています。
- (当たり前ですが) strict を宣言して、グローバルで変数を使わないようにします
- Config、Cacheコネクションなどの毎回同じものはInstance化する
- MaxRequestsPerChild を少なめに設定し、リクエスト処理数の増加とプロセスサイズ増加にLimitをかけます
- 通常は最大リクエスト数を100程度で設定してから調整を行っています。
MaxRequestsPerChild 100
プロセス数の増加を防ぐ
プロセスの増加自体がメモリを消費するベースになります。無駄な増加は増やさないようにします。
但しAPIを多用するようなサイトの場合、KeepAlive On での設定の方が効率的な場合があります。
KeepAlive On
MaxKeepAliveRequests 10
KeepAliveTimeout 2
この場合の「MaxKeepAliveRequests」は、ブラウザで1ページを表示させる際に必要とする mod_perlへのリクエスト数を
割り当てます。
また、KeepAliveTimeoutを短く設定することで、フロントサーバからのコネクションを無駄に発生させないようにしています。
参考リンク