EBUG勉強会/20141115_httpdをスケールさせる
をテンプレートにして作成
Start:
#topicpath
*OpenBSDでhttpdをスケールさせる
RIGHT:川俣 吉広 ~
EBUG勉強会 @ 新潟, 2014/11/15
**発端
以前この勉強会で紹介した[[ウェブ/メルマガのサーバ>EBUG勉...
- トップページが「500 Internal Server Error」を表示してい...
- SSHでログインし、状況調査
-- httpd (Apache) の error_logを確認
---子プロセスが起動できなくなっている。
[Mon Nov 3 15:15:51 2014] [error] [client xxx.xxx.xxx.x...
unavailable: couldn't spawn child process: /var/www/d...
---静的なページは正常にアクセスできる
---ロードアベレージは、1時間平均で0.8~1.0, 瞬間最大で7...
---CPU usageはピークで85%程度
---スワップは0MB … 起動から一回も使われていない。
---ネットワークのスループットは10Mb/sを少し超える程度。
- ... CPU, メモリなどのリソースは枯渇していないが、プロセ...
- ... サーバは2台が並列稼動しているが、両方とも同様な状...
**応急対応
- /index.cgi を /index.html に変更 ~
→ User Agent によって、ケータイ端末をリダイレクトしていた。
- 以下のように設定値を変更し、httpdを再起動 ~
/etc/login.conf
default:\
:path=/usr/bin /bin /usr/sbin /sbin /usr/X11R6/b...
:umask=022:\
:datasize-max=512M:\
:datasize-cur=512M:\
:maxproc-max=256:\
:maxproc-cur=128:\
:openfiles-cur=128:\
:stacksize-cur=4M:\
:localcipher=blowfish,6:\
:ypcipher=old:\
:tc=auth-defaults:\
:tc=auth-ftp-defaults:
# www - resource definition for web processes
#
www:\
- :maxproc=512:\
+ :maxproc-max=384:\
+ :maxproc-cur=384:\
:tc=default:\
設定をチェックした段階では、defaultログインクラスではmaxp...
指定されているのに対し、wwwログインクラスではmaxproc指定...
上書きされているかどうか不明だったため、maxproc-max, maxp...
/var/www/conf/httpd.conf
# It is intended mainly as a brake to keep a runaway se...
# the system with it as it spirals down...
#
-MaxClients 256
+MaxClients 192
プロセス数の上限で制限がかかっていると仮定し、httpdのプロ...
子プロセス(*.cgi)の数を増やせるようにした。
→ 30分ほどで不具合は解消
- アクセスそのものが減少し
- 上記対策が効を奏した(かどうか、本当は不明)
**恒久対策
#ref(ProcessModel.jpg,wrap,around,right,70%)
状況をモデリングする
-httpdに関しては、最大でhttpd.confで定義されたMaxClients...
-そのhttpdのうちの幾つかがNp個の子プロセス(*.cgi)を起動す...
-httpdとその子プロセスの総数(Nh+Np)の上限が login.conf の...
→httpd.confのMaxClients、 login.confの maxprocを幾つにす...
#img(,clear)
----
#ref(0005mem.gif,wrap,around,left,70%)
設定値の算定
-プロセス一つ当り、どの程度メモリを消費するか。
-動作記録を基に概算する。~
... 11/8に使用メモリの大幅な変動がある。
これは設定変更の反映のためにhttpdの停止・起動を行ったため...
~
... サーバの実装メモリは4096MB~
~
... sysctlによりkern.bufcachepercentが75%に設定されている...
~
... 左のグラフをみると、httpdの停止時はhttpdプロセス約200...
~
... よって 4000*0.2 / 200 = 4。大体プロセス一個あたり4MB...
#img(,clear)
----
バッファキャッシュ3GBのうち、2GBを取り崩してhttpd用に割り...
2048 / 4 = 512
とりあえず、MaxClientを512、ワーストケースとして *.cgiが...
動作をみる。
**実施と検証
***httpd.conf、MaxClientsの設定
MaxClientを512にして実行
# /usr/sbin/httpd -u -DSSL
WARNING: MaxClients of 512 exceeds compile time limit of...
lowering MaxClients to 256. To increase, please see the
HARD_SERVER_LIMIT define in src/include/httpd.h.
#
httpd.confの設定値にかかわらず、MaxClientsは256を超えない...
ハードコーディングされている。(Apache 2.xでは、ServerLim...
設定可)
ということで
/* Limit on the total --- clients will be locked out if ...
* this are needed. It is intended solely to keep the s...
* when things get out of hand.
*
* We keep a hard maximum number of servers, for two rea...
* in case something goes seriously wrong, we want to st...
* short of actually crashing the machine we're running ...
* kernel table. Secondly, it keeps the size of the sco...
* enough that we can read the whole thing without worry...
* the overhead.
*/
#ifndef HARD_SERVER_LIMIT
#define HARD_SERVER_LIMIT 256
#endif
この部分変更してコンパイル
# cd /usr/src/usr.sbin/httpd
# make -f Makefile.bsdwrapper obj
# make -f Makefile.bsdwrapper clean
# CFLAGS="-DHARD_SERVER_LIMIT=4096" make -f Makefile.bsd...
:
:
# make -f Makefile.bsdwrapper install
# /usr/sbin/httpd -V
Server version: Apache/1.3.29 (Unix)
Server's Module Magic Number: 19990320:15
Server compiled with....
(略)
-D DYNAMIC_MODULE_LIMIT=64
-D HARD_SERVER_LIMIT=4096
-D HTTPD_ROOT="/var/www"
***login.confのmaxproc設定
#ref(loginclass.jpg,wrap,around,right,70%)
# www - resource definition for web processes
#
www:\
:maxproc-max=1024:\
:maxproc-cur=1024:\
:tc=default:\
この部分の課題 ... setuidした子プロセスについてはlogin cl...
~
(11/21, 後日検証した結果を追記)
#img(,clear)
***運用の監視
SAG(Server Activity Grapher)にプロセス数の項目を組み込ん...
#ref(0005procs.gif,wrap,around,right,70%)
#
# t0005 - executing every 5 minutes
#
# $Id: t0005,v 1.2 2004/05/17 01:21:52 cvs Exp $
(echo =dt $DAYTIME
echo =mem
cat /proc/meminfo
echo =end
echo =procs `sysctl -n kern.nprocs; pgrep httpd | wc -l`
echo =sensors `sysctl -n hw.sensors.cpu0.temp0`
) >> var/rl0005
この状況で様子を見る。
#img(,clear)
**さらに...
将来的にさらにプロセス数の増加が必要な場合を想定し、どの...
-httpd 2048程度に設定。~
... pgrep httpd | wc -l
--実際には1000少しまでしか設定できず。
--他アカウントでログイン不可となる。
-sysctl kern.maxproc が1310となっていた。
--増加させてみる。
# sysctl -w kern.maxproc=8192
# sysctl kern.maxproc
kern.maxproc=8192
--再試行
... pgrep httpd | wc -l
--プロセス数増えたが、設定値どおりにならず ... 2000弱 ~
httpdでやってるとかったるいので、簡単なスクリプト書いてテ...
maxchild-test.sh
#!/bin/sh
if [ "$1" = "" ]; then
childlevel=1
echo -n "forking "
else
childlevel=$((1+$1))
fi
echo -n " $childlevel"
if $0 $childlevel; then
:
else
echo "failed at $childlevel"
fi
実行結果
# ./maxchild-test.sh
forking 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54...
71 72 73 74 75 76 77 78 79 80 (略) 1856 1857 1858 1859 1...
1870 1871 1872 1873 1874^C/home/kaw/maxchild-test.sh[17]...
^C
#
このとき、syslog (/var/log/messages) に出力されることを発...
Nov 14 17:56:37 mediakaw /bsd: process: table is full
カーネル内を探す;
# grep -rs ': table is full' /usr/src/sys
Binary file /usr/src/sys/arch/i386/compile/GENERIC/bsd m...
Binary file /usr/src/sys/arch/i386/compile/GENERIC/subr_...
/usr/src/sys/kern/subr_prf.c: log(LOG_ERR, "%s: table ...
#
/usr/src/sys/kern/subr_prf.c内のtablefull関数が実行されて...
# grep -rs 'tablefull.*process' /usr/src/sys
/usr/src/sys/kern/kern_fork.c: ...
kern_fork.cの該当部分
if ((flags & FORK_THREAD) == 0) {
if ((nprocesses >= maxprocess - 5 && uid != ...
nprocesses >= maxprocess) {
static struct timeval lasttfm;
if (ratecheck(&lasttfm, &fork_tfmrat...
tablefull("process");
nthreads--;
return (EAGAIN);
}
nprocesses++;
maxprocessをどこで初期化しているか?
# grep -rs 'maxprocess.*=' /usr/src/sys
/usr/src/sys/conf/param.c:int maxprocess = NPROCESS;
NPROCESSは?
# grep -rs '#.*define.*NPROCESS' /usr/src/sys
/usr/src/sys/conf/param.c:#define NPROCESS (30 + 1...
ということで
-カーネルレベルでのプロセス最大数はsysctlのkern.maxprocで...
-ただし、kernel configのMAXUSERSで規定される「真の最大値...
この値はsysctlで変更不可(変更にはカーネルの再コンパイル...
** 11/21追記: login.confでのmaxproc設定関連について
前項「実施と検証」/「login.confのmaxproc設定」について示...
***調査方法
-3種類のログインクラスエントリ, class0, class1, class2を...
-class1, class2ともtcによりclass0の設定を引き継ぐようにす...
-ユーザアカウントuser1, user2を作成し、それぞれのログイン...
-user1, user2アカウントにログインし、ulimit にてmaxprocの...
***調査1: login.confの記述方法について
以下のケースAでは、ログインクラス class1 でログインした場...
さらに、ケースBではどうか。
ケースA
class0:\
:maxproc-cur=100:\
:maxproc-max=200:
class1:\
:maxproc=150:\
:tc=class0:
ケースB
class0:\
:maxproc=300:
class1:\
:maxproc-cur=150:\
:maxproc-max=250:\
:tc=class0:
結果:ケースA、ケースBのどちらでも、class1のログインクラ...
***調査2:
以下の設定で、user1 (ログインクラス:class1)からuser2 (ロ...
class0:\
:maxproc=200:
class1:\
:maxproc=225:
結果:class1の設定値に関係なく、class2の値が新規に設定さ...
***調査3:
ulimitの挙動について
:maxproc-cur=A:\
:maxproc-max=B:
上記のように記述した場合、ログイン直後の最大プロセス数はA...
シェルのビルトイン・コマンドulimit -pで変更する場合、
プロセス数を増加する方向には「Bを超えない範囲、かつ一回だ...
プロセス数を減少させる方向には何回でも可能。~
(以上の挙動は使用するシェルに依存する可能性あり)~
また、
:maxproc=C:
と記述した場合は、
:maxproc-cur=C:\
:maxproc-max=C:
と書いた場合と等価であり、上記のルールに従う。
----
#topicpath
End:
#topicpath
*OpenBSDでhttpdをスケールさせる
RIGHT:川俣 吉広 ~
EBUG勉強会 @ 新潟, 2014/11/15
**発端
以前この勉強会で紹介した[[ウェブ/メルマガのサーバ>EBUG勉...
- トップページが「500 Internal Server Error」を表示してい...
- SSHでログインし、状況調査
-- httpd (Apache) の error_logを確認
---子プロセスが起動できなくなっている。
[Mon Nov 3 15:15:51 2014] [error] [client xxx.xxx.xxx.x...
unavailable: couldn't spawn child process: /var/www/d...
---静的なページは正常にアクセスできる
---ロードアベレージは、1時間平均で0.8~1.0, 瞬間最大で7...
---CPU usageはピークで85%程度
---スワップは0MB … 起動から一回も使われていない。
---ネットワークのスループットは10Mb/sを少し超える程度。
- ... CPU, メモリなどのリソースは枯渇していないが、プロセ...
- ... サーバは2台が並列稼動しているが、両方とも同様な状...
**応急対応
- /index.cgi を /index.html に変更 ~
→ User Agent によって、ケータイ端末をリダイレクトしていた。
- 以下のように設定値を変更し、httpdを再起動 ~
/etc/login.conf
default:\
:path=/usr/bin /bin /usr/sbin /sbin /usr/X11R6/b...
:umask=022:\
:datasize-max=512M:\
:datasize-cur=512M:\
:maxproc-max=256:\
:maxproc-cur=128:\
:openfiles-cur=128:\
:stacksize-cur=4M:\
:localcipher=blowfish,6:\
:ypcipher=old:\
:tc=auth-defaults:\
:tc=auth-ftp-defaults:
# www - resource definition for web processes
#
www:\
- :maxproc=512:\
+ :maxproc-max=384:\
+ :maxproc-cur=384:\
:tc=default:\
設定をチェックした段階では、defaultログインクラスではmaxp...
指定されているのに対し、wwwログインクラスではmaxproc指定...
上書きされているかどうか不明だったため、maxproc-max, maxp...
/var/www/conf/httpd.conf
# It is intended mainly as a brake to keep a runaway se...
# the system with it as it spirals down...
#
-MaxClients 256
+MaxClients 192
プロセス数の上限で制限がかかっていると仮定し、httpdのプロ...
子プロセス(*.cgi)の数を増やせるようにした。
→ 30分ほどで不具合は解消
- アクセスそのものが減少し
- 上記対策が効を奏した(かどうか、本当は不明)
**恒久対策
#ref(ProcessModel.jpg,wrap,around,right,70%)
状況をモデリングする
-httpdに関しては、最大でhttpd.confで定義されたMaxClients...
-そのhttpdのうちの幾つかがNp個の子プロセス(*.cgi)を起動す...
-httpdとその子プロセスの総数(Nh+Np)の上限が login.conf の...
→httpd.confのMaxClients、 login.confの maxprocを幾つにす...
#img(,clear)
----
#ref(0005mem.gif,wrap,around,left,70%)
設定値の算定
-プロセス一つ当り、どの程度メモリを消費するか。
-動作記録を基に概算する。~
... 11/8に使用メモリの大幅な変動がある。
これは設定変更の反映のためにhttpdの停止・起動を行ったため...
~
... サーバの実装メモリは4096MB~
~
... sysctlによりkern.bufcachepercentが75%に設定されている...
~
... 左のグラフをみると、httpdの停止時はhttpdプロセス約200...
~
... よって 4000*0.2 / 200 = 4。大体プロセス一個あたり4MB...
#img(,clear)
----
バッファキャッシュ3GBのうち、2GBを取り崩してhttpd用に割り...
2048 / 4 = 512
とりあえず、MaxClientを512、ワーストケースとして *.cgiが...
動作をみる。
**実施と検証
***httpd.conf、MaxClientsの設定
MaxClientを512にして実行
# /usr/sbin/httpd -u -DSSL
WARNING: MaxClients of 512 exceeds compile time limit of...
lowering MaxClients to 256. To increase, please see the
HARD_SERVER_LIMIT define in src/include/httpd.h.
#
httpd.confの設定値にかかわらず、MaxClientsは256を超えない...
ハードコーディングされている。(Apache 2.xでは、ServerLim...
設定可)
ということで
/* Limit on the total --- clients will be locked out if ...
* this are needed. It is intended solely to keep the s...
* when things get out of hand.
*
* We keep a hard maximum number of servers, for two rea...
* in case something goes seriously wrong, we want to st...
* short of actually crashing the machine we're running ...
* kernel table. Secondly, it keeps the size of the sco...
* enough that we can read the whole thing without worry...
* the overhead.
*/
#ifndef HARD_SERVER_LIMIT
#define HARD_SERVER_LIMIT 256
#endif
この部分変更してコンパイル
# cd /usr/src/usr.sbin/httpd
# make -f Makefile.bsdwrapper obj
# make -f Makefile.bsdwrapper clean
# CFLAGS="-DHARD_SERVER_LIMIT=4096" make -f Makefile.bsd...
:
:
# make -f Makefile.bsdwrapper install
# /usr/sbin/httpd -V
Server version: Apache/1.3.29 (Unix)
Server's Module Magic Number: 19990320:15
Server compiled with....
(略)
-D DYNAMIC_MODULE_LIMIT=64
-D HARD_SERVER_LIMIT=4096
-D HTTPD_ROOT="/var/www"
***login.confのmaxproc設定
#ref(loginclass.jpg,wrap,around,right,70%)
# www - resource definition for web processes
#
www:\
:maxproc-max=1024:\
:maxproc-cur=1024:\
:tc=default:\
この部分の課題 ... setuidした子プロセスについてはlogin cl...
~
(11/21, 後日検証した結果を追記)
#img(,clear)
***運用の監視
SAG(Server Activity Grapher)にプロセス数の項目を組み込ん...
#ref(0005procs.gif,wrap,around,right,70%)
#
# t0005 - executing every 5 minutes
#
# $Id: t0005,v 1.2 2004/05/17 01:21:52 cvs Exp $
(echo =dt $DAYTIME
echo =mem
cat /proc/meminfo
echo =end
echo =procs `sysctl -n kern.nprocs; pgrep httpd | wc -l`
echo =sensors `sysctl -n hw.sensors.cpu0.temp0`
) >> var/rl0005
この状況で様子を見る。
#img(,clear)
**さらに...
将来的にさらにプロセス数の増加が必要な場合を想定し、どの...
-httpd 2048程度に設定。~
... pgrep httpd | wc -l
--実際には1000少しまでしか設定できず。
--他アカウントでログイン不可となる。
-sysctl kern.maxproc が1310となっていた。
--増加させてみる。
# sysctl -w kern.maxproc=8192
# sysctl kern.maxproc
kern.maxproc=8192
--再試行
... pgrep httpd | wc -l
--プロセス数増えたが、設定値どおりにならず ... 2000弱 ~
httpdでやってるとかったるいので、簡単なスクリプト書いてテ...
maxchild-test.sh
#!/bin/sh
if [ "$1" = "" ]; then
childlevel=1
echo -n "forking "
else
childlevel=$((1+$1))
fi
echo -n " $childlevel"
if $0 $childlevel; then
:
else
echo "failed at $childlevel"
fi
実行結果
# ./maxchild-test.sh
forking 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54...
71 72 73 74 75 76 77 78 79 80 (略) 1856 1857 1858 1859 1...
1870 1871 1872 1873 1874^C/home/kaw/maxchild-test.sh[17]...
^C
#
このとき、syslog (/var/log/messages) に出力されることを発...
Nov 14 17:56:37 mediakaw /bsd: process: table is full
カーネル内を探す;
# grep -rs ': table is full' /usr/src/sys
Binary file /usr/src/sys/arch/i386/compile/GENERIC/bsd m...
Binary file /usr/src/sys/arch/i386/compile/GENERIC/subr_...
/usr/src/sys/kern/subr_prf.c: log(LOG_ERR, "%s: table ...
#
/usr/src/sys/kern/subr_prf.c内のtablefull関数が実行されて...
# grep -rs 'tablefull.*process' /usr/src/sys
/usr/src/sys/kern/kern_fork.c: ...
kern_fork.cの該当部分
if ((flags & FORK_THREAD) == 0) {
if ((nprocesses >= maxprocess - 5 && uid != ...
nprocesses >= maxprocess) {
static struct timeval lasttfm;
if (ratecheck(&lasttfm, &fork_tfmrat...
tablefull("process");
nthreads--;
return (EAGAIN);
}
nprocesses++;
maxprocessをどこで初期化しているか?
# grep -rs 'maxprocess.*=' /usr/src/sys
/usr/src/sys/conf/param.c:int maxprocess = NPROCESS;
NPROCESSは?
# grep -rs '#.*define.*NPROCESS' /usr/src/sys
/usr/src/sys/conf/param.c:#define NPROCESS (30 + 1...
ということで
-カーネルレベルでのプロセス最大数はsysctlのkern.maxprocで...
-ただし、kernel configのMAXUSERSで規定される「真の最大値...
この値はsysctlで変更不可(変更にはカーネルの再コンパイル...
** 11/21追記: login.confでのmaxproc設定関連について
前項「実施と検証」/「login.confのmaxproc設定」について示...
***調査方法
-3種類のログインクラスエントリ, class0, class1, class2を...
-class1, class2ともtcによりclass0の設定を引き継ぐようにす...
-ユーザアカウントuser1, user2を作成し、それぞれのログイン...
-user1, user2アカウントにログインし、ulimit にてmaxprocの...
***調査1: login.confの記述方法について
以下のケースAでは、ログインクラス class1 でログインした場...
さらに、ケースBではどうか。
ケースA
class0:\
:maxproc-cur=100:\
:maxproc-max=200:
class1:\
:maxproc=150:\
:tc=class0:
ケースB
class0:\
:maxproc=300:
class1:\
:maxproc-cur=150:\
:maxproc-max=250:\
:tc=class0:
結果:ケースA、ケースBのどちらでも、class1のログインクラ...
***調査2:
以下の設定で、user1 (ログインクラス:class1)からuser2 (ロ...
class0:\
:maxproc=200:
class1:\
:maxproc=225:
結果:class1の設定値に関係なく、class2の値が新規に設定さ...
***調査3:
ulimitの挙動について
:maxproc-cur=A:\
:maxproc-max=B:
上記のように記述した場合、ログイン直後の最大プロセス数はA...
シェルのビルトイン・コマンドulimit -pで変更する場合、
プロセス数を増加する方向には「Bを超えない範囲、かつ一回だ...
プロセス数を減少させる方向には何回でも可能。~
(以上の挙動は使用するシェルに依存する可能性あり)~
また、
:maxproc=C:
と記述した場合は、
:maxproc-cur=C:\
:maxproc-max=C:
と書いた場合と等価であり、上記のルールに従う。
----
#topicpath
Page: