コンテンツにスキップ
Apache2.2のパフォーマンスチューニング(その2)

Apache2.2のパフォーマンスチューニング(その2)

Debian lenny
本記事は 2011 年 2 月に旧サイト(オンプレミス環境)で公開した記録の復元です。内容は当時のまま掲載しています。本記事には Amazon アソシエイトのアフィリエイトリンクを含みます。

対象サーバについて

製品名OpenBlockS 600
OS(kernel ver)Debian lenny(2.6.29)
CPU600MHz(AMCC PowerPC 405EX)
メモリ1GB(DDR2 SDRAM)
ストレージ8GB(Compact Flash)

はじめに

Apache2.2の基本設定、バーチャルホスト設定、ログ設定等はApache2.2の設定にまとめていますので参照してみて下さい。

Apache MPM preforkのMaxclients以外のパラメータ(StartServers、MinSpareServers、MaxSpareServers、MaxRequestsPerChild)についてはApache2.2のパフォーマンスチューニング(その1)にまとめていますので参照してみて下さい。

本記事について

いまさらながらサーバ/インフラを支える技術に載っていたApache2のチューニングをしてみることにしました(ここに書いてあることは間違いだらけかもしれません…がご了承下さい)。

チューニングをする意味があるほどのアクセスは当サイトにはありませんが、マシンリソースを使い切るほどの攻撃を受けないとも限りませんので、本記事ではMaxClientsが適切な値になっているかを確認したいと思います。

Apache2の1プロセスが使用するメモリ量の確認

適切なMaxClientsの値を調べるため、まずはApacheの1プロセスが使用するメモリ容量を調べます。

www:~# ps auxw | egrep '(STAT|apache)'
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
www-data 12650  0.0  1.7  72176 18036 ?        SN   20:10   0:05 /usr/sbin/apache2 -k start
www-data 16666  0.0  1.8  73820 19156 ?        SN   20:35   0:07 /usr/sbin/apache2 -k start
www-data 16690  0.0  1.8  73504 18844 ?        SN   20:59   0:06 /usr/sbin/apache2 -k start
www-data 20764  0.1  1.6  71920 17280 ?        SN   21:30   0:12 /usr/sbin/apache2 -k start
www-data 20780  0.0  1.2  72584 12808 ?        SN   21:41   0:01 /usr/sbin/apache2 -k start
root     24605  0.0  1.0  71052 10584 ?        SNs  Jan22   0:08 /usr/sbin/apache2 -k start
www-data 24855  0.0  1.2  72772 13080 ?        SN   22:46   0:01 /usr/sbin/apache2 -k start
www-data 24856  0.0  1.7  72452 18200 ?        SN   22:46   0:01 /usr/sbin/apache2 -k start
www-data 24864  0.0  1.3  72184 13656 ?        SN   23:08   0:00 /usr/sbin/apache2 -k start
www-data 28933  0.5  1.2  72576 12844 ?        SN   23:23   0:01 /usr/sbin/apache2 -k start
www-data 28934  0.3  0.9  72004  9572 ?        SN   23:23   0:00 /usr/sbin/apache2 -k start
root     28957  0.0  0.0   3316   960 pts/0    SN+  23:26   0:00 egrep (STAT|apache)

preforkのためPID(プロセスID)とLWP(スレッドID)は等しくなっています。

rootユーザで起動しているのが親プロセスです。

ここでは子プロセスの中から、例としてPID=12650の使用メモリ量を調べてみます。

以下の、VmHWMの値(18376=約18M)が実際にプロセスの使用しているメモリ容量の最大値になります。

www:~# cat /proc/12650/status
Name:   apache2
State:  S (sleeping)
Tgid:   12650
Pid:    12650
PPid:   24605
TracerPid:      0
Uid:    33      33      33      33
Gid:    33      33      33      33
FDSize: 32
Groups: 33
VmPeak:    72688 kB
VmSize:    72176 kB
VmLck:         0 kB
VmHWM:     18376 kB
VmRSS:     18036 kB
VmData:     4900 kB
VmStk:        84 kB
VmExe:       388 kB
VmLib:     26916 kB
VmPTE:        80 kB
Threads:        1
SigQ:   0/8192
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000001000
SigCgt: 000000018c0046eb
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: fffffffffffffeff
voluntary_ctxt_switches:        213
nonvoluntary_ctxt_switches:     1429

