[perl] Apache2+mod_perl2 のメモリ消費量を調べる

2009年6 月20日  |  Written by matsumoto  |  under Perl, サーバー Yahoo!ブックマークに登録    はてなブックマーク - [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スクリプトを利用して計測します。

このプログラムを利用して、メモリを計測すると以下の結果が出ました。

# 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;
      .
      .
      .
  • Config、Cacheコネクションなどの毎回同じものはInstance化する
  • MaxRequestsPerChild を少なめに設定し、リクエスト処理数の増加とプロセスサイズ増加にLimitをかけます

    • 通常は最大リクエスト数を100程度で設定してから調整を行っています。

      MaxRequestsPerChild  100

プロセス数の増加を防ぐ

プロセスの増加自体がメモリを消費するベースになります。無駄な増加は増やさないようにします。

  • KeepAlive をOFFにする

    • Apacheをフロントとバックエンドの2つに分けて バックエンド側でmod_perlだけのリクエストを処理します。
      この際にバックエンド側では

      KeepAlive off

      を設定し、フロントからのコネクションを無駄に占有させることが無いようにしています。

但しAPIを多用するようなサイトの場合、KeepAlive On での設定の方が効率的な場合があります。

KeepAlive On
MaxKeepAliveRequests 10
KeepAliveTimeout 2

この場合の「MaxKeepAliveRequests」は、ブラウザで1ページを表示させる際に必要とする mod_perlへのリクエスト数を
割り当てます。

また、KeepAliveTimeoutを短く設定することで、フロントサーバからのコネクションを無駄に発生させないようにしています。

参考リンク

現在コメントはありません | コメントの投稿はこちら

コメントを書き込む

コメント本文

※コメントのフォーム内で以下のタグがご利用いただけます
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

私はチーム・マイナス6%です