【図解】Linux straceの使い方|System Call・エラー・待ち時間を解析する方法

はじめに

Linux ServerでApplicationのResponse Timeが悪化したり、Processが応答しなくなったりした場合、topやpidstatを使うことでProcessのCPU使用率や状態を確認できます。

しかし、Processを特定できても、「そのProcessがLinux Kernelに何を要求し、どこで待機・失敗しているのか」までは分からないことがあります。Fileを開けない、Network接続に失敗する、I/OやThread Synchronizationを待っている、といった問題はCPU使用率だけでは判断できません。

このような場合に利用できるのがstraceです。straceを利用すると、Processが発行するSystem Callと受信するSignalをTraceし、Argument、Return Value、ErrorなどからProcessとLinux Kernelの境界で何が起きているかを確認できます。

本記事では、Linuxトラブルシューティング連載の第8回として、straceを使い、Process → System Call → Error / Wait → File / Network / Synchronizationと原因を深掘りする方法を解説します。

straceとは

straceは、Processが発行するSystem Callと受信するSignalをTraceするToolです。ApplicationのSource Codeを直接Debugしなくても、ProcessがLinux Kernelに対してどのような処理を要求しているかを観測できます。

System CallはUser SpaceのApplicationがLinux Kernelの機能を利用するためのInterfaceです。straceはApplication内部のFunctionそのものをTraceするToolではなく、ProcessとKernelの境界を観測するToolです。

分類代表的なSystem Call見るポイント
File / I/Oopenat() / read() / write() / fsync()File Access、Read / Write、同期
Networksocket() / connect() / sendto() / recvfrom()接続、送受信、Error
Wait / Eventfutex() / poll() / epoll_wait()Thread / Event待ち
Processclone() / execve() / wait4()Process / Thread生成、実行、終了待ち

straceによるトラブルシューティングの全体像

straceはProcess障害の最初に無条件で実行するToolではありません。まずtop、ps、pidstat、Application Logなどで対象を絞り、System Call Levelの確認が必要な場合に利用します。

重要なのは、straceだけでRoot Causeを断定するのではなく、System CallをEvidenceとして次に確認すべきLayerを絞ることです。

straceをインストールする

RHEL / AlmaLinux 9系ではstrace Packageをインストールして利用します。

# dnf install strace
$ strace --version

straceの基本的な使い方

Commandを指定してTraceする

新しくCommandを起動し、最初からSystem Callを確認する場合はstraceの後ろにCommandを指定します。

$ strace <command>

strace ls コマンドの表示例:

出力量は多くなるため、実際の障害調査では後述するFilterで対象を絞ることが重要です。

稼働中ProcessへAttachする

すでに稼働しているProcessをTraceする場合はPIDを指定します。

# strace -p <PID>

strace -p <PID> の出力例:

TraceはCtrl + C で終了できます。権限やSecurity設定によっては他ProcessへのAttachが制限される場合があります。

straceの出力を読む

System Call名だけでなく、Argument、Return Value、errnoを確認します。

openat の表示例:

項目意味見るポイント
openat()ファイルをOpenするSystem CallどのSystem Callが実行されているか
AT_FDCWD相対Pathの場合、現在のWorking Directoryを基準にする指定Pathをどこを基準に解決するか
"/etc/ld.so.preload"Open対象のFile PathApplicationがどのFileへAccessしているか
O_RDONLYRead OnlyでOpenRead / Writeなど、どのAccess Modeか
O_CLOEXECexec時にFile DescriptorをCloseする指定File DescriptorにどのFlagが指定されているか
= 3openat()の戻り値。この場合はFile Descriptor 3成功か失敗か。成功時はFile Descriptor、失敗時は通常-1とerrnoが表示される

Errorを確認する

Applicationが起動しない、Fileを読めない、接続できない場合はSystem CallのErrorが重要なEvidenceになります。

errno意味主な確認ポイント
ENOENTFile / Directoryが存在しないPath、設定ファイル、Mount
EACCESPermission deniedPermission、実行User、SELinuxなど
ECONNREFUSEDConnection refusedListen、Port、Firewall / Middlebox
ETIMEDOUTOperation timed outNetwork経路、接続先、応答
EAGAIN一時的に処理できないNon-blocking I/O、Resource状態、文脈

Error CodeだけでRoot Causeを断定しないことも重要です。たとえばECONNREFUSEDは接続先Applicationだけでなく、途中の機器などがResetを返すケースもあります。

straceでは、System Callが失敗すると通常= -1とerrnoが表示されます。まずどのSystem Callが、どのArgumentで、どのerrnoを返したかを確認し、具体的な調査はFile / I/OやNetworkなど該当するLayerへ進めます。

File / I/Oを調査する

