psが時々、有効なプロセスを*非常に*見つけられないことがありますか?


9

問題のサーバーで確実に実行されているにもかかわらず、ps -o args -p <pid>コマンドが問題のプロセスを見つけることができない場合があるという奇妙な問題に遭遇しました。問題のプロセスは、一部のJavaアプリの起動に使用される長期実行ラッパースクリプトです。

問題の「野生」の出現は、常に早朝に起きているように見えるので、それは彼らは非常に重く、その後ロードされているので、問題になっているサーバ上のディスク負荷に近い関連といういくつかの証拠は、しかし、実行することで、そこにあるps中をタイトなループで質問すると、最終的に問題を再現できます-数百回に1回実行するとエラーが発生します。

次のbashスクリプトを実行することで、失敗した実行と成功した実行の両方のstrace出力を生成できました。

while [ $? == 0 ] ; do strace -o fail.out ps -o args -p <pid> >/dev/null ; done ; strace -o good.out ps -o args -p <pid>

以下からの出力を比較するfail.outgood.out、私はそれを見ることができますgetdents何とか失敗し、実行上のシステムコールが(〜1100年と比較して〜500程度)システム上のプロセスの実際の数よりもはるかに小さい数を返します

grep getdents good.out
  getdents(5, /* 1174 entries */, 32768)  = 32760
  getdents(5, /* 31 entries */, 32768)    = 992
  getdents(5, /* 0 entries */, 32768)     = 0

grep getdents fail.out
  getdents(5, /* 673 entries */, 32768)   = 16728
  getdents(5, /* 0 entries */, 32768)     = 0

...そして、その短いリストには問題の実際のpidが含まれていないため、見つかりません。

このセクションは無視できます。ENOTTYエラーは、以下のdave_thompsonのコメントで説明されており、無関係です。

さらに、失敗した実行にはENOTTY、成功した実行では表示されないいくつかのエラーが発生します。私が見る出力の初め近く

ioctl(1、TIOCGWINSZ、0x7fffe19db310)= -1 ENOTTY(デバイスの不適切なioctl)ioctl(1、TCGETS、0x7fffe19db280)= -1 ENOTTY(デバイスの不適切なioctl)

そして最後に私はシングルを見ます

ioctl(1、TCGETS、0x7fffe19db0d0)= -1 ENOTTY(デバイスに不適切なioctl)

ioctl最後の失敗はps戻りの直前に発生しますがps、空の結果セットがすでに出力された後に発生するため、それらが関連しているかどうかはわかりません。私が持っているすべての失敗したstrace出力でそれらが一貫していることは知っていますが、成功したものには表示されません。

getdentsプロセスの完全なリストが時々見つからない理由がまったくわかりません。今、ラッパースクリプトをチェックする制御スクリプトを変更するだけで、全体のバンドエイドを平手打ちにするところに到達しましたps最初の1つが失敗した場合、2回目を呼び出す問題ですが、誰かがここで何が起こっているのか考えているかどうか知りたいです。

問題のシステムは、CentOS 7およびprocps-ngバージョン3.3.10-17.el7_5.2.x86_64でカーネル4.16.13-1.el7.elrepo.x86_64を実行しています。


1
参考までに、ioctlは端末設定の取得に関係しています(たとえば、最初の設定は行と列の数を見つけることです)。したがって、それらが失敗しているのは奇妙ですが、直接の原因ではない可能性があります。これはカーネルバグのように聞こえます...
derobert

2
OpenBSDのからの関連研究:https.www.google.com.tedunangst.com/flak/post/...
thrig

2
あなたは持っている>/dev/nullので、(ループ内)の呼び出しではなく、「良い」の呼び出し、FD 1.上ENOTTYを「失敗」に
dave_thompson_085

ああ、くそったれ。あのデイブを捕まえてくれてありがとう、それは確かにENOTTYsを説明している。
ジェームズ

この問題が発生しているのは私だけではありません。これを回避する方法は、コマンドが失敗した場合に再試行するtry-catchを使用することですが、それでも迷惑です:/
Josh Correia

回答:


7

/procなどのツールではなく、ファイルシステムから直接必要な情報を読み取ることを検討してくださいps。探している情報( "args")はfile内/proc/$pid/cmdlineにあり、スペースではなくNULバイトで区切られているだけです。

このsedワンライナーを使用して、プロセスの引数を取得できます$pid

sed -e 's/\x00\?$/\n/' -e 's/\x00/ /g' "/proc/$pid/cmdline"

このコマンドは次と同等です。

ps -o args= -p "$pid"

args=in psを使用すると、ヘッダーが省略されます。)

このsedコマンドは、最初に最後のNULバイトを探し、それを改行で置き換えます。その後、他のすべてのNULバイト(個々の引数を区切る)をスペースで置き換え、最後にと同じ形式を生成しますps


システム内のプロセスの一覧表示に関してps/proc、でディレクトリを一覧表示することによって行いますが、プロセスのps実行中にプロセスが開始および終了するため、その手順には固有の競合状態があり、実際に取得されるのはスナップショットではなく概算です。特に、結果psを表示するまでにすでに終了しているプロセスを表示したり、実行中に開始したプロセスを省略したりすることができます(ただし、の内容をリストしているときにカーネルから返されませんでし/procた)。

私は常に想定し、プロセスが前に存在している場合は、そのps開始され、それが行わだ後にまだそこにある、それは考えていない私は、それによって見逃されると仮定する他のプロセスの解約がたくさんあります場合でも、カーネルはそれらが常に含まれることになる保証します作成され、破壊されます。あなたが説明していることは、そうではないことを意味します。私はまだそれについて懐疑的ですが、ps動作方法に既知の競合状態があることを考えると、/procそれらの競合状態が原因で、PIDをリストすると既存のPIDが見落とされる可能性があると考えられます。

Linuxカーネルのソースをチェックすることでそれを確認することは可能ですが、私は(まだ)まだ行っていないため、このような競合状態が存在して長時間実行プロセスを逃すかどうかを実際に確認することはできません。あなたが説明します。


もう1つの部分はps動作方法です。-p引数付きの単一のPIDを渡しても、その単一のPID だけに関心がある場合でも、既存のすべてのPIDがリストされます。その場合は、間違いなくショートカットを使用して、にエントリをリストし/procて直接に移動することはできません/proc/$pid

なぜこのように実装されたのかはわかりません。最もので、おそらくpsオプションはプロセス上の「フィルター」、そう実装され-p、同じように簡単だったに直進するショートカットを取って/proc/$pid別のコードパスやコードの重複を伴うかもしれませんが...もう一つの仮説は、いくつかの例を含むことにある-pだろうプラス追加オプション最終的にはリストが必要になるため、ショートカットを許可できるケースとそうでないケースを正確に判断するのはおそらく複雑です。


これ/proc/$pidにより、システムのPIDの完全なセットを一覧表示せずに、に直接進み、既知の競合をすべて回避し、必要な情報をソースから直接取得することで、回避策に進みます。

それは少し見苦しいですが、あなたが説明する問題は確かに存在します。それはその情報を取得するための信頼できる方法であるべきです。


2
そのFilipeのおかげで、sedコマンドが便利なため(そして、スクリプトを/ proc内のみに表示するように変更しました)、psに「=」を追加するとヘッダーがドロップされることを認識していなかったので、賛成しました。なぜ/ procのリスト全体が表示されないのかについて本当に興味があるので、答えを受け入れませんでした。誰かが知っていることを願っています:)
James
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.