[perl] Apache2+mod_perl2 のメモリ消費量を調べる
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スクリプトを利用して計測します。
- perlスクリプトはこちら(Linux のプロセスが Copy on Write で共有しているメモリのサイズを調べる)
- ※上記ブログに「Perl には Linux::Smaps という /proc/PID/smaps のデータをプログラマブルに扱えるモジュールがあります。…」という部分があり、その下にプログラムがあります。
このプログラムを利用して、メモリを計測すると以下の結果が出ました。
# 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」、「各プロセスの全体メモリ」、「その中の共有メモリ」、「プロセス内の共有メモリの割合(%)」になります。
内訳は
- 共有メモリ
- 85.6MB
- プライベートメモリ
- 830.5MB
になります。
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 を宣言して、グローバルで変数を使わないようにします
- 全ての pl/pm ファイルで use strict するようにしています。 no strict もよっぽどの例外でない限り禁止しています。
package App::Pages::Some; use strict; . . .
- 全ての pl/pm ファイルで use strict するようにしています。 no strict もよっぽどの例外でない限り禁止しています。
- Config、Cacheコネクションなどの毎回同じものはInstance化する
- MaxRequestsPerChild を少なめに設定し、リクエスト処理数の増加とプロセスサイズ増加にLimitをかけます
- 通常は最大リクエスト数を100程度で設定してから調整を行っています。
MaxRequestsPerChild 100
- 通常は最大リクエスト数を100程度で設定してから調整を行っています。
プロセス数の増加を防ぐ
プロセスの増加自体がメモリを消費するベースになります。無駄な増加は増やさないようにします。
- KeepAlive をOFFにする
- Apacheをフロントとバックエンドの2つに分けて バックエンド側でmod_perlだけのリクエストを処理します。
この際にバックエンド側ではKeepAlive off
を設定し、フロントからのコネクションを無駄に占有させることが無いようにしています。
- Apacheをフロントとバックエンドの2つに分けて バックエンド側でmod_perlだけのリクエストを処理します。
但しAPIを多用するようなサイトの場合、KeepAlive On での設定の方が効率的な場合があります。
KeepAlive On MaxKeepAliveRequests 10 KeepAliveTimeout 2
この場合の「MaxKeepAliveRequests」は、ブラウザで1ページを表示させる際に必要とする mod_perlへのリクエスト数を
割り当てます。
また、KeepAliveTimeoutを短く設定することで、フロントサーバからのコネクションを無駄に発生させないようにしています。








