私は 小さなマルチプレイヤーカードゲーム ピーク時に約500人のユーザーで実行します:
クライアントはFlashで、サーバーはPerlです。
Perlサーバーはポート8080にバインドします。つまり、起動できるインスタンスは1つだけです(重要な詳細)。
PerlサーバーはTCPソケットとフォークを1回だけポーリングします-起動時に次のメソッドを呼び出します。
sub daemonize {
die "Can not fork: $!\n" unless defined (my $child = fork());
# the parent should die
exit 0 if $child;
setsid();
open(STDIN, '</dev/null');
open(STDOUT, '>/tmp/pref.txt');
open(STDERR, '>&STDOUT');
chdir('/');
umask(0);
}
....
$tcpSocket = IO::Socket::INET->new(Proto => 'tcp',
LocalPort => 8080,
Listen => SOMAXCONN,
ReuseAddr => 1,
);
die "Can not create listening TCP socket: $!\n"
unless defined $tcpSocket;
CentOS 5.6 Linux/64ビット、PostgreSQL 8.4.8、Perl5.8.8で動作します。
予算が少なく、すでに十分なトラブルが発生しているため、追加のソフトウェアをできるだけ少なくして、ホスティング業者を変更したり、安価なサーバーをすばやく再インストールしたりしたいと考えています。そのため、たとえば、syslog-ngをインストールする代わりに/tmp/pref.txtにログを記録します。そのため、Perlデーモンを再起動するために/ etc/inittabを使用したいと思います。
私のPerlデーモンはほとんど安定して動作しますが、約週に一度、
May 29 11:06:46 myhost kernel: pref.pl[3113]: segfault at 00007fffa21e6fd8 rip 0000003cce274460 rsp 00007fffa21e6fd0 error 6
サーバーを手動で再起動するのにうんざりしているので、サーバーを/ etc/inittabに追加しようとしました。
pref:3:respawn:/bin/su -c '/usr/local/pref/pref.pl' nobody
(そして、この方法でPerlを更新することを期待して、「pkill pref.pl」に毎晩cronジョブを追加しました)。
残念ながら、これは期待どおりに機能しません-/ var/log/messagesで、スクリプトが何度も開始されていることがわかります。
Jun 2 18:55:56 myhost init: Id "pref" respawning too fast: disabled for 5 minutes
Jun 2 19:00:58 myhost init: Id "pref" respawning too fast: disabled for 5 minutes
Jun 2 19:06:02 myhost init: Id "pref" respawning too fast: disabled for 5 minutes
私はここで何が間違っているのですか?ここで/ etc/inittabを使用できることを望んでいました。数年前に職場で同様の状況で使用したことを覚えており(Perlデーモンでも)、その後はうまく機能しました...
ありがとうございました!アレックス
更新:
私のゲームはクラッシュしていませんが、Perlインタープリターはクラッシュします(ただし、頻繁ではありませんが、週に1回)。
私の質問は、Perlデーモンを実行する方法についてです(つまり、最初に一度フォークしてからTCPポート)from/etc/inittab?
コードからfork()を削除するだけです。ここまでで、コンソールから切り離してバックグラウンドで実行するコードを作成しました。ただし、プロセスがinittabから実行される場合は、接続を維持する必要があります。 fork()を削除すると、initに接続されたままになり、initは適切に監視/開始/停止/再起動できるようになります。
私はあなたのinittabソリューションと話すことができません、うまくいけば他の誰かが話すことができますが、デーモン呼び出しの後にスクリプトに追加するものとして「File :: Pid」を見るように提案したいと思います(これは重要です-あなたのプロセスIDフォーク後に変更されます)。
use File::Pid;
my $pidfile = File::Pid->new({
file => '/var/run/myprogram.pid',
pid => $$,
});
if ( my $num = $pidfile->running ) {
exit;
}
$pidfile->write;
これにより、いくつかのことが得られます。1つは、2つのコピーを同時に実行しないようにすることです(これは大したことです)。また、単純なキープアライブを提供したいときはいつでも、このプログラムを安全に呼び出すことができます。 10分ごとにcronからコードを呼び出すだけで、実行中の場合は何も実行されず、ダウンしている場合は再起動します。