Apache2の親・子プロセス間の共有メモリ容量の確認

上記で1プロセスが使用するメモリ容量が18Mであることを確認しましたが、実際にはapache2の親プロセスと子プロセスがコピーオンライト機能によりメモリを一部共用しているため、そのメモリサイズを上記18Mから引く必要があります。

「サーバインフラを支える技術」にも載っていて、著者のブログであるLinux のプロセスが Copy on Write で共有しているメモリのサイズを調べる - naoyaのはてなダイアリーでも紹介されている、共有メモリサイズを調べるPerlスクリプトを使用して、各プロセスが親プロセスと共用しているメモリ容量を調べます。

www:~# vi shared_memory.pl

#!/usr/bin/env perl
use strict;
use warnings;
use Linux::Smaps;

@ARGV or die "usage: %0 [pid ...]";

print "PID\tRSS\tSHARED\n";

for my $pid (@ARGV) {
        my $map = Linux::Smaps->new($pid);
        unless ($map) {
                warn $!;
                next;
        }

        printf
                "%d\t%d\t%d (%d%%)\n",
                $pid,
                $map->rss,
                $map->shared_dirty + $map->shared_clean,
                int((($map->shared_dirty + $map->shared_clean) / $map->rss) * 100)
}

www:~# chmod +x shared_memory.pl

www:~# ./shared_memory.pl `pgrep apache2`
Can't locate Linux/Smaps.pm in @INC at ./shared_memory.pl line 4.
BEGIN failed--compilation aborted at ./shared_memory.pl line 4.

PerlモジュールのLinux::Smapsが必要になります。

最近はCPANよりもcpanmの方が主流になっているようですので、こちらのサイトを参考にさせて頂き、Linux::Smapsモジュールをインストールします。

www:~# mkdir bin && cd ~/bin

www:~/bin# wget http://xrl.us/cpanm
--2010-10-31 16:25:22--  http://xrl.us/cpanm
xrl.us をDNSに問いあわせています... 207.171.7.197
xrl.us|207.171.7.197|:80 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 301 Moved Permanently
場所: http://github.com/miyagawa/cpanminus/raw/master/cpanm [続く]
--2010-10-31 16:25:22--  http://github.com/miyagawa/cpanminus/raw/master/cpanm
github.com をDNSに問いあわせています... 207.97.227.239
github.com|207.97.227.239|:80 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 170261 (166K) [text/plain]
`cpanm' に保存中

100%[==============================================================================================================================================================>] 170,261      113K/s 時間 1.5s

2010-10-31 16:25:24 (113 KB/s) - `cpanm' へ保存完了 [170261/170261]

www:~/bin# chmod +x cpanm

www:~/bin# ./cpanm local::lib
--> Working on local::lib
Fetching http://search.cpan.org/CPAN/authors/id/G/GE/GETTY/local-lib-1.006007.tar.gz ... OK
Configuring local-lib-1.006007 ... OK
Building and testing local-lib-1.006007 ... OK
Successfully installed local-lib-1.006007

