ps -o args -p <pid>
コマンドの1つが奇妙な問題に遭遇しました。非常に時々そのプロセスがそのサーバーで確実に実行されているにもかかわらず、そのプロセスが見つかりません。これらのプロセスは、特定のJavaアプリケーションを実行するために使用される長期実行ラッパースクリプトです。
「野生」で発生する問題は常に早朝に発生しているように見えるため、サーバーの負荷がかなり重いため、サーバーのディスク負荷に関連しているという証拠がありますps
。問題は繰り返すことができます。数百回ごとにエラーが発生するので実行します。
次の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.out
との出力を比較すると、実行時に失敗したシステムコールがシステムの実際のプロセス数よりはるかに小さい数を返すことがgood.out
わかります(〜1100と比較して約〜500)。getdents
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
ラッパーをチェックする制御スクリプトを変更して、全体に絆創膏を貼り付けようとするところに達しました。最初に失敗した場合は、2番目の呼び出しが疑われますが、ps
ここで何が起こっているのか知っている人がいるかどうかを知りたいです。
問題のシステムはCentOS 7およびprocps-ngバージョン3.3.10-17.el7_5.2.x86_64でカーネル4.16.13-1.el7.elrepo.x86_64を実行しています。
答え1
/proc
を介さずにファイルシステムから直接必要な情報を読むことを検討してください。空白の代わりにNULバイトで区切られたps
ファイルで探している情報( "args")を見つけることができます。/proc/$pid/cmdline
この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
競合条件のために、PIDリストが既存のPIDを見逃す可能性があることは少なくとも合理的であると思います。/proc
これはLinuxカーネルのソースコードを調べて確認できますが、まだやっていないので、説明したように、長期実行プロセスを見逃す可能性がある競合状態があるかどうかは実際にはわかりません。
他の部分はps
動作方法です。パラメータを使用して単一のPIDを渡しても、-p
単一のPIDにのみ興味がある場合でも、既存のすべてのPIDが引き続き一覧表示されます。この場合、ショートカットを使用してアイテムのリストをスキップし/proc
てすぐに移動できます/proc/$pid
。
なぜこのように実装されたのか言うことはできません。たぶん、ほとんどのps
オプションはプロセスの「フィルタ」なので、-p
同じ方法で実装する方が簡単です。ショートカットを直接使用すると、別のコードパスまたはコードの重複が含まれる可能性があります...別の仮説は次のとおりです。プラスを/proc/$pid
含むいくつかの状況-p
最終的に追加のオプションをリストする必要があるため、特定の状況でショートカットを許可し、どの状況を許可しないかを決定するのは複雑な場合があります。
/proc/$pid
これにより、システムの完全なPIDセットを一覧表示せずにすぐに開始し、すべての既知の競合を回避し、ソースから直接必要な情報を取得する解決策を見つけることができます。
少し醜いが説明する問題が存在し、その情報を取得する信頼できる方法でなければなりません。