Debug 利器:pstack & strace


工作中難免會遇到各種各樣的 bug,對於開發環境 or 測試環境的問題還好解決,可以使用 gdb 打斷點或者在代碼中埋點來定位異常;
但是遇到線上的 bug 就很難受了,由於生產環境不能隨意替換、中斷程序,如果日志中找不到問題原因,解決問題就會很棘手

這時候就需要請出這兩位 debug 利器了 ———— pstack & strace

什么是 pstack

pstack 是 Linux 系統下的一個命令行工具,此命令可以顯示指定進程每個線程的堆棧快照,便於排查程序異常和性能評估

pstack 是基於 gdb 實現的,通過 man pstack 可以發現,它其實是 gstack 的一個軟鏈接

GSTACK(1)                  Linux Programmer's Manual                 GSTACK(1)
 
NAME
       gstack - print a stack trace of a running process
 
SYNOPSIS
       gstack pid
 
DESCRIPTION
       gstack attaches to the active process named by the pid on the command line, and prints out an execution stack trace.  If ELF symbols exist
       in the binary (usually the case unless you have run strip(1)), then symbolic addresses are printed as well.
 
       If the process is part of a thread group, then gstack will print out a stack trace for each of the threads in the group.
 
SEE ALSO
       nm(1), ptrace(2), gdb(1)
 
AUTHORS
       Ross Thompson <ross@whatsis.com>
 
       Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla>
 
Red Hat Linux                     Feb 15 2008                        GSTACK(1)
[root@Centos6x64 bin]# pwd
/usr/bin
[root@Centos6x64 bin]# ll -h | grep gstack
-rwxr-xr-x. 1 root root    1.1K 3月  22 2017 gstack
lrwxrwxrwx. 1 root root       6 8月  24 21:21 pstack -> gstack

而 gstack 則是封裝了 gdb 功能的 shell 腳本,通過 " thread apply all bt " 的命令獲得輸出所有的線程堆棧信息,再用 sed 進行替換和過濾

# Run GDB, strip out unwanted noise.
$GDB --quiet $readnever -nx /proc/$1/exe $1 <<EOF 2>&1 |
set width 0
set height 0
set pagination no
$backtrace
EOF
/bin/sed -n \
    -e 's/^\((gdb) \)*//' \
    -e '/^#/p' \
    -e '/^Thread/p'

 

什么是 strace

使用 pstack 獲得的進程堆棧是程序的靜態信息,而使用 strace 可以獲得程序的動態信息,即程序現在正在做什么(執行哪些系統調用和所接收的信號)

strace 的功能主要是通過 ptrace 這個系統調用來實現的,它提供了父進程觀察/控制子進程的能力

#include <sys/ptrace.h>
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);

詳見:ptrace(2) - Linux man page

當使用了 pstrace 跟蹤子進程后,所有發送給被跟蹤子進程的信號都會轉發給父進程(SIGKILL 除外),而子進程則會阻塞,被標注為 TASK_TRACED 狀態

父進程收到信號后,可以對阻塞的子進程進行檢查和修改,然后讓子進程繼續運行

 

關於 strace 的參數可以參考:strace 跟蹤進程中的系統調用

或者查看 Linux 手冊 man strace

 

如何使用 pstack & strace 排查程序問題

pstack 的用法

通過 ps / pidof 命令獲取到異常進程的 pid,執行 pstack [pid],我們可以獲得以下輸出:

從上面的輸出中我們可以得到很多信息

  • 當前進程中有多少線程
  • 各線程當前的調用堆棧(即這個線程正在做什么)

通過這些信息,我們可以簡單判斷線程是否掛死或者阻塞,再通過堆棧信息定位到代碼中具體的函數進一步排查

另外需要注意一點,只有保留了 debug symbols 的程序才可以 pstack,否則將看不到調用棧(如下圖)

 

strace 的用法

strace 的用法也很簡單,常用的選項有這幾個:

  • -f 跟蹤目標進程,以及目標進程創建的所有子進程
  • -t 在輸出中的每一行前加上時間信息(-tt 表示微秒級)
  • -T 顯示每個系統調用所耗的時間

執行 strace ... -p [pid] 我們將獲得如下的輸出:

通過觀察系統調用我們可以確認當前程序的行為,分析其消耗的時間、返回值是否正常

可以過濾指定的線程號,確認當前線程的行為是否符合預期

如果執行命令后完全沒有輸出,那么可以懷疑是否由於網絡、IO等原因導致阻塞,或程序產生死鎖

 

小結

有了這兩個工具,當出現線上異常時,如果情況緊急,我們可以收集程序當前狀態的信息,再進行救災
待生產環境穩定后,可以慢慢分析是哪里產生的問題

另外分析 pstack / strace 的信息時,最好和日志對照觀察


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM