Apache の MaxClients の設定値を自動計算する
MySQL のチューニングをサポートするスクリプトとして MySQLTuner が有名だが、似たような発想で Apache の MaxClients (Apache 2.4 以降は MaxRequestWorkers) の設定値を自動計算するスクリプトがある。
MaxClients の最適値に関する議論は「Apache の MaxClients の適正値」に別途まとめたので参照されたい。
海外製
海外製で一番それっぽいのが Apache2 Buddy だが、子プロセスの共有メモリなどは考慮せずに単純計算をしているようだ。結果的に MaxClients は小さい数字になるので、無難に設定したい場合はこれを利用すればよい。と思ったが、Remaining Memory の計算が特定のサービスの除算しかしてないので、分母のメモリ量が多くなり大きい数字になってしまう場合があるので注意。
Your server's physical RAM: 993 MB
Remaining Memory after other services considered: 993 MB
Apache's MaxClients directive: 256 <--------- Current Setting
Apache MPM Model: prefork
[ !! ] Your MaxRequestWorkers setting is too high.
Your recommended MaxRequestWorkers setting is between 168 and 187. <------- Acceptable Range (10% of MAX)
Max potential memory usage: 1354 MB
Percentage of TOTAL RAM allocated to Apache: 136.38 %
Percentage of REMAINING RAM allocated to Apache: 136.38 %
子プロセスのメモリ出力
子プロセスのメモリ出力では、伊藤直也氏の記事で有名な shared_memory_size.pl の流れを汲んだ none_shared_memory_fetcher.pl が子プロセスの非共有メモリを計算してくれるが、 MaxClients の値は自分で計算する必要がある。
PID RSS SHARED NONE_SHARED
12538 3780 3072 (81%) 708
12540 3048 2836 (93%) 212
12541 3060 2840 (92%) 220
12542 3152 2908 (92%) 244
12543 3060 2840 (92%) 220
自動計算
get_max_clients.sh は、不完全ではあるものの、子プロセスの共有メモリを考慮した MaxClients の数値を自動計算してくれるので、ぎりぎりを攻めたいようであればこれを利用すると良いだろう。
Memory Total / (Rss Average - Shr Average) = 1020076 / (3626 - 3263)
Memory Free / (Rss Average - Shr Average) = 635560 / (3626 - 3263)
MaxClients = 1750 ~ 2810
海外製
Apachetuner.sh
Gustav Maskowitz (@gusmaskowitz) によるコンセプトの記録としてのシェルスクリプト。当人による後述の Apachebuddy.pl に代替されている。
curl -sL https://raw.githubusercontent.com/gusmaskowitz/apachetuner/master/apachetuner.sh | sh
=========================SYSTEM=========================
CentOS release 6.8 (Final)
Server Name: localhost.localdomain
Total Physical Memory: 996 MB
=========================APACHE=========================
Version: Apache/2.2.15 (Unix)
RPM: httpd-2.2.15-53.el6.centos.x86_64
httpd binary: /usr/sbin/httpd
Whats running on port 80 12538/httpd
Apache Architecture: 64-bit
Serverlimit is: 256
MaxClients is: 256
httpd root /etc/httpd
httpd server config file /etc/httpd/conf/httpd.conf
httpd default errorlog /etc/httpd/logs/error_log
=========================PHP============================
/etc/php.ini memory_limit is: 128M
=====================APACHE RUNTIME=====================
Apache user: apache
Average Memory use: 2.07 MB per child
Number of children: 8
=========================REPORT==========================
Current memory footprint 16.56 MB
Maximum memory footprint 529.92 MB (53% of installed RAM)
System memory divided by MaxClients 4
System memory divided by Apache child size 481
Apache Buddy
Apache Buddy は Gustav Maskowitz (gusmaskowitz) により apachetuner.sh の代替として作成されたが、ohaio-solo に同等の実装がされているのでアクティブな開発は行っていない、としている。
curl -sL apachebuddy.pl | perl
########################################################################
# Apache Buddy v 0.3 ###################################################
########################################################################
Gathering information...
We are checking the service running on port 80
The process listening on port 80 is /usr/sbin/httpd
The process running on port 80 is Apache/2.2.15 (Unix)
Apache has been running 0d 0h 18m 39s
The full path to the Apache config file is: /etc/httpd/conf/httpd.conf
Apache is using prefork model
Examining your Apache configuration...
Apache runs as apache
Your max clients setting is 256
Analyzing memory use...
Your server has 996 MB of memory
The largest apache process is using 2.08 MB of memory
The smallest apache process is using 2.08 MB of memory
The average apache process is using 2.08 MB of memory
Going by the average Apache process, Apache can potentially use 532.49 MB RAM (53.47 % of available RAM)
Going by the largest Apache process, Apache can potentially use 532.49 MB RAM (53.47 % of available RAM)
Generating reports...
### GENERAL REPORT ###
Settings considered for this report:
Your server's physical RAM: 996MB
Apache's MaxClients directive: 256
Apache MPM Model: prefork
Largest Apache process (by memory): 2.08MB
[ OK ] Your MaxClients setting is within an acceptable range.
Max potential memory usage: 532.48 MB
Percentage of RAM allocated to Apache 53.47 %
-----------------------------------------------------------------------
-----------------------------------------------------------------------
Henry Wong (somethingweird) フォーク
apachebuddy.pl に対する CentOS 7.0 - Apache 2.4.6 対応パッチ版
curl https://raw.githubusercontent.com/somethingweird/apachebuddy.pl/master/apachebuddy.pl | perl
Apache2 Buddy
Richard Forth (@richardforth) による Apache Buddy のフォーク。
物理メモリをApacheプロセスの平均メモリで割った値、およびその9割を MaxClients の許容範囲としていて、子プロセスの共有メモリなどは考慮していない模様。
netstat
コマンドを使用しているため RHEL/CentOS 7.x では事前に yum install net-tools
の実行が必要。
curl -sL apache2buddy.pl -o apache2buddy.pl
perl apache2buddy.pl -r
[ CRITICAL ] Going by the average Apache process, Apache can potentially use 1354.25 MB RAM:
Without considering services: 136.38 % of total installed RAM
Considering extra services: 136.38 % of remaining RAM
[ CRITICAL ] Going by the largest Apache process, Apache can potentially use 1354.25 MB RAM:
Without considering services: 136.38 % of total installed RAM
Considering extra services: 136.38 % of remaining RAM
--------------------------------------------------------------------------------
Apache2buddy.pl report for server: localhost (14.3.31.162):
Settings considered for this report:
Your server's physical RAM: 993 MB
Remaining Memory after other services considered: 993 MB
Apache's MaxClients directive: 256 <--------- Current Setting
Apache MPM Model: prefork
[ !! ] Your MaxRequestWorkers setting is too high.
Your recommended MaxRequestWorkers setting is between 168 and 187. <------- Acceptable Range (10% of MAX)
Max potential memory usage: 1354 MB
Percentage of TOTAL RAM allocated to Apache: 136.38 %
Percentage of REMAINING RAM allocated to Apache: 136.38 %
--------------------------------------------------------------------------------
子プロセスのメモリ出力
shared_memory_size.pl (naoya版)
Linux のプロセスが Copy on Write で共有しているメモリのサイズを調べる - naoyaのはてなダイアリー
大変よく参照されるが、以下の shared_memory_size.pl は Linux::Smaps が必要なため、他のスクリプトを利用する方が良いだろう。
cat << _EOF_ > shared_memory_size.pl
#!/usr/bin/env perl
use strict;
use warnings;
use Linux::Smaps;
@ARGV or die "usage: %0 [pid ...]";
printf "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)
}
_EOF_
perl shared_memory_size.pl `pgrep httpd`
PID RSS SHARED
4847 8272 6180 (74%)
4876 5544 5292 (95%)
4935 5544 5292 (95%)
4976 5544 5292 (95%)
4999 5544 5292 (95%)
shared_memory_size.pl (yumatsumo版)
プロセスのCoW共有しているメモリのサイズ - マツモブログ
Linux::Smaps
不要版。
cat << _EOF_ > shared_memory_size.pl
#!/bin/env perl
use strict;
use warnings;
use List::Util ();
@ARGV or die "usage: %0 [pid ...]";
my @output;
for my \$pid (@ARGV) {
die "invalid pid '\$pid'" if \$pid =~ /\D/;
my @smaps = \`cat /proc/\$pid/smaps\`;
die if \$? != 0;
my @shared = map { /(\d+)\s+kB/; \$1 } grep { /^Shared_(Clean|Dirty)/ } @smaps;
my \$shared_total = List::Util::sum(@shared);
my @rss = map { /(\d+)\s+kB/; \$1 } grep { /^Rss/ } @smaps;
my \$rss_total = List::Util::sum(@rss);
my \$parcent = sprintf '(%d %%)', int((\$shared_total / \$rss_total) * 100);
push @output, [\$pid, \$rss_total, \$parcent];
}
unshift @output, [qw(PID RSS SHARED)];
for my \$out (@output) {
print join "\t", @\$out;
print "\n";
}
_EOF_
perl shared_memory_size.pl `pgrep httpd`
PID RSS SHARED
2505 3460 (75 %)
2506 2960 (93 %)
2507 2960 (93 %)
2508 2960 (93 %)
2509 2960 (93 %)
2510 2960 (93 %)
getmem.sh / getshmem.sh
Apacheのメモリ使用量を調べる - satooshi@blog
getmem.sh
cat << _EOF_ > getmem.sh
#!/bin/sh
#1 process name
if [ \$# -ne 1 ]; then
exit
fi
# print header
printf "PID\tVmPeak\tVmSize\tVmHWM\tVmRSS\n"
# get memory size
pid=\`pgrep \$1\`
for p in \$pid
do
if [ -f /proc/\$p/status ]; then
vm=\`grep -e '^VmPeak:\|VmSize:\|VmHWM:\|VmRSS:' /proc/\$p/status | awk '{print \$2}'\`
printf "%d\t%d\t%d\t%d\t%d\n" \$p \$vm
fi
done
_EOF_
sh getmem.sh httpd
PID VmPeak VmSize VmHWM VmRSS
2193 307688 307688 11828 11828
2194 307708 307688 6096 6096
2195 307708 307688 6096 6096
2196 307708 307688 6096 6096
2197 307708 307688 6096 6096
2198 307708 307688 6096 6096
getshmem.sh
cat << _EOF_ > getshmem.sh
#!/bin/sh
# \$1 process name
if [ \$# -ne 1 ]; then
exit
fi
# print header
printf "PID\tRSS\tSHARED\n"
# get shared memory size
pid=\`pgrep \$1\`
for p in \$pid
do
if [ -f /proc/\$p/smaps ]; then
vm=\`grep -e '^Rss:\|^Shared_Clean:\|^Shared_Dirty:' /proc/\$p/smaps |
awk '
BEGIN {
rss = 0;
clean = 0;
dirty = 0;
}
{
if(\$1 == "Rss:") {
rss += \$2;
}
else if(\$1 == "Shared_Clean:") {
clean += \$2;
}
else if(\$1 == "Shared_Dirty:") {
dirty += \$2;
}
}
END {
per = (rss == 0) ? 0 : (clean+dirty)*100/rss;
printf("%d\t%d\t%d\n", rss, clean+dirty, per);
}
'\`
printf "%d\t%d\t%d (%d%%)\n" \$p \$vm
fi
done
_EOF_
sh getshmem.sh httpd
PID RSS SHARED
2193 11832 8368 (70%)
2194 6208 6012 (96%)
2195 6208 6016 (96%)
2196 6208 6016 (96%)
2197 6208 6016 (96%)
2198 6208 6016 (96%)
smaps.sh
hollyなblog:2010-09-23の技術こねた
シェルスクリプト版。Perl も Linux::Smaps も不要。
単位としてKB、項目としてVSZ(Virtual Memory Size)が追加されている。
cat << _EOF_ > smaps.sh
#!/bin/sh
echo -e "PID\tVSZ\t\tRSS\tShared"
for pid in \$@; do
smaps="/proc/\$pid/smaps"
vsz=\$(grep -E "^Size" \$smaps | awk 'BEGIN{ num = 0 } { num += \$2 } END{ print num }')
rss=\$(grep -E "^Rss" \$smaps | awk 'BEGIN{ num = 0 } { num += \$2 } END{ print num }')
shared=\$(grep -E "^Shared" \$smaps | awk 'BEGIN{ num = 0 } { num += \$2 } END{ print num }')
percent=\$(echo "scale=2; (\$shared / \$rss) * 100" | bc | cut -d "." -f 1)
echo -e "\$pid\t\${vsz}KB\t\${rss}KB\t\${shared}KB(\${percent}%)"
done
_EOF_
sh smaps.sh `pgrep httpd`
PID VSZ RSS Shared
4847 232840KB 8272KB 6180KB(74%)
4876 232840KB 5544KB 5292KB(95%)
4935 232840KB 5544KB 5292KB(95%)
4976 232840KB 5544KB 5292KB(95%)
4999 232840KB 5544KB 5292KB(95%)
none_shared_memory_fetcher.pl
Apacheとかforkしたプロセスのメモリチューニングに関するメモとスクリプト | hirobanex.net
VSZ の代わりに NONE_SHARED が計算、出力されている。
cat << _EOF_ > none_shared_memory_fetcher.pl
#!/usr/bin/env perl
use strict;
use warnings;
@ARGV or die "usage: %0 [pid ...]";
printf "PID\tRSS\tSHARED\tNONE_SHARED\n";
for my \$pid (@ARGV) {
open my \$fh, "< /proc/\$pid/smaps" or (warn \$! and next);
my @rows = <\$fh>;
my \$rss = mem_size_fetcher('Rss',@rows) or next;
my \$shared = mem_size_fetcher('Shared_Clean',@rows) + mem_size_fetcher('Shared_Dirty',@rows);
printf
"%d\t%d\t%d (%d%%)\t%d\n",
\$pid,
\$rss,
\$shared,
int((\$shared / \$rss) * 100),
(\$rss - \$shared),
}
sub mem_size_fetcher {
my (\$target,@rows) = @_;
my \$mem_size = 0;
for my \$row (@rows) {
my (\$mem) = \$row =~ /^\$target:\s*(\d+)/i;
\$mem_size +=(\$mem||0);
}
return \$mem_size;
}
_EOF_
perl none_shared_memory_fetcher.pl `pgrep httpd`
PID RSS SHARED NONE_SHARED
12538 3780 3072 (81%) 708
12540 3048 2836 (93%) 212
12541 3060 2840 (92%) 220
12542 3152 2908 (92%) 244
12543 3060 2840 (92%) 220
12544 3048 2836 (93%) 212
12545 3060 2840 (92%) 220
12546 3060 2840 (92%) 220
12547 3060 2840 (92%) 220
自動計算
get_max_client.php
apacheのMaxClientを算出するスクリプトを作った - webネタ
curl -sL https://raw.githubusercontent.com/ryoppy/Get-MaxClients./master/get_max_client.php | php
--------------------------------
memorySize / (rssAverage - shrAverage) = 1020076KB / (5673KB - 5364KB) = 3301
MaxClient maximum value is 3301.
--------------------------------
kenjis フォーク
curl -sL https://raw.githubusercontent.com/kenjis/Get-MaxClients./my_change/get_max_client.php | php
--------------------------------
rssAverage - shrAverage = (5673KB - 5364KB) = 309KB
memorySize / (rssAverage - shrAverage) = 1020076KB / 309KB = 3301
MaxClient maximum value is 3301.
--------------------------------
get_max_clients.sh
Apacheチューニング: MaxClientsに設定できる上限値を計算する - (DxD)∞
get_max_client.php のシェルスクリプト版。 $_MIN_MAX_CLIENTS
については以下の通り。
空きメモリ量からMaxClientsを算出しています。ただし、起動済みのApacheプロセスが使用しているメモリ量を考慮していないので不完全です。
cat << _EOF_ > get_max_clients.sh
#!/bin/bash
_PIDS=(\`pgrep httpd\`)
_PROC_COUNT=\${#_PIDS[@]}
_MEMORY_TOTAL=\`free | grep Mem | awk '{print \$2;};'\`
_MEMORY_FREE=\`vmstat -a | awk 'NR==3{print \$4+\$5;};'\`
_RSS_TOTAL=0
_SHARED_TOTAL=0
for _PID in \${_PIDS[@]}; do
_SMAPS=\`cat /proc/\$_PID/smaps\`
_RSS=\`echo "\$_SMAPS" | grep Rss | awk '{value += \$2} END {print value;};'\`
_SHARED=\`echo "\$_SMAPS" | grep Shared | awk '{value += \$2} END {print value;};'\`
_RSS_TOTAL=\`expr \$_RSS_TOTAL + \$_RSS\`
_SHARED_TOTAL=\`expr \$_SHARED_TOTAL + \$_SHARED\`
done
_RSS_AVERAGE=\`expr \$_RSS_TOTAL / \$_PROC_COUNT\`
_SHARED_AVERAGE=\`expr \$_SHARED_TOTAL / \$_PROC_COUNT\`
_PROC_MEMORY=\`expr \$_RSS_AVERAGE - \$_SHARED_AVERAGE\`
_MIN_MAX_CLIENTS=\`expr \$_MEMORY_FREE / \$_PROC_MEMORY\`
_MAX_MAX_CLIENTS=\`expr \$_MEMORY_TOTAL / \$_PROC_MEMORY\`
echo "Memory Total / (Rss Average - Shr Average) = \$_MEMORY_TOTAL / (\$_RSS_AVERAGE - \$_SHARED_AVERAGE)"
echo "Memory Free / (Rss Average - Shr Average) = \$_MEMORY_FREE / (\$_RSS_AVERAGE - \$_SHARED_AVERAGE)"
echo "MaxClients = \$_MIN_MAX_CLIENTS ~ \$_MAX_MAX_CLIENTS"
exit 0
_EOF_
sh get_max_clients.sh
Memory Total / (Rss Average - Shr Average) = 1020076 / (3626 - 3263)
Memory Free / (Rss Average - Shr Average) = 635560 / (3626 - 3263)
MaxClients = 1750 ~ 2810