Linux

committedが増えていく

ErogameScapeでは各種リソースをmuninで監視しています。
ある日からmemoryのcommittedが着々と増えていきました。
memory
committedがなんなのかをググってもよくわからなかったことと、増えててもサーバーの動作に支障が無いのでそのうち直るかな…と思って放置していました。
メモリを使いそうなのは
  1. PostgreSQL
  2. apache
  3. php
なので、それぞれ再起動してみるもNGでした。
ある日、たまたまスレッド数の画面を見たときに、スレッドも激増していることに気がつきました。
日単位で見ると、ゆるやかに増えているので気がつかなかったのですが、週単位/月単位で見ると激増していることがわかります。
threads
そこでスレッドの状態を確認しました。
# ps_aux_-L

中略

root     27385 27385  0.0    1  0.0 139800   260 ?        S    Sep02   0:00 CROND
ap2      27390 27390  0.0    1  0.0 299400   544 ?        Ss   Sep02   0:00 rsync -aurptz -e /usr/bin/ssh --exclude *~ --delete /home/ap2/public_html ap2@192.168.0.13:/home/ap2
ap2      27395 27395  0.0    1  0.0  60028  1364 ?        S    Sep02   0:00 /usr/bin/ssh -l ap2 192.168.0.13 rsync --server -ulogDtprze.iLs --delete . /home/ap2
root     27464 27464  0.0    1  0.0 139800   628 ?        S    Sep10   0:00 CROND
ap2      27469 27469  0.0    1  0.0 301576  5164 ?        Ss   Sep10   0:00 rsync -aurptz -e /usr/bin/ssh --exclude *~ --delete /home/ap2/public_html ap2@192.168.0.13:/home/ap2
ap2      27473 27473  0.0    1  0.0  60028  2264 ?        S    Sep10   0:00 /usr/bin/ssh -l ap2 192.168.0.13 rsync --server -ulogDtprze.iLs --delete . /home/ap2

以下、いっぱい、繰り返し

中略
ErogameScapeでは、メインのサーバーにスクリプト等をアップロードして、待機系のサーバーにはcronで定期的にrsyncでコピーする、ということをしています。
このrsyncが大量に動いているのか…ゴミとして残っているのか…していました。
手動でrsyncを実行したところ、エラーが滅茶苦茶でて、いっこうにrsyncが終わらないことを確認しました。
rsyncを実行するけど終わらなくて、次のrsyncが実行されて終わらなくて、というのが積み重なっていた模様です。
rsyncを全部殺して、エラーがでないようにrsyncのコマンドを見直して回復しました。 memory2
その後、muninの他のグラフを見たところ、プロセス数も日単位で見るとゆるやかに増えており、週/月単位で見ると激増していたので、閾値をもうけて通知するようにするか、週/月単位のグラフもたまに眺めるようにしないといけないな…と思いました。
processes

no server suitable for synchronization found

ある日、ntpdが時刻を上位サーバーから取れていないことが分かりました。
ErogameScapeではntpdの様子をmuninで監視しています。
以下に当時のmuninのグラフを示します。

ntp_offset-week

グラフの線があるところが上位のNTPサーバーから時刻を取得出来ているところ、線がないところは取得出来ていないところです。

ntpqコマンドの実行結果は以下の通りでした。
$ /usr/sbin/ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
 ntp01.****.**.j ***.***.***.***  2 u  13h  512    0   43.504   -8.250   0.000
 ntp02.****.**.j ***.***.***.***  2 u  10h 1024    0   16.760    0.650   0.000
 ntp03.****.**.j ***.***.***.***  2 u  11h  512    0   23.520   -0.850   0.000
あるべき姿は、いずれかの行の先頭に*があることです。
正常な場合のコマンドの結果は以下の通りです。
$ /usr/sbin/ntpp -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
+ntp01.****.**.j ***.***.***.***  2 u  139   64  144   10.949  -294.17  46.238
*ntp02.****.**.j ***.***.***.***  2 u  334   64  140   11.410  -292.78  14.636
 ntp03.****.**.j ***.***.***.***  2 u  330   64  140   15.319  -275.40  20.041

とりあえず、ntpサーバーを再起動すると、INITのままで、だいぶ時間がたっても、3つすべてINITのままとなるか、やっと1つだけ繋がる状態でした。
# /usr/sbin/ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
 ntp01.****.**.j .INIT.          16 u    -   64    0    0.000    0.000   0.000
*ntp02.****.**.j ***.***.***.***  2 u   49   64    1    9.308    0.609   0.000
 ntp03.****.**.j .INIT.          16 u    -   64    0    0.000    0.000   0.000
