linuxでユーザごとにシステムリソースの制限をかける。
linuxでkernel単位でシステムリソースの制限をかける場合はこちらを参照のこと。
linuxサーバ構築時に設定が必須のパラメータと言えば/etc/sysctl.confである。
しかしここはカーネルパラメータを記述する設定ファイルであり、
つまりシステム全体で利用可能なリソースの制限を行うためのファイルである。
ユーザ単位での上限は変更できない。
ulimitコマンドを使えば設定を変更することができる。
サーバ再起動時には元に戻るので、設定を永続的にするためには、
/etc/security/limits.confに記述しておく必要がある。
サーバのチューニング時に必ずするポイントの一つだろう。
例としてファイルディスクリプタ数とプロセス数を30000に変更する。
◆ testというユーザの現在のシステムリソースの制限値を確認する
% su - test
% ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 4096
max locked memory (kbytes, -l) 32
max memory size (kbytes, -m) unlimited
open files (-n) 1024 ←ここを変更する(ファイルディスクリプタ)
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 1024
cpu time (seconds, -t) unlimited
max user processes (-u) 1024 ←ここを変更する(プロセス数)
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
◆ testユーザの制限を変更する
% ulimit -S -H -n 2048
-S : ソフトリミット
-H : ハードリミット
-n : ファイルディスクリプタ数
"ulimit -a"の結果からオプションは確認できる。"open files (-n)"
◆ testユーザの変更されたシステムリソースの制限値を確認する
% ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 4096
max locked memory (kbytes, -l) 32
max memory size (kbytes, -m) unlimited
open files (-n) 30000 ←変更されている
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 1024
cpu time (seconds, -t) unlimited
max user processes (-u) 30000 ←変更されている
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
◆ testユーザの制限をサーバの再起動時にも有効にする。
% su -
# cp /etc/security/limits.conf /etc/security/limits.conf.default
# vi /etc/security/limits.conf
test soft nofile 30000 ←ファイルディスクリプタのソフトリミット
test hard nofile 30000 ←ファイルディスクリプタのハードリミット
test soft nproc 30000 ←プロセス数のソフトリミット
test hard nproc 30000 ←プロセス数のハードリミット
limits.confの記載とulimitコマンド実行時の文言は下記のようになっている。
◆ limits.conf設定とulimitコマンド設定時のキーの対応表
limits.conf設定 ulmitコマンド表示
core limits the core file size (KB)
data max data size (KB)
fsize maximum filesize (KB)
memlock max locked-in-memory address space (KB)
nofile max number of open files
rss max resident set size (KB)
stack max stack size (KB)
cpu max CPU time (MIN)
nproc max number of processes
as address space limit (KB)
maxlogins max number of logins for this user
maxsyslogins max number of logins on the system
priority the priority to run user process with
locks max number of file locks the user can hold
sigpending max number of pending signals
msgqueue max memory used by POSIX message queues (bytes)
nice max nice priority allowed to raise to values: [-20, 19]
rtprio max realtime priority
追記
意図したlimitの設定通りに動作しない問題にぶつかった。
下も合わせて参照した方がいい。
コアダンプ(core dump)しない!!
2012年12月7日金曜日
kernelチューニング
linuxサーバのOS全体に効くカーネルパラメータのチューニング箇所と
その設定値、またその理由をまとめておく。
あくまで自分の環境ではこうした、というだけであり、
提供するサービスごとに検討が必要である。
どこをどう変更するのか、または変えないのか、その判断材料にはなるだろう。
※ユーザ単位でシステムリソースに制限をかける場合をこちらを参照してほしい。
以下は/etc/sysctl.conf で設定するものとする。
● 大規模サイト用チューニング
kernel.pid_max
動作:pidの最大数
設定値:131072
理由:pidを枯渇させない
vm.max_map_count
動作:mmapやmalloc時にメモリを仮想空間にマッピングできる最大ページ数
設定値:300000
理由:マッピングできなくなる事態を防ぐ
net.core.somaxconn
動作:接続(ソケット)キューの最大数
設定値:30720
理由:カーネルの処理能力以上のトラフィックが届いた場合にバッファをもたせる
net.core.netdev_max_backlog
動作:パケット受信時にキューにつなぐことのできるパケットの最大数
設定値:30720
理由:カーネルの処理能力以上のトラフィックが届いた場合にバッファをもたせる
net.ipv4.tcp_max_syn_backlog
動作:SYNに対するSYN/ACKの応答待ちに使うソケットの最大数
設定値:30720
理由:socketの枯渇を防ぐ
net.netfilter.nf_conntrack_tcp_timeout_established
動作:ESTABLISHEDかつIDLE状態でRESETパケットを投げ、リストから消すまでの時間(秒)
設定値:2000
理由:無駄なコネクションは長い時間保持しない
net.netfilter.nf_conntrack_max
動作:ESTABLISHEDのリストの最大数(iptablesの管理数)
設定値:1048576 ※1セッション350Bとし、メモリ1GB程度に抑える
理由:コネクションを保持できない事態を防ぐ
net.nf_conntrack_max
動作:ESTABLISHEDのリストの最大数(OS側の管理数)
設定値:1048576 ※1セッション350Bとし、メモリ1GB程度に抑える
理由:コネクションを保持できない事態を防ぐ
net.ipv4.tcp_keepalive_time
動作:keepaliveのタイムアウト時間(秒)
設定値:60
理由:socketの枯渇を防ぐ
net.ipv4.tcp_keepalive_intvl
動作:keepaliveのタイムアウト判定の再試行時間(秒)
設定値:2
理由:socketの枯渇を防ぐ
net.ipv4.tcp_keepalive_probes
動作:keepaliveのタイムアウト判定のリトライ回数
設定値:3
理由:socketの枯渇を防ぐ
net.ipv4.tcp_fin_timeout
動作:FINのタイムアウト時間(秒)
設定値:2
理由:socketの枯渇を防ぐ
vm.overcommit_memory
動作:実メモリ以上にメモリをプロセスに割り当てるオーバーコミットを許すかどうか
設定値:2 ※無効
理由:OOM killerを発生させたくない
vm.overcommit_ratio
動作:最大仮想メモリ領域 ※SWAP+(RSS*(この値/100)
設定値:95
理由:物理メモリを超えない範囲で少し余裕を持たせる
vm.swappiness
動作:実メモリがある状態でスワップを使うかどうか
設定値:0 ※無効
理由:実メモリを使い切るまでスワップは使わせない
vm.min_free_kbytes
動作:メモリのFREE領域の確保量
設定値:524288 (524288/1024 = 512MB)
理由:メモリ確保の容量を常にあけておく
net.ipv4.ip_local_port_range
動作:クライアントとして使用できるローカルポートの範囲
設定値:1024 65500
理由:サーバ発の通信対策
※以下は検討中
net.core.rmem_max
net.core.wmem_max
net.ipv4.tcp_rmem
net.ipv4.tcp_wmem
● IPv6対応の有無
net.ipv6.conf.all.disable_ipv6
net.ipv6.conf.lo.disable_ipv6
net.ipv6.conf.default.disable_ipv6
動作:IPv6周りの設定を有効にするかどうか
設定値:0 ※無効
理由:IPv6は使わない
● ハングアップ時の動作を規定
kernel.panic_on_oops
kernel.panic
kernel.softlockup_panic
kernel.hung_task_panic
動作:ハングアップ時にリブートさせるかどうか
設定値:1
理由:ハングアップしたらリブートさせる
● 設定の反映
変更を反映させる。
# sysctl -p
変更を確認する。
# sysctl -a
OS全体のカーネルチューニングの必要最小限な個所は以上ぐらいであろうか。
しかし、ユーザ単位でのシステムリソース制限も検討が必須である。
さらに、NICのリングバッファ(ring buffer)の設定値も見直した方がいい。
TSO(TCPsegmentation offload)、
GSO(Generic Segmentation Offload)
の扱いも考慮すべきである。
tcを利用したトラフィックコントロール内の
【TSO、GSOの扱い】章を参照。
2012年3月8日木曜日
コアダンプ(core dump)しない!!
コアダンプ(core dump)させる設定をしているにも関わらず、
プロセスが不正終了でダウンする時にコアを吐かなかった。
その原因を考えてみる。
◆ 前提
コアダンプの設定を確認する。
sysctl.conf にてコアファイルを生成するディレクトリと名前を決めている。
ディフォルトではプロセスのカレントディレクトリに作られるが、
専用のパーティションを作成している。
%pの位置にpid名を入れたいので、お尻に自動で付与されるpidは省略する。
SUIDされたプログラムもコアダンプさせたいため、最後の行を入れている。
# cat /etc/sysctl.conf
kernel.core_pattern=/var/core/%t-%e-%p-%c.core
kernel_core_uses_pid=0
fs.suid_dumpable=1
システム全体でコアダンプを有効にはしたくはない。
システムにログインするユーザが読み込むprofile内で無効化しておく。
# cat /etc/profile
ulimit -S -c 0 > /dev/null 2>&1
プロセスがデーモンとしてinitスクリプトで起動される場合も無効化しておく。
# cat /etc/sysconfig/init または /etc/sysconfig/デーモン名
#DAEMON_CORE_LIMIT='unlimited" ← 記載しない。ディフォルトは0。
コアを吐かせたいプロセスのみ、limits.confの設定で有効化する。システムにログインするユーザが読み込むprofile内で無効化しておく。
# cat /etc/profile
ulimit -S -c 0 > /dev/null 2>&1
プロセスがデーモンとしてinitスクリプトで起動される場合も無効化しておく。
# cat /etc/sysconfig/init または /etc/sysconfig/デーモン名
#DAEMON_CORE_LIMIT='unlimited" ← 記載しない。ディフォルトは0。
# cat /etc/security/limits.conf
test soft core unlimited
test hard core unlimited
※プロセスはtestユーザで起動するものとする。
# su - test
% ulimit -a
core file size (blocks, -c) unlimited
◆ 切り分け
設定は有効だが、起動しているプロセスがその設定を読み込んでいないのではないか。
既に起動しているプロセスの現在の設定を確認する。
プロセスIDはpsコマンドで確認してほしい。
$ cat /proc/プロセスID/limits
Limit Soft Limit Hard Limit Units
(略)
Max core file size 0 unlimited bytes
(略)
Hard limitはその値までSoft Limitを変更できるという制限値になる。
Soft Limitが0になっているので、これでは確かにコアダンプしない。
"ulimit -a"コマンドによる確認は今の該当ユーザの設定値がどうなっているか、である。
◆ 原因推測
limits.confの設定が読まれなかったことは間違いない。
(1) 推測1
limits.confの設定前にプロセスを起動させたのでは?
操作ログから、アプリケーションの起動前に設定済みであった。
(2) 推測2
limits.confが読み込まれない、もしくはその設定が上書きされる、
つまり別の設定が優先されるような起動手段をとったのでは?
いくつかある起動手段でlimits.confが読み込まれるかを確認する。
① サーバ起動シーケンスでプロセス起動
limits.conf の設定が使用される。
② suしてプロセス起動
limits.conf の設定が使用される。
③ cronでプロセス起動
limits.conf の設定が使用される。
④ ローカルからログインしてプロセス起動
limits.confの設定が使用されるがprofileの設定で上書きされる。
⑤ telnet、ssh等でリモートからログインしてそのまま(suしないで)プロセス起動
limits.confの設定が使用されるがprofileの設定で上書きされる。
※リモートからログインした後に、suすると②の通り再度limits.confの設定になる。
※PAMを利用するという前提である。
例えば、sshなら/etc/ssh/sshd_configファイル内でUsePAM行がyesの場合のみである。
◆ 結論
操作ログを確認すると、上の④なり⑤でプロセスを起動させていた。
/etc/profileファイルを確認する。
ディフォルトでコアを吐かない設定を入れていた。
# cat /etc/profile
ulimit -S -c 0 > /dev/null 2>&1
これが原因である。
limits.confで設定しており、④、⑤による起動手段をとる可能性があるのなら
コメントアウトしておけばいいだろう。
ただし、システム全体でコアダンプが有効になることに注意すること。
◆ 既に起動しているプロセスの設定を変えられるか
自分がログインしているbashなりのログインンシェルに対しては変更できる。
そのため、当然そのから新規に起動させるプロセスに対しても変更は効いてくる。
しかし、既に立ち上がっているプロセスのlimitsは残念ながら変えられない。
2012年1月15日日曜日
fsckの高速化
突然のサーバダウンなどで正常なシャットダウンシーケンスが走らなかった場合、
サーバ起動時にファイルシステムごとにfsckが実行される。
サービス影響が出ている場合、一刻も早く復旧したいのにも関わらず、
fsckに時間がかかり、もどかしい思いをしたことはないだろうか。
補足。正常なshutdownシーケンスが走る場合もfsckが動作することがある。それは設定による。
定期的に実行されるfsckを無効化にまとめているので参照してほしい。
今回はfsckを高速に実行させ、復旧までの時間を短縮させることを目的とする。
ここではファイルシステムはext3、ジャーナリングモードはext3のディフォルトであるorderedを想定している。
モードの説明についてはここを参照してほしい。
fsckの動作を理解しておかなければ高速化手法の検討はできない。
サーバ起動時にファイルシステムがマウントされるまでの動作を簡単におさらいしておく。
◆ サーバ起動時にファイルシステムがマウントされるまでの動作
ファイルシステムがマウントされるまでにどういった処理と判断がされるか順を追っていく。
(1) ファイルシステムの状態(クリーンフラグの有無)の確認
(1-a) ファイルシステムの状態がクリーン(clean)である場合
⇒ ファイルシステムはすぐにマウントされる。終了。
(1-b) ファイルシステムがクリーンではない(not clean)である場合
⇒ (2)以降の処理が走る。
クリーンフラグはファイルシステム単位で設定されている。
クリーンフラグはファイルシステムのスーパーブロック(ファイルシステムの構成に関する
情報が格納されているブロック)に存在している。
クリーンフラグがセットされていない場合にのみファイルシステムの修復が行われる。
手動で状態を確認することもできる。
既にマウントされている領域であれば当然cleanになっているだろう。
$ su-
# tune2fs -l /dev/sda1
Filesystem state: clean
シャットダウンシーケンスが走らずに終了した場合などは、状態がnot cleanとなっている。
(2) ジャーナルによるリカバリ(ジャーナリングを利用している場合のみ)
fsckがファイルシステムのチェックと修復前の前にジャーナルを確認する。
(2-a) ジャーナルで修復が終わった場合
⇒ ファイルシステムはマウントされる。終了。
(2-b) ジャーナルで修復が完了しなかった場合
⇒ (3)の処理(fsckによるPhase1からPhase5までの全ての処理)が実行される。
ジャーナルの説明はここを参照してほしい。
抜粋
『不正なシャットダウン時にfsckコマンドを実行する必要があるのは、
メタデータの整合性が保たれていない可能性があるからだ。
もし不正なシャットダウン時においてもメタデータの不正がないということが保証できれば、
fsckコマンドを実行する必要はない。そもそもファイルシステム全体に対するメタデータの
整合性のチェックをするのは無駄であり、不正なシャットダウン時には、
壊れた可能性のある部分だけをチェックすればよいのではないだろうか。
ジャーナリング内に何か残っていれば、ディスクへの書き込みに失敗した可能性が
あるということがわかる。このときジャーナリング内に記載された手順内容を見れば、
どのような操作をしたかがわかるから、壊れた可能性がある箇所がわかる。
よってその箇所だけを調査すればよい。
すなわち強制的に全メタデータを調査するfsckコマンドによるものと違い、
壊れた可能性がある箇所だけを調べることで、不正なシャットダウン後の
ディスクチェックの時間を高速化することができるというわけだ。』
(3) fsckによるファイルシステムのチェックと修復
fsckによるPhase1からPhase5までのファイルシステム全体に対するメタデータの
整合性のチェックがなされる。
ここまでくると復旧までに時間がかかることは覚悟しなければならない。
・ Phase1(Check Blocks and Sizes)
ブロックとサイズのチェックを行う。
ファイルシステムはファイルシステム全体をブロックグループに分けて管理するが、
そのブロックのサイズのチェックと、ブロックグループ0(先頭)にある
iノードのチェックを行う。
・ Phase2(Check Path names)
Phase1で見つかった不良iノードのチェックを行い、削除を実施する。
・ Phase3(Check Connectivity)
参照されないディレクトリがないか等、ディレクトリの構成のチェックを行う。
・ Phase4(Check Reference Counts)
参照されないファイルのチェック等、ファイルの参照チェックを行う。
・ Phase5(Check Cyl groups)
シリンダグループからi-nodeもしくはブロック構成のチェックを行う。
以上を踏まえどうすればfsckにかかる時間を短縮できるか考えてみる。
◆ 高速化の検討
サーバ起動時にファイルシステムがマウントされるまでの動作を(1)から(3)まで見てもらった。
(1)では何もできることはないだろう。
(2)でできることは、ジャーナリングのカスタマイズぐらいだろうか。
ただし、ジャーナリングが利用できる場合は復旧までにそれほで時間はかからないだろう。
(3)はどうだろうか。
この処理をしなければならないかどうかはもう運しだいなのだが、
やらざるを得ない最悪の事態を想定し、何かしらのアクションをとりたい。
例えばファイルシステムが10個あり、それぞれが数百GBもあったらどれほど時間がかかるだろうか。
想像するだけで恐ろしくなる。
仮に一つのファイルシステムのfsckが1時間かかれば合計で10時間である。
だからといって、fsck自体を簡略化することはコードを見直さない限り不可能である。
であるならば待つしかないだろうか。
シーケンシャルに動作するfsckを並列に動かせばいいのではないだろうか。
先ほどの10個のファイルシステムがある場合、システムが動作させる1つのfsckの裏で、
手動で同時に別領域をfsckできれば短縮できるはずである。
サーバの負荷をモニタしつつ何多重まで動かせるか決定すればよい。
手動でfsckが完了した領域をシステムもその後に2重でfsckかけるだろうが、
ファイルシステムの状態はすでにcleanになっているので即終了である。
ただしこれを実施するには、システムがクラスタを利用しており、
フェールオーバ先にログインできる、という条件が必要になるだろう。
スマートな手段を期待してここまで目を通してもらった方には申し訳ないが、
これが現実的に効果があり、かつ容易にできる方法ではないだろうか。
FSCK備忘録
Q. fsckが走っている領域を2重でFSCKかけた場合どうなるか?
A. 2重には実行できない。
システムがfsckしている箇所を手動で実行してしまうことを心配する必要はない。
2011年12月1日木曜日
TCP keepalive設定でハーフコネクションを解消
2台のサーバ間がTCPハーフコネクション状態になる事象が発生した。
TCP keepalive(キープアライブ)の設定でその状態を解消するための手段をメモしておく。
◆ 構成
サーバAとサーバB
◆ アプリケーション仕様
サーバAがサーバB上のファイルを定期的に取得する。
両サーバ間はTCPコネクションを張り続けている。通信ごとに接続する仕様ではない。
◆ トラブル
サーバBに障害が発生し、サーバBが突然ダウンした。
そのためサーバBからサーバAへのTCPのクローズ処理が行われず、
サーバAだけにTCPの状態がESTABLISHEDで残るハーフコネクションとなってしまった。
LANケーブルが抜けた場合なども同じ状態になるだろうか。
ハーフコネクションの有無は、サーバA、サーバBでそれぞれ
"lsof -n"、"netstat -an" などのコマンドを打ち、状態がESTABLISHEDになっている行で
対になっていないものがあるかどうかで確認できる。
サーバAはコネクションが残っていると思い込んでいるため、その経路を使おうとする。
しかしサーバB側では既にコネクションは維持されていないので接続できない。
TCPのオープン、クローズ処理に関しては下が参考になるだろう。
TCPのオープンとクローズ処理
TCPの状態遷移図
◆ 疑問
サーバAをサーバごと再起動(もしくはネットワークの再起動)すればハーフコネクションの状態からは復旧するだろう。しかし商用のサーバではそうそう再起動などかけられない。サーバは稼働し続けているという条件の元で、異常なハーフコネクションはいつまで続くのだろうか。
◆ 現在の設定値の確認
TCPキープアライブの設定周りを確認すればよいだろう。
まずはキープアライブプローブが送信される時間を確認する(単位は秒)。
これは接続がアイドル状態になってからである。つまり接続がアイドル状態でなければキープアライブプローブは送信されない。
# sysctl -a | grep tcp_keepalive_time
7200
相手からキープアライブ応答がなかった場合のキープアライブプローブの間隔を確認する(単位は秒)。
# sysctl -a | grep tcp_keepalive_intvl
75
キープアライブプローブの最大回数を確認する。
この回数だけ試しても接続先から反応が得られない場合に接続は切断される(単位は回)。
# sysctl -a | grep tcp_keepalive_probes
9
ディフォルト設定値では7200(秒)+75(秒)×9(回)の間はハーフコネクションの状態が続いてしまう。2時間以上というのは長すぎるだろう。
補足
sysctlコマンドで確認したものはサーバ起動時に読み込まれる設定であるため起動後に変更をしていれば現在の設定と相違がある可能性がある。grepした文言名で/proc/sys/net/配下あたりのファイルを見た方が正確だろう。
◆ 恒久的な設定変更
OS再起動時にも設定を有効にさせる。
# cp /etc/sysctl.conf /etc/sysctl.conf.YYYYMMDD
# vi /etc/sysctl.conf
net.ipv4.tcp_keepalive_time = 60
net.ipv4.tcp_keepalive_intvl = 3
net.ipv4.tcp_keepalive_probes = 3
変更を反映させる。
# sysctl -w
変更を確認する。
# sysctl -a
◆ 確認
発生した障害と同じ条件を作り、設定した時間でサーバAのハーフコネクションが切断されることを確認する。しかし、意図した時間が経ってもコネクションは切断されず、残り続けてしまった。
このページのUsing TCP keepalive under Linux の章を読み原因が分かった。
『Remember that keepalive support, even if configured in the kernel, is not the default behavior in Linux.
Programs must request keepalive control for their sockets using the setsockopt interface.
There are relatively few programs implementing keepalive,
but you can easily add keepalive support for most of them following the instructions explained later in this document. 』
つまり、アプリケーション側からカーネルのTCPキープアライブの設定をコントロールすることができるわけである。
こちらで使っているアプリケーションではキープアライブの設定を有効にするかどうかを
決めるコンフィグのキーが存在した。アプリケーションに依存する部分なのでどのキーかは記載しない。アプリケーションごとに仕様を確かめてほしい。
キープアライブを制御するようなコンフィグがなければ、ソースを見るしかないだろう。
setsockopt関数あたりで制御しているようである。
(参考)
カーネルパラメータのチューニング
2011年3月22日火曜日
32bit OSに物理メモリを大量に搭載させた場合の問題点
デーモンとして稼動していたプロセスがメモリ不足のためダウンする事象が発生した。
調査していくと、大量の物理メモリを搭載させた32bit OS特有の問題であることが判明した。
事象を整理しておく。
◆ 環境
x86アーキテクチャ 32bit OS
PAE対応kernel(kernel-smp 64G)
メモリ:24G (8プロセス × 3GB 用)
◆ 事象
OOM-Killer(Out of Memory Killer)が発生し、プロセスが強制終了させられた。
32bitOSで1プロセスが利用できるプロセス上限には達していなかった。
1プロセスが利用するメモリは3GB以下であった。
ログのエラー内容
$ cat /var/log/messages
09:00:01 XXXXX kernel: Normal free:3120kB min:3756kB low:4692kB high:5632kB
active:6068kB inactive:128kB present:901120kB pages_scanned:156118 all_unreclaimable?
09:00:01 XXXXX kernel: HighMem free:11078260kB min:512kB low:26348kB high:52188kB
active:12065708kB inactive:1043652kB present:24772604kB pages_scanned:0
all_unreclaimable? no
Normal(Low)ゾーンの最小値は3756kBである。
空き領域が3120kBと下回っていることから、Normalゾーンが不足していることが分かる。
原因はNormalゾーンの不足にあるようだ。
Normalゾーンとは何か。
原因を説明する前に32bit OSでのメモリのレイアウトについて簡単に説明しておく。
◆ メモリの予備知識
現在のメモリのレイアウトと使用状況は下で確認できる。
cat /proc/meminfo
meminfoから確認できるメモリ内訳は下の通りである。
MemTotal = MemFree + Active + Inactive + Slab + VmallocUsed + PageTables
Active + Inactive = AnonPages + Buffers + Cached + SwapCached
● MemTotal : システム全体で利用できる物理メモリの総容量(不変)。
● MemFree : システム全体で利用できる物理メモリの空き容量。
● Active : 最近アクセスした(とカーネルが思っている)物理メモリの容量。
● Inactive : 最近アクセスしていない(とカーネルが思っている)、
解放してよい物理メモリの容量。
● Slab : スラブアロケータで使用されている物理メモリの総容量。
● VmallocUsed : vmalloc()で確保された物理メモリ領域とMMCONFIGで確保している
メモリ領域の総容量。
● PageTables : ページテーブルエントリという「ページ」の管理構造体として
利用されているメモリ領域。
● AnonPages : 無名ページ(Anonymous Page)の領域。
ユーザープロセスがmalloc()などで確保したり、
プログラム本体用に利用するメモリ領域。
● Buffers : ファ イルなどのメタデータとして使用している物理メモリの総容量。
● Cached : ファ イルデータのキャッシュなどに使用している物理メモリの総容量。
共有メモリは Cached に加算される。SwapCachedは含まない。
そして、x86アーキテクチャ(32bit)にのみ存在する概念が以下である。
● LowTotal : Normal(Low)ゾーンにある物理メモリの容量。
● HighTotal : Highゾーンにある物理メモリの容量。
MemTotal = LowTotal + HighTotal
x86_64アーキテクチャ(64bit)の場合は、すべてのメモリがLow側で扱われる。
では、High、Lowとは何か。
Linuxではプロセスごとに仮想メモリ空間を割り当てる。
各プロセスでは4Gバイトのメモリ空間を利用できるはずである。
しかし実際にプロセスが(ユーザーモードで)利用できるのは先頭から3Gバイトである。
残りの1Gバイトをカーネルが(カーネルモードで)利用するためである。
プロセスが利用する先頭から3Gバイトの領域をプロセス空間と呼び、
残りの1Gバイトの領域をカーネル空間と呼ぶ。
そしてそれぞれはHigh、Lowとも呼ばれる。
そして実は、カーネル空間が1GBをすべて使うわけではない。
1GBの内訳
● カーネル空間
カーネルが必要な実メモリに直接アクセスするためのマッピング領域。
最大で896MBである。
● Highmemアクセス領域
実メモリの大きさが896MBを超える場合、つまりストレートマッピング
できない実メモリ(Highmem)にアクセスるるための領域。
※
その他として、固定マップ領域もあるがここでの説明は割愛する。
プロセスが異なると仮想メモリ空間も異なる。
ただし、カーネル仮想空間の部分については全プロセスで共用される。
◆ 原因
物理メモリを増やしたことで、Normal(Low)領域が減少していた。
Low領域が減少する理由は2つある。
(1)
PTE(Page Table Entry)は、Linuxでは4KB単位でメモリーを管理している。
搭載メモリー量が大きくなれば管理領域のサイズも大きくなる。
管理領域はLowmem側に記録されるため、LowTotalの値が小さくなる。
物理メモリが4GBが増えるごとに、32MB程度のLowメモリが余分に
Highmemアクセス領域に確保される。
※
/proc/meminfo 内を見る限りでは、LowTotalが減った分、
HighTotalが増えているように見えるが、これは表示上の問題であろう。
論理的には、PAE(Physical Address Extension)対応のkernelは64GBのメモリを認識できる。
しかし、PTEの領域が巨大になり、Low領域のリソースが不足する。
現実的には、システムを安定動作させるために12GB未満の物理メモリで運用することが望まれる。
また下のデメリットを指摘しているサイトもあった。
PAE対応のkernelはそうでないkernelを使用した場合よりも、
最大で50%の性能低下があります。
これは、PAE対応のkernelでは、PTEの階層が1つ多いために、
TLBがミスヒットした場合の ペナルティーが大きいためです。
また、メモリを大量に管理しているため、TLBのヒット率そのものがあまり高くありません。
(2)
kernelのキャッシュ・バッファ用に確保されるLowメモリの増加
もう一つの理由がこれである。
物理メモリが4GBが増えるごとに、32MB程度のLowメモリが、
kernelキャッシュ・バッファ用にカーネル空間に余分に確保されていく。
物理メモリを増やし、プロセスも多く起動させたことで、
Kernel空間がメモリのLow領域を使いきり、KernelがOOM-Killerを発動した。
その際にプロセスの一つがkillされた。
どのプロセスを停止するかはKernelが決定する。
◆ 対策
物理メモリを減らさない、という条件で可能な対策を検討する。
(1)は対処療法である。
(2)、(3)、(4)、(5)はチューニングである。
(6)が根本解決である。
(1) 不要なプロセスを停止させ、Low空間をより多く確保する。
OOM-Killerが発動するまでの時間を延ばすだけで根本解決にはならない。
(2) Low領域が足りなくなった場合に、High領域を積極活用する。
チューニングキーのパラメータは3つあり、
それぞれ左から、DMA領域、Normal(Low)領域、High領域用の値になる。
パラメータ値の意味を下の例を使って説明する。
1GBのメモリを積んでおり、内訳は次の通りであるとする。
DMA(16MB)、Normal(784MB)、High(224MB)。
実際に物理メモリがどのような領域に分けられているかは、
起動時のメッセージから読み取れる(dmesgコマンドを使えばよい)。
さて、Normal領域が足りなくなったらどうなるか。
例えば、High領域からメモリが確保される。
224(MB) / 32(High領域のパラメータ) = 7(MB)
パラメータが小さいほど、各領域から転用される容量は増していくことが分かる。
現実的ではないが、パラメータを1にすれば、
特定の領域からメモリを100%確保できる。
● 現在値
cat /proc/sys/vm/lowmem_reserve_ratio
256 256 32
● 設定変更
echo "256 256 16" > /proc/sys/vm/lowmem_reserve_ratio
● 恒久設定
sysctl -w vm.lowmem_reserve_ratio = 256 256 16
● 問題点
各領域は元々意図に沿った用途があるわけで、
他の目的のために使い回すことで、その領域が今度は不足することが想定される。
(3) キャッシュ上でまだディスクに書き込まれていない領域(dirty領域)の割合を小さくし、解放を早める。
● 現在値
cat /proc/sys/vm/dirty_background_ratio
5 ← 単位は全物理ページに対する割合(%))
● 設定変更
echo 2 > /proc/sys/vm/dirty_ratio
● 恒久設定
sysctl -w vm.dirty_ratio=2
● 問題点
スループットの低下
(4) キャッシュ上に存在しているページの存在時間を短くし、ライトバックの頻度を早める。
● 現在値
cat /proc/sys/vm/dirty_expire_centisecs
2999 ← 単位はms
● 設定変更
echo "400" > /proc/sys/vm/dirty_expire_centisecs
● 恒久設定
sysctl -w vm.dirty_expire_centisecs=400
● 問題点
スループットの低下
(5) Cache領域の開放を早める。
Low、Highの両方の領域から解放可能なキャッシュメモリを解放する。
● 現在値
cat /proc/sys/vm/drop_caches
0
● 設定変更
ページキャッシュのみを解放したい場合
echo 1 > /proc/sys/vm/drop_caches
Slabキャッシュを解放したい場合
echo 2 > /proc/sys/vm/drop_caches
ページキャッシュとSlabキャッシュを解放したい場合
echo 3 > /proc/sys/vm/drop_caches
● 恒久設定
sysctl -w vm.drop_caches=XXX
● 問題点
スループットの低下。
キャッシュのヒット率が低ければ問題ないか。
(6) 64bitOSを使う
● 問題点
アプリケーションが対応していない場合がある。
補足だが、64bitOSに32bitのアプリケーションをインストールした場合は、
そのアプリケーションはどこまでメモリを使えるだろうか。
答えは4GBである。理由は以上を読んでもらえれば分かるだろう。
2011年1月17日月曜日
定期的に実行されるfsckを無効化
クラスタ構成を組んでいるシステムで、サーバに障害が発生しても、
fsckがかかりフェールオーバに時間を要することがある。
そのためいつfsckをさせるか検討しておく必要がある。
◆ fsckの動作基礎知識
(1) デバイスがmountされた状態でサーバがダウンすればfsckは必ず実行される。
(2) 正常なshutdownシーケンスが走った場合は、fsckが動作するかどうかは設定による。
(1)時のfsckは仕様がない。
しかしながら、サービスの提供が最優先時に(2)のfsckは不要であろう。
そこで今回は(2)の対応を検討する。
(1)のfsck必須時のfsck高速化の検討はここでしている。
◆ ファイルシステムをチェックする最大マウント回数の変更
・ 現在設定しているマウント回数の確認
# tune2fs -l $デバイス名 | fgrep 'Maximum mount count'
Maximum mount count: XX
tune2fsコマンドで確認できる項目はスーパーブロックに保存される。
ファイル管理されていると思ってさがしてしまったことがあるorz
・ 最大マウント回数(0回、つまりしない)の変更
# tune2fs -c 0 $デバイス名
Setting maximal mount count to -1
マウントしたままで設定変更可能かつ有効になる。
コマンド実行後に即設定は反映される。
・ 変更後の設定確認
# tune2fs -l $デバイス名 | fgrep 'Maximum mount count'
Maximum mount count: -1 ←こうなっていればよい
◆ ファイルシステムをチェックするインターバルの変更
・ 現在設定しているインターバルの確認
# tune2fs -l $デバイス名 | fgrep 'Check interval'
Check interval: XX s
マウントされた状態でインターバルの期間を迎えた場合は、
/var/log/messagesに警告が出るだけでfsckは実施されない。
ただし、デバイスがumountされ、mountされるタイミングでは実施される。
・ インターバル(0秒、つまりしない)の変更
# tune2fs -i 0 $デバイス名
Setting interval between checks to 0 seconds
マウントしたままで設定変更可能かつ有効になる。
コマンド実行後に即設定は反映される。
・ 変更後設定確認
# tune2fs -l $デバイス名 | fgrep 'Check interval'
Check interval: 0 ←こうなっていればよい
その他、コマンドもメモ。
◆ システム起動時のマウント前のfsckを強制
-Fオプションを付けてshutdownコマンドを実行する。
# shutdown -F -r now
fsckがかかりフェールオーバに時間を要することがある。
そのためいつfsckをさせるか検討しておく必要がある。
◆ fsckの動作基礎知識
(1) デバイスがmountされた状態でサーバがダウンすればfsckは必ず実行される。
(2) 正常なshutdownシーケンスが走った場合は、fsckが動作するかどうかは設定による。
(1)時のfsckは仕様がない。
しかしながら、サービスの提供が最優先時に(2)のfsckは不要であろう。
そこで今回は(2)の対応を検討する。
(1)のfsck必須時のfsck高速化の検討はここでしている。
◆ ファイルシステムをチェックする最大マウント回数の変更
・ 現在設定しているマウント回数の確認
# tune2fs -l $デバイス名 | fgrep 'Maximum mount count'
Maximum mount count: XX
tune2fsコマンドで確認できる項目はスーパーブロックに保存される。
ファイル管理されていると思ってさがしてしまったことがあるorz
・ 最大マウント回数(0回、つまりしない)の変更
# tune2fs -c 0 $デバイス名
Setting maximal mount count to -1
マウントしたままで設定変更可能かつ有効になる。
コマンド実行後に即設定は反映される。
・ 変更後の設定確認
# tune2fs -l $デバイス名 | fgrep 'Maximum mount count'
Maximum mount count: -1 ←こうなっていればよい
◆ ファイルシステムをチェックするインターバルの変更
・ 現在設定しているインターバルの確認
# tune2fs -l $デバイス名 | fgrep 'Check interval'
Check interval: XX s
マウントされた状態でインターバルの期間を迎えた場合は、
/var/log/messagesに警告が出るだけでfsckは実施されない。
ただし、デバイスがumountされ、mountされるタイミングでは実施される。
・ インターバル(0秒、つまりしない)の変更
# tune2fs -i 0 $デバイス名
Setting interval between checks to 0 seconds
マウントしたままで設定変更可能かつ有効になる。
コマンド実行後に即設定は反映される。
・ 変更後設定確認
# tune2fs -l $デバイス名 | fgrep 'Check interval'
Check interval: 0 ←こうなっていればよい
その他、コマンドもメモ。
◆ システム起動時のマウント前のfsckを強制
-Fオプションを付けてshutdownコマンドを実行する。
# shutdown -F -r now
2010年12月6日月曜日
NICのリングバッファ(ring buffer)拡張
サーバのNIC(eth0)にてRXのdroppedカウンタが増加していることに気がついた。
◆ 問題点
droppedが増えている。
droppedが増えている。
$ ifconfig
eth0 Link encap:Ethernet HWaddr 78:E7:D1:DE:AE:7A
UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1
RX packets:1229784925 errors:0 dropped:830 overruns:0 frame:0
TX packets:1527648296 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:3738595284 (3.4 GiB) TX bytes:1955713102 (1.8 GiB)
Interrupt:169 Memory:f4000000-f4012800
RX : Receive eXchange(受信)
TX : Transmit eXchange(送信)
受信側のリングバッファ(ring buffer)のサイズを上げることにする。
◆ 現在の設定確認
$ ethtool -g eth0
Ring parameters for eth0:
Pre-set maximums:
RX: 1020 ← ここまで上げられる
RX Mini: 0
RX Jumbo: 4080
TX: 255
Current hardware settings:
RX: 255 ← 現在値
RX Mini: 0
RX Jumbo: 0
TX: 255
-g : Queries the specified ethernet device for rx/tx ring parameter information.
バッファを領域がいっぱいになったあとは、名前のとおり、
古いデータを順次上書きするような循環バッファとして機能する。
リングバッファの現在の利用率を確認することは難しい。
NICドライバが管理する領域であり、OSからは確認できない。
◆ 設定の変更
さしあたり2倍程度にする(ルート権限が必要である)。
CPUの処理量の増加が増やすことのデメリットとしてあげられる。
CPUの処理量の増加が増やすことのデメリットとしてあげられる。
$ ethtool -G eth0 rx 512
-G : Changes the rx/tx ring parameters of the specified ethernet device.
設定変更後、一時的にNICのリセットが発生し、リンクのダウン・アップ(ただし瞬断)が発生した。
◆ 設定変更後の確認
$ ethtool -G eth0 rx 512
Ring parameters for eth0:
Pre-set maximums:
RX: 1020
RX Mini: 0
RX Jumbo: 4080
TX: 255
Current hardware settings:
RX: 512 ← 変更された
RX Mini: 0
RX Jumbo: 0
TX: 255
◆ 設定変更後の有効性確認
ドロップカウンタが増加し続けているか確認する。
リングバッファのサイズを変更するとカウンタは初期化される。
しばらく時間をおいて確認するも増加していない。
$ ifconfig
eth0 Link encap:Ethernet HWaddr 78:E7:D1:DE:AE:7A
UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1
RX packets:1229784925 errors:0 dropped:0 overruns:0 frame:0
TX packets:1527648296 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:3738595284 (3.4 GiB) TX bytes:1955713102 (1.8 GiB)
Interrupt:169 Memory:f4000000-f4012800
◆ 設定の永続化
設定を永続化させるために、下記ファイルにも記載しておく。
$ vi /etc/rc.d/rc.local
#!/bin/sh
ethtool -G eth0 rx 512
大規模なシステムを構築するなら下記も見直すことが必要である。
kernelチューニング
ユーザ単位でのシステムリソース制限
TSO(TCPsegmentation offload)、
GSO(Generic Segmentation Offload)
の扱いも考慮すべきである。
tcを利用したトラフィックコントロール内の
【TSO、GSOの扱い】章を参照。
ethtool -G eth0 rx 512
大規模なシステムを構築するなら下記も見直すことが必要である。
kernelチューニング
ユーザ単位でのシステムリソース制限
TSO(TCPsegmentation offload)、
GSO(Generic Segmentation Offload)
の扱いも考慮すべきである。
tcを利用したトラフィックコントロール内の
【TSO、GSOの扱い】章を参照。
2010年7月23日金曜日
iptablesのip_conntrackが上限に達した場合の対処方法
ログを確認していると何かエラーが出ていた
# tail -f /var/log/messages
ip_conntrack: table full, dropping packet
iptablesのセッション管理テーブル(ip_conntrack)が上限に達したようである
解消方法は二つ。
① ESTABLISHEDな状態を記録する期間を短くする
② ip_conntrackに記録できる上限数を上げる
【OSパラメータの変更作業】
◆ 現在の使用状況の確認
# cat /proc/sys/net/netfilter/nf_conntrack_count
# sysctl -a | grep nf_conntrack
net.netfilter.nf_conntrack_tcp_timeout_established = 432000 ← ①の対策
net.netfilter.nf_conntrack_max = 65536 ← ②の対策
net.nf_conntrack_max = 65536 ← ②の対策
正確には上は設定値なので、proc配下あたりの
該当キーを見た方がいいかもしれない。
# cat /proc/sys/net/~
◆ 設定ファイルの編集
# vi /etc/sysctl.conf
net.netfilter.nf_conntrack_tcp_timeout_established = 2000
net.nf_conntrack_max = 1048576
net.netfilter.nf_conntrack_max = 1048576
◆ 設定反映
# sysctl -p
◆ 事後確認
# sysctl -a | grep nf_conntrack
net.netfilter.nf_conntrack_tcp_timeout_established = 2000
net.netfilter.nf_conntrack_max = 1048576
net.nf_conntrack_max = 1048576
意外と見落としがちなポイントではないだろうか。
それ以外のチューニングすべき項目はこちらを参考にしてほしい。
また、iptables関係で、ここも気をつけるポイントだろう。
登録:
投稿 (Atom)