www:~/bin# ./cpanm --self-upgrade
--> Working on App::cpanminus
Fetching http://search.cpan.org/CPAN/authors/id/M/MI/MIYAGAWA/App-cpanminus-1.0015.tar.gz ... OK
Configuring App-cpanminus-1.0015 ... OK
==> Found dependencies: Module::Build, ExtUtils::Install, LWP
--> Working on Module::Build
Fetching http://search.cpan.org/CPAN/authors/id/D/DA/DAGOLDEN/Module-Build-0.3607.tar.gz ... OK
Configuring Module-Build-0.3607 ... OK
==> Found dependencies: ExtUtils::CBuilder, ExtUtils::ParseXS, Test::Harness
--> Working on ExtUtils::CBuilder
Fetching http://search.cpan.org/CPAN/authors/id/D/DA/DAGOLDEN/ExtUtils-CBuilder-0.2703.tar.gz ... OK
Configuring ExtUtils-CBuilder-0.2703 ... OK
Building and testing ExtUtils-CBuilder-0.2703 ... OK
Successfully installed ExtUtils-CBuilder-0.2703 (upgraded from 0.21)
--> Working on ExtUtils::ParseXS
Fetching http://search.cpan.org/CPAN/authors/id/D/DA/DAGOLDEN/ExtUtils-ParseXS-2.2206.tar.gz ... OK
Configuring ExtUtils-ParseXS-2.2206 ... OK
Building and testing ExtUtils-ParseXS-2.2206 ... OK
Successfully installed ExtUtils-ParseXS-2.2206 (upgraded from 2.18_02)
--> Working on Test::Harness
Fetching http://search.cpan.org/CPAN/authors/id/A/AN/ANDYA/Test-Harness-3.22.tar.gz ... OK
Configuring Test-Harness-3.22 ... OK
Building and testing Test-Harness-3.22 ... OK
Successfully installed Test-Harness-3.22 (upgraded from 2.64)
Building and testing Module-Build-0.3607 ... OK
Successfully installed Module-Build-0.3607 (upgraded from 0.2808_01)
--> Working on ExtUtils::Install
Fetching http://search.cpan.org/CPAN/authors/id/Y/YV/YVES/ExtUtils-Install-1.54.tar.gz ... OK
Configuring ExtUtils-Install-1.54 ... OK
Building and testing ExtUtils-Install-1.54 ... OK
Successfully installed ExtUtils-Install-1.54 (upgraded from 1.44)
--> Working on LWP
Fetching http://search.cpan.org/CPAN/authors/id/G/GA/GAAS/libwww-perl-5.837.tar.gz ... OK
Configuring libwww-perl-5.837 ... OK
==> Found dependencies: URI, HTML::Parser, HTML::Tagset
--> Working on URI
Fetching http://search.cpan.org/CPAN/authors/id/G/GA/GAAS/URI-1.56.tar.gz ... OK
Configuring URI-1.56 ... OK
Building and testing URI-1.56 ... OK
Successfully installed URI-1.56
--> Working on HTML::Parser
Fetching http://search.cpan.org/CPAN/authors/id/G/GA/GAAS/HTML-Parser-3.68.tar.gz ... OK
Configuring HTML-Parser-3.68 ... OK
==> Found dependencies: HTML::Tagset
--> Working on HTML::Tagset
Fetching http://search.cpan.org/CPAN/authors/id/P/PE/PETDANCE/HTML-Tagset-3.20.tar.gz ... OK
Configuring HTML-Tagset-3.20 ... OK
Building and testing HTML-Tagset-3.20 ... OK
Successfully installed HTML-Tagset-3.20
Building and testing HTML-Parser-3.68 ... OK
Successfully installed HTML-Parser-3.68
Building and testing libwww-perl-5.837 ... OK
Successfully installed libwww-perl-5.837
Building and testing App-cpanminus-1.0015 ... OK
Successfully installed App-cpanminus-1.0015

local::libの導入とcpanm自身のupgradeも実施しています。

続けて、Linux::Smapsがまだ入っていないことを念のため確認してから、インストールを実施します。

www:~/bin# cd ..

www:~# ./shared_memory.pl `pgrep apache2`
Can't locate Linux/Smaps.pm in @INC at ./shared_memory.pl line 4.
BEGIN failed--compilation aborted at ./shared_memory.pl line 4.

www:~# cd bin/

www:~/bin# ./cpanm Linux::Smaps
--> Working on Linux::Smaps
Fetching http://search.cpan.org/CPAN/authors/id/O/OP/OPI/Linux-Smaps-0.06.tar.gz ... OK
Configuring Linux-Smaps-0.06 ... OK
==> Found dependencies: Class::Member
--> Working on Class::Member
Fetching http://search.cpan.org/CPAN/authors/id/O/OP/OPI/Class-Member-1.6.tar.gz ... OK
Configuring Class-Member-1.6 ... OK
Building and testing Class-Member-1.6 ... OK
Successfully installed Class-Member-1.6
Building and testing Linux-Smaps-0.06 ... FAIL
! Installing Linux::Smaps failed. See /root/.cpanm/build.log for details.

インストールに失敗しました。ログを確認してみます。

www:~/bin# tail /root/.cpanm/build.log