通常はすぐにすべてrefidの部分はINITでなくなるはずなのです…
ntpdを止めて、ntpdateを実行してみると以下のようになりました。
# /usr/sbin/ntpdate -b ntp01.****.**.jp
 2 Feb 22:17:44 ntpdate[32505]: no server suitable for synchronization found
ntpdateもntpdもUDPの123番ポートを使ってNTPサーバーに問い合わせに行きます。
宛先ポートも123番、送信元ポートも123番です。

ntpdateコマンドは-uオプションをつけると非特権ポート…1024番以降のポートを送信元として問い合わせを実施します。-uオプションを使ってntpdateを実行すると、時刻が取れました。
# /usr/sbin/ntpdate -b -u ntp01.****.**.jp
 2 Feb 22:17:36 ntpdate[32493]: step time server ***.***.***.*** offset -0.007014 sec
自身のNW機器は特に変更していないので…一応、NW機器が悪さをしている可能性もあるので、PPPoEルータを再起動しましたが、疎通はNG、iptablesも外してみましたが疎通はNGでした。
おそらくになるのですが、プロバイダからこちらのNW向けのUDPの123番ポートが微妙に閉じられている…微妙というのは、グラフを見る限りたまに繋がったりしているので、動的に123番ポートが閉じたり開いたりしているのかもしれません。

ntpdは自身が使用するポート番号を変更できない…ソースを変更してコンパイルすれば出来るようなのですが、それはしたくないなあ…と思いました。

ntpdのかわりにchronydというNTPサーバーがあり、こちらは自身のポートは123番ポートを使用しない…おそらく非特権ポートを使うので、乗り換えることにしました。

chronydについては以下のドキュメントがいいかなと思います。
chronydを使って無事時刻を取得できるようになりました。

ちなみに、ntpdateのデバッグモードである-dオプションをつけると、ちゃんと時刻が取得できるように見えてしまうので、とても悩みました。
おそらく-dオプションをつけた場合、送信元ポートは123番ではなく、非特権ポートを使うのかな…と思います。
# /usr/sbin/ntpdate -d time1.google.com
 1 Feb 20:52:36 ntpdate[17925]: ntpdate 4.2.6p5@1.2349-o Tue May 31 10:09:22 UTC 2016 (1)
Looking for host time1.google.com and service ntp
host found : time1.google.com
transmit(216.239.35.0)
receive(216.239.35.0)
transmit(216.239.35.0)
receive(216.239.35.0)
transmit(216.239.35.0)
receive(216.239.35.0)
transmit(216.239.35.0)
receive(216.239.35.0)
server 216.239.35.0, port 123
stratum 2, precision -20, leap 00, trust 000
refid [216.239.35.0], delay 0.20763, dispersion 0.00116
transmitted 4, in filter 4
reference time:    dc3c4a85.949cfffe  Wed, Feb  1 2017 20:52:37.580
originate timestamp: dc3c4a85.949d0001  Wed, Feb  1 2017 20:52:37.580
transmit timestamp:  dc3c4a85.76b5b1f9  Wed, Feb  1 2017 20:52:37.463
filter delay:  0.21288  0.21077  0.20763  0.21376 
         0.00000  0.00000  0.00000  0.00000 
filter offset: 0.022838 0.025773 0.025351 0.022737
         0.000000 0.000000 0.000000 0.000000
delay 0.20763, dispersion 0.00116
offset 0.025351

 1 Feb 20:52:37 ntpdate[17925]: adjust time server 216.239.35.0 offset 0.025351 sec

ソフトはソースからインストールしない

はじめに

CentOS等のパッケージ管理があるLinuxのディストリビューションにおいて、ソフトをソースからインストールするのは極力やめた方がよいです。
昔はそうでもなかったのですが、現在、たいていのソフトは新しいVerがでるとすぐにパッケージがリリースされますので、ソースからインストールしなければいけない場面は、そんなにない…と思います。

ソースからインストールしない方がよい理由は以下の通りです。
  • ソースからインストールしたソフトは、何がどこに入ったか、make installのログ等を追わないと分からない
  • インストールはmake insatllでめっちゃ簡単にインストールできるが、アントンストールは手動
  • パッケージ管理されているソフトと競合する

導入

サーバーにmemcashedをインストールしたのでmuninで監視することにしました。

memcashedをmuninで監視するはとても簡単…muninがインストールされていれば、多分デフォルトでmemcashed監視用のスクリプトがついてくるので、スクリプトにシンボリックリンクをはるだけ…なのですが、何を血迷ったのか、当時の私はmuninをソースからインストールするという手順を実行していました。

その結果
  • ソースからインストールしたmunin
  • パッケージを使ってインストールしたmunin
の2つがサーバーに混在することになりました。

/etc/init.d/munin-node start
すると、ソースからインストールしたmuninが起動します。