File AccessやI/Oが疑われる場合はopenat()、read()、write()、fsync()などを確認します。System Call名だけでなく、Return Valueとerrno、さらに-Tで確認できる経過時間も合わせて見ます。

read()の戻り値を確認する

read()は戻り値によって、読み込めたByte数、EOF、Errorを区別できます。

read(3, "Hello Linux\n", 131072) = 12
read(3, "", 131072)             = 0
read(3, ..., 131072)            = -1 E...
戻り値意味見るポイント
> 0読み込んだByte数Dataを正常に読み込めている
0EOFFile終端など。Errorではない
-1Errorerrnoを確認する

fsync()のErrorを確認する

例えばfsync()がErrorになった場合、以下のようにReturn Valueとerrnoから失敗を確認できます。

straceでfsyncがEINVALを返した例

この例では/dev/nullに対してfsync()を実行し、意図的にEINVALを発生させています。実際のStorage障害を再現した例ではありません。実環境ではerrnoと対象File、File System、Storage側の状態を合わせて確認します。

read()やfsync()の完了に時間がかかっていても、straceだけでStorageが原因と断定してはいけません。straceで見えるのはProcessから見たSystem Callの挙動です。Block I/O側はiostatやpidstat -dなどで確認します。

Network接続を調査する

Network接続が疑われる場合はsocket()、connect()、sendto() / sendmsg()、recvfrom() / recvmsg()などを確認します。

connect()のReturn ValueからProcessが認識した接続結果を確認できます。

ncコマンドによる接続が失敗した例:

connect()で127.0.0.1の9999番ポートへのTCP接続を試みています。今回は接続先ポートで待ち受けているプロセスがないため、最終的にECONNREFUSEDが返され、Connection refusedとして接続に失敗しています。

なお、connect()のEINPROGRESSは接続失敗そのものではなく、非同期で接続処理中であることを示しています。その後のgetsockopt()でECONNREFUSEDを確認しているのがポイントです。

straceで見えるのはProcessから見たSystem Callの結果です。SYN / SYN-ACK / RST / RetransmissionなどPacket Levelの挙動はtcpdumpやWiresharkで確認します。

Processが何を待っているか確認する

CPU使用率が低いにもかかわらずResponseが遅い場合、ProcessやThreadがEventを待っている可能性があります。

System Call主な意味見るポイント
futex()Synchronizationに関連する待機Mutex / Condition Variableなど
poll() / ppoll()FDのEvent待ちSocket / Pipeなど
select()複数FDのEvent待ち対象FD、Timeout
epoll_wait()epoll Event待ち正常なIdle待機の場合も多い

futexやepoll_waitが表示されたからといって、それ自体が異常とは限りません。Server Applicationでは正常な待機の場合もあるため、Response TimeやThread状態、Application Logと組み合わせて判断します。

TraceするSystem Callを絞り込む

-e trace=を使うと、仮説に応じてTraceするSystem Callを限定できます。

# strace -e trace=openat,read,write -p <PID>
# strace -e trace=socket,connect,sendto,recvfrom -p <PID>

大量のSystem Callを眺めるのではなく、症状から仮説を立ててTrace対象を絞ることが重要です。一部だけをFilterした場合は、表示されていないSystem Callを含むProcess全体の動作を推測しすぎないようにします。

子Process / Threadを追跡する

子ProcessやThreadを生成するApplicationでは-fでfork / cloneなどにより生成されたTraceeも追跡できます。

# strace -f -p <PID>

Multi-process / Multi-thread Applicationでは出力量と負荷が増えるため、Filterと組み合わせます。

System Callにかかった時間を確認する

性能問題を調査する場合は、個々のSystem Callの経過時間を見る-Tと、System Callごとの統計を確認する-cを使い分けます。

Option確認できるもの向いている用途
-T個々のSystem Callの経過時間どの呼び出しで長く待っているか確認する
-cSystem Callごとの回数、Error、時間の統計System Call全体の傾向を把握する

-Tで経過時間を確認する

-Tは各System Callの開始から終了までの経過時間を、行末の<秒>で表示します。

以下では、openat()の経過時間を表示しています。

strace -Tでopenatの経過時間を確認した例

例えば<0.000013>なら、そのSystem Callの開始からReturnまで約13マイクロ秒かかったことを示します。長時間完了しないSystem Callを探す手掛かりになります。

ただし、System Callの経過時間が長いことと、その下位LayerがRoot Causeであることは同義ではありません。例えばread()が長時間化していても、File、Socket、Pipeなど対象FDによって待っているものは異なります。

-cでSystem Callを集計する

-cはSystem CallごとのCall回数、Error数、時間などを集計してSummary表示します。

# strace -c -p <PID>
# strace -c ls

lsコマンド実行時の集計値表示例:

strace -cでSystem Callを集計した例
項目意味見るポイント
% timestraceが集計したSystem Call時間全体に占める割合どのSystem Callが計測時間の大きな割合を占めたか
secondsそのSystem Callに費やされた集計時間System Callごとの時間を比較する
usecs/call1 Callあたりの平均時間(マイクロ秒)1回あたりの処理時間の目安
calls呼び出し回数大量に呼ばれているSystem Callを確認する
errorsErrorになった回数errnoを伴う失敗が多いSystem Callを確認する
syscallSystem Call名どの処理の統計か確認する

例えばwait4の% timeが65.25%なら、straceが集計したSystem Call時間全体のうち65.25%をwait4が占めたことを示します。Application全体のWall-clock実行時間の65.25%という意味ではありません。

また、-cの結果を単純な「待ち時間ランキング」と解釈しないことが重要です。個々のSystem Callが実際にどの程度の経過時間を要したかを調べる場合は、-Tの結果と組み合わせて確認します。

Trace結果をFileへ保存する

障害時のEvidenceとしてTrace結果をFileへ保存できます。

# strace -o /tmp/strace.log -p <PID>

Trace LogにはPath、接続先、Argument、場合によってはApplication Dataなど機密情報が含まれる可能性があるため、取扱いに注意してください。

straceを使ったApplication遅延のトラブルシューティング例

Web ApplicationのResponse Timeが悪化しているものの、CPU使用率は高くないケースを例に調査します。

① Processを特定する

# top
# pidstat -u -p <PID> 1

対象Processを特定し、CPU Bottleneckではないことを確認したとします。

② straceでSystem Callを確認する

# strace -T -p <PID>

③ Wait / Errorを確認する

Application遅延
   ↓
strace
   ↓
System Call
   ├─ connect() → Network?
   ├─ read()    → File / Socket?
   ├─ fsync()   → Storage?
   └─ futex()   → Synchronization?

④ 次のLayerへ進む

straceで見えた状況次に確認する例対象
connect()の失敗 / 長時間化ss、tcpdumpNetwork / 接続先
read() / fsync()の長時間化iostat、pidstat -dFile / Block I/O
futex()の長時間待機Thread Dump、ProfilerLock / Thread
openat()がENOENTPath、Mount、設定File / Configuration

straceの役割はSystem CallだけでRoot Causeを即断することではなく、ProcessがどこでKernelとのやり取りに失敗・待機しているかを確認し、次の調査対象を絞ることです。

straceと他のToolの使い分け

Tool主に見るもの用途
straceSystem Call / SignalProcessとKernelの境界、Error / Wait
perfCPU / Function / Call GraphCPU Hotspot
tcpdumpNetwork PacketTCP / DNSなどPacket解析
kdump / crashKernel Crash / vmcoreKernel PanicのPostmortem解析
eBPFKernel / Process EventCPU、I/O、Networkなどの動的観測

straceを本番環境で使用する際の注意点

Performanceへの影響を考慮する

straceは対象ProcessのSystem CallをTraceするため、Applicationの実行速度に影響を与えます。System Call頻度が高いProcessほど影響が大きくなる可能性があります。本番では対象と時間帯を絞り、短時間・限定的に利用します。

Trace対象を絞る

無条件にすべてTraceせず、障害の仮説に応じて-e trace=などで対象を限定します。

子Process / ThreadのTraceに注意する

-fで多数のProcess / Threadを追跡するとTrace量とOverheadが増えます。Process構成を確認して利用します。

機密情報の取扱いに注意する

System CallのArgumentにはFile Path、接続先、Application Dataなどが表示される場合があります。Trace Logは機密情報として適切に管理します。

straceだけで原因を断定しない

read()が遅いからDisk障害、connect()が遅いからNetwork障害、futex()が見えるからLock障害、と単純には断定できません。iostat、ss、tcpdump、perf、Application Log、Thread Dumpなどと組み合わせます。

まとめ

straceはLinux Processが発行するSystem Callと受信するSignalをTraceし、ProcessとLinux Kernelの境界で何が起きているかを確認するためのToolです。

  1. Processを特定:top、ps、pidstatで対象を絞る。
  2. strace:System Call、Argument、Return Valueを確認する。
  3. Error:errnoから失敗内容を確認する。
  4. Wait:futex、poll、epoll_waitなどから待機を確認する。
  5. -e trace=:仮説に応じて対象を絞る。
  6. -T:System Callの経過時間を確認する。
  7. 次の調査:File / I/O、Network、Threadなど該当Layerへ進む。

Processトラブルシューティングでは、Process → System Call → Error / Wait → File / Network / Synchronizationと段階的に深掘りすることが重要です。straceを単独で使うのではなく、top、pidstat、iostat、tcpdump、perf、Application Logなどと組み合わせて原因を絞り込みます。

コメント