#   Failed test 'other process'
#   at t/Linux-Smaps.t line 72.
# Looks like you failed 1 test of 35.
t/Linux-Smaps.t ..
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/35 subtests
        (less 4 skipped subtests: 30 okay)

Test Summary Report
-------------------
t/Linux-Smaps.t (Wstat: 256 Tests: 35 Failed: 1)
  Failed test:  20
  Non-zero exit status: 1
Files=1, Tests=35, 17 wallclock secs ( 0.88 usr  0.17 sys + 11.31 cusr  3.04 csys = 15.40 CPU)
Result: FAIL
Failed 1/1 test programs. 1/35 subtests failed.
make: *** [test_dynamic] エラー 1
-> FAIL Installing Linux::Smaps failed. See /root/.cpanm/build.log for details.

検索しても同様の事象が見当たらず、何とかできる技術力も無いので、今のところPerlは未使用ということもありforce installしてしまいます。

www:~/bin# ./cpanm -f Linux::Smaps
--> Working on Linux::Smaps
Fetching http://search.cpan.org/CPAN/authors/id/O/OP/OPI/Linux-Smaps-0.06.tar.gz ... OK
Configuring Linux-Smaps-0.06 ... OK
Building and testing Linux-Smaps-0.06 ... FAIL
! Testing Linux-Smaps-0.06 failed but installing it anyway.
Successfully installed Linux-Smaps-0.06

テストは失敗しましたがインストールは成功しました。

www:~/bin# cd ..

www:~# ./shared_memory.pl `pgrep apache2`
PID     RSS     SHARED
12650   18036   15572 (86%)
16666   19156   16152 (84%)
16690   19016   16220 (85%)
20764   17280   14884 (86%)
20780   12808   10016 (78%)
24605   10584   6368 (60%)
24855   13080   10272 (78%)
24856   18208   15576 (85%)
24864   13656   11376 (83%)
28933   12844   10024 (78%)
28934   9572    7920 (82%)

平均80%程度を親プロセスと共有しています。

各プロセスについて正確な値を把握するため、以下のようなシェルスクリプトを書いて確かめます。

www:~# vi mem.sh

#!/bin/sh

PID=`ps auxw | grep apache | grep -v root | awk '{print $2}'`
for pid in $PID
do
        cat /proc/$pid/status | egrep '(^Pid:|VmHWM)'
done

www:~# chmod 755 mem.sh
www:~# ./mem.sh
Pid:    12650
VmHWM:     18376 kB
Pid:    16666
VmHWM:     19268 kB
Pid:    16690
VmHWM:     19100 kB
Pid:    20764
VmHWM:     17760 kB
Pid:    20780
VmHWM:     12808 kB
Pid:    24855
VmHWM:     13084 kB
Pid:    24856
VmHWM:     18348 kB
Pid:    24864
VmHWM:     13656 kB
Pid:    28933
VmHWM:     12844 kB
Pid:    28934
VmHWM:      9572 kB

Pidごとに、VmHWM x (1 - shared_memory.plの結果出た共有率)してみた結果が実際のプロセスの使用率になります(以下に計算結果を表示)。

VmHWM共有率VmHWM x (1-共有率)
183760.862572.64
192680.843082.88
191000.852865
177600.862486.4
128080.782817.76
130840.782878.48
183480.852752.2
136560.832321.52
128440.782825.68
95720.821722.96

上記の平均を取ると、本サーバでは1プロセスあたり約2.5Mになります(こんなに小さくていいものなんでしょうかね…)。

本サーバのメモリは1Gですので、単純計算でMaxClients = 1024/2.5 = 409となりますが、現実的には通常時の使用可能メモリが700M程度(後述)ですので以下の値が上限値となります。

MaxClients = 700/2.5 = 280

この理屈で値を決定して本当に問題ないか、abコマンドを使用して確かめてみたいと思いますが、記事が長くなってきたので別記事にまとめます。apache2.2の負荷試験を参照して下さい。

あと、本記事に誤りがあるのに気付かれたらご指摘下さいm(_ _)m

参考文献

[24時間365日] サーバ/インフラを支える技術 ‾スケーラビリティ、ハイパフォーマンス、省力運用 (WEB+DB PRESS plusシリーズ) ">サーバ/インフラを支える技術

Amazonアソシエイトリンク