これはまずい…ということで、ソースからインストールしたmuninを削除するべく行動し始めました。


ソースからインストールしたソフトをアンインストールする

「ソースからインストールしたソフト アンインストール」でぐぐると
make uninstall
してみろ、そんなオプションがあったらラッキー、と書いてありました。
残念ながらmuninにuninstallというオプションはありませんでした。

インストールされたファイルを削除していく

find / -name munin
で、見つかったそれっぽいディレクトリを削除していきます。

rm -rf /opt/munin
rm -rf /opt/munin/log/munin
rm -rf /etc/opt/munin
rm -rf /var/opt/munin

そして、
/sbin/service munin-node start
Starting Munin Node: ERROR: Cannot open '/etc/opt/munin/munin-node.conf':  at /usr/sbin/munin-node line 60

パッケージでインストールしたmuninの設定ファイルは
/etc/munin/munin-node.conf

一方ソースからインストールしたmuninの設定ファイル
/etc/opt/munin/munin-node.conf 

/etc/munin/munin-node.confを見に行くように変更しなければいけません。
Starting Munin Node: ERROR: Cannot open '/etc/opt/munin/munin-node.conf':  at /usr/sbin/munin-node line 60
ですので、 /usr/sbin/munin-nodeのline 60を確認します。

/usr/sbin/munin-nodeを読む

munin-nodeは先頭行に
#!/usr/bin/perl -wT
と書いてあるperlのスクリプトです。

60行目の内容は以下の通りです。
$config->parse_config_from_file($conffile);

$conffileの定義は以下の通りです。
my $conffile   = "$Munin::Common::Defaults::MUNIN_CONFDIR/munin-node.conf";

$Munin::Common::Defaults::MUNIN_CONFDIRに/etc/opt/muninが入っているのですが、$Munin::Common::Defaults::MUNIN_CONFDIRがどこで定義されているか、さっぱり分かりませんでした。

/usr/sbin/munin-nodeにおいて、$Munin::Common::Defaults::MUNIN_CONFDIRの前に書いてある内容は以下の通りです。

use strict;
use warnings;

# Trust PERL5LIB from environment
use lib map { /(.*)/ } split(/:/, ($ENV{PERL5LIB} || ''));

use Getopt::Long;
use Munin::Node::Config;
use Munin::Common::Defaults;
use Munin::Node::OS;
use Munin::Node::Server;

my $servicedir = "$Munin::Common::Defaults::MUNIN_CONFDIR/plugins";
my $sconfdir   = "$Munin::Common::Defaults::MUNIN_CONFDIR/plugin-conf.d";
my $conffile   = "$Munin::Common::Defaults::MUNIN_CONFDIR/munin-node.conf";

Perlをちゃんと扱っている方であれば、
  • $ENV{PERL5LIB}はperl -e 'foreach(@INC){print "$_\n";}'で確認できる
  • $Munin::Common::Defaults::MUNIN_CONFDIRは、$ENV{PERL5LIB}に格納されているディレクトリの中にあるMunin/Common/Defaults.pmのour $MUNIN_CONFDIRに書いてある
ことを知っている…と思うのですが、そんなことを知らない私は$Munin::Common::Defaults::MUNIN_CONFDIRがどこで定義されているかに悩みました。

/usr/local/share/perl5/を消す

$ find / -name Munin
したら
/usr/share/perl5/vendor_perl/Munin/Common/Defaults.pm
/usr/local/share/perl5/Munin/Common/Defaults.pm
の2つがひっかかりました。

前者には
our $MUNIN_CONFDIR    = q{/etc/munin};
後者には
our $MUNIN_CONFDIR    = q{/etc/opt/munin};
と書いてあったので、後者がいらないと分かりました。

もう一つのサーバーとディレクトリの構造を見比べたら、もう一つのサーバーには、そもそも/usr/local/share/perl5/がなかった…つまりmuninをソースからインストールしたときに作られたディレクトリでしたので、ディレクトリごと削除しました。
※ソースからインストールすると/use/localにいろいろ入るので、ここを見てみるべきでした…というか、make installしたときのログを見ればよかったのですが…


$ perl -e 'foreach(@INC){print "$_\n";}'
/usr/local/lib64/perl5
/usr/local/share/perl5
/usr/lib64/perl5/vendor_perl
/usr/share/perl5/vendor_perl
/usr/lib64/perl5
/usr/share/perl5

なので、 /usr/share/perl5/vendor_perlよりも、/usr/local/share/perl5の方を先読みするということも確認できました。

この後、もう少し紆余曲折があった(muninのVerが2系になっていて、今使っている1系のrpmがなかなか見つからなかった)のですが、最終的に/sbin/service munin-node startできるようになりました。

以上で3時間かかりました。


学んだこと
  • ソースからインストールするとアンインストールが大変
  • パッケージでインストールされたソフトの設定ではなく、ソースからインストールしたソフトの設定が優先されることがある
  • Perlを知らないと困ることがある
  • 簡単な作業でも眠いときに作業しない

中井悦司 『プロのための Linuxシステム・10年効く技術』 技術評論社 2012 を読みました

プロのための Linuxシステム・10年効く技術を読みました。
発売時に買ったのですが、本が厚いし、内容が重そうなので、今まで放置していました。
最近、本を読むためのまとまった時間を確保できましたので、読みました。



とてもよい内容でした。買って良かったです。この本は3部作で、3部作の最後の本でしたので、他2冊も早速購入しました。いつ読めるか分かりませんが…

私は仕事でLinuxを使うことは一切なくて、ErogameScapeを運用するためだけにLinuxを使っています。
どの分野もそうですが、初心者向けの本はあふれかえっていますが、初心者からステップアップして次に読んだ方がいいという本はなかなかない…と思っています。

この本は、仕事でLinuxを使っていないから他人から学ぶ機会はないけど、Linuxを長年扱っている…方が読むととても知見に溢れていて学ぶ事が多いと思います。

以下、章立てと内容です。

第1章 知らないと損するぞ! 押さえておきたいLinux内部構造

「ディスク管理」「メモリ管理」「プロセス管理」について記載されています。今までなんとなくしか知らなかったことが「ああ、そうだったのか」とすっと入ってきます。他の章もそうですが、一つの項目が滅茶苦茶丁寧に書いてあることと、まるで説明を受けているかのような感覚になります。


第3章 10番勝負! 自作スクリプトでコマンド活用

Linuxを扱っているのであれば自作スクリプトを書くことはつまにあると思いますし、一度はbashの本を読んだりしているんじゃなかろうと思います。この章はスクリプトの書き方について、実践的にとても丁寧に説明がなされます。Linuxを私用で10年以上使っていますし、スクリプトの書き方の本も読んだ…あー、もう何年も前になりますが…のですが、「あー、そうやって書くのかー」とか「あー、そういう書き方もできるんだー」と発見がありました。

第4章 最後の砦! カーネルソースを読む

カーネルのソースを読むことは多分ない…と思いますが、カーネルに限らず何かのソースを読むことはあるのかなあと思います。PHPではじめてフレームワークを使ったとき、マニュアルに全部書いてあるわけじゃないので、フレームワークを使う際にはソースを読むことは必要かなと思います。
この章は、どうやってソースを読むのか?が非常に丁寧に書かれています。
よく「わからなかったらソースを読め」と書いてありますが、じゃあ具体的にどうやってソースを読むのか…というドキュメントはなかったんじゃなかろうか…と思います。
この章は、「ああ、こうやってソースは読むんだ…」ということが、よく分かります。
仕事で出来る先輩がいたら「どうやって読むんですか」と聞けますが、仕事でもないとなかなか聞く機会はないと思いますが、この章を読めばいけると思います。

第5章 一歩先を行く! RHEL6新機能の総まとめ

Upstartとanacron、この文書を読んで全貌を理解しました。
anacronは「なんかcrontabのところ見るとあるけど、なんなのかなー」程度にしか思っていませんでした…
PHPとかPostgtreSQLはVerUPのたびに、何が変わったのかを追っていますが、CentOSは何がかわったのか等を追っていなかったので助かりました…

本当に一つ一つの項目が丁寧で、まるで誰かに教えて貰っているような感覚に陥る本です。
お勧めです。
 

プロセス名を指定してプロセスをkillする方法について

例えばhttpをkillしたい場合は
pkill httpd
もしくは
killall  httpd

上記のような止め方をすることは通常ないと思いますが
/sbin/service httpd restart
で止めようとしても、止まらない状況が発生した場合…例えば、Apacheへの接続が多すぎてさばききれないとそうい状況に陥ります…は、上記コマンドで止めましょう。

killはたまに使うので覚えているのですが、pkill、killallは年に1回使うか使わないか程度なので、自分用に記録します。 

rm 引数リストが長すぎます

ログやキャッシュファイルなどを大量に削除しようとした際に
rm -f *
とすると
引数リストが長すぎます
と怒られます。
echo * | xargs rm
とすればよいのですが、そのディレクトリにファイルが大量にあったり(ErogameScapeは8万ファイルほどありました…)、もともとI/Oの負荷がそれなりにあると(そのマシンはPostgreSQLが動いていました)、I/O待ちでとんでもない負荷がかかります。

ちゃんと考えれば当たり前のことなのですが、コマンドを実行するまでまったく気がつかずにいました。

自分的に再発防止できるか微妙ですが気をつけようと思います…
記事検索