<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    用strace排查故障的5種簡單方法(每日一譯)

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    原文鏈接:5 simple ways to troubleshoot using Strace

    我很意外大部分人都不知道如何使用strace。strace一直是我的首選debug工具,因為它非常的有效,很多問題都能夠用它進行排查。

    strace是什么?

    Strace是一個用來跟蹤系統調用的簡易工具。它最簡單的用途就是跟蹤一個程序整個生命周期里所有的系統調用,并把調用參數和返回值以文本的方式輸出。

    當然它還可以做更多的事情:

    strace可以過篩選出特定的系統調用。

    strace可以記錄系統調用的次數,時間,成功和失敗的次數。

    strace可以跟蹤發給進程的信號。

    strace可以通過pid附加到任何正在運行的進程上。

    strace類似其他Unix系統上的truss,或者Sun's Dtrace

    使用教程

    以下這些只是些皮毛的用法:

    1)查看初始化時程序讀取的配置文件

    你是否遇到過程序去錯誤的位置讀取配置文件的情況?

    簡單的排查方式:

    $ strace php 2>&1 | grep php.ini
    open("/usr/local/bin/php.ini", O_RDONLY) = -1 ENOENT (No such file or directory)
    open("/usr/local/lib/php.ini", O_RDONLY) = 4
    lstat64("/usr/local/lib/php.ini", {st_mode=S_IFLNK|0777, st_size=27, ...}) = 0
    readlink("/usr/local/lib/php.ini", "/usr/local/Zend/etc/php.ini", 4096) = 27
    lstat64("/usr/local/Zend/etc/php.ini", {st_mode=S_IFREG|0664, st_size=40971, ...}) = 0
    So this version of PHP reads php.ini from /usr/local/lib/php.ini (but it tries /usr/local/bin first).

    如果只關心特定的系統調用可以使用以下略微復雜的使用方法:

    $ strace -e open php 2>&1 | grep php.ini
    open("/usr/local/bin/php.ini", O_RDONLY) = -1 ENOENT (No such file or directory)
    open("/usr/local/lib/php.ini", O_RDONLY) = 4

    如果安裝多個版本的程序庫,想搞清楚自己的程序加載的是哪個也可以如法炮制~。

    2)為什么程序打不開這個文件?

    是否有遇到過讀取文件的時候被拒絕呢,你可以試試下面的命令:

    $ strace -e open,access 2>&1 | grep your-filename

    查看open()和access()系統調用是否有異常

    3)進程現在在做啥?

    是否有遇到過進程突然cpu占用率很高?又或者進程莫名其妙被掛起的情況?

    找到這個進程的pid,然后執行下列命令:

    root@dev:~# strace -p 15427
    Process 15427 attached - interrupt to quit
    futex(0x402f4900, FUTEX_WAIT, 2, NULL 
    Process 15427 detached

    在這個示例里進程在調用futex的時候被掛起了。順帶一說,在這個例子里調用futex掛起可能有很多的原因(Futex是Linux的一種線程同步原語)。上述場景是個正常工作等待處理請求的apache子進程。

    “strace -p”可以讓你省去很多猜測,不需要重新編譯,重啟應用打log就能夠找到問題。

    4)統計程序的調用時間

    要對程序進行性能分析往往需要重新編譯程序,并打開跟蹤選項。用strace可以很容易的附加到進程上查看實時的時間消耗。

    如下:

    root@dev:~# strace -c -p 11084
    Process 11084 attached - interrupt to quit
    Process 11084 detached
    % time     seconds  usecs/call     calls    errors syscall
    ------ ----------- ----------- --------- --------- ----------------
     94.59    0.001014          48        21           select
      2.89    0.000031           1        21           getppid
      2.52    0.000027           1        21           time
    ------ ----------- ----------- --------- --------- ----------------
    100.00    0.001072                    63           total
    root@dev:~# 

    啟用strace -c -p命令后,在你按ctrl-c退出前程序的調用時間將會打印出來。

    在上面的例子里。空閑的Postgres進程大部分時間都在安靜的等待select()返回。在每個select()調用中調用getppid() 和time()。這是個標準的event loop方式。

    也可以跟蹤一次程序的開始和結束,比如下面的“ls”例子

    root@dev:~# strace -c >/dev/null ls
    % time     seconds  usecs/call     calls    errors syscall
    ------ ----------- ----------- --------- --------- ----------------
     23.62    0.000205         103         2           getdents64
     18.78    0.000163          15        11         1 open
     15.09    0.000131          19         7           read
     12.79    0.000111           7        16           old_mmap
      7.03    0.000061           6        11           close
      4.84    0.000042          11         4           munmap
      4.84    0.000042          11         4           mmap2
      4.03    0.000035           6         6         6 access
      3.80    0.000033           3        11           fstat64
      1.38    0.000012           3         4           brk
      0.92    0.000008           3         3         3 ioctl
      0.69    0.000006           6         1           uname
      0.58    0.000005           5         1           set_thread_area
      0.35    0.000003           3         1           write
      0.35    0.000003           3         1           rt_sigaction
      0.35    0.000003           3         1           fcntl64
      0.23    0.000002           2         1           getrlimit
      0.23    0.000002           2         1           set_tid_address
      0.12    0.000001           1         1           rt_sigprocmask
    ------ ----------- ----------- --------- --------- ----------------
    100.00    0.000868                    87        10 total

    如你所料,這個命令花費兩個調用用于讀取目錄實體。

    5)為什么連不上服務器?

    調試某些進程為什么連不上遠程的服務器是個很讓人頭疼的事情。DNS可能掛了,連接可能斷了,服務器可能返回什么無法識別的東西。。。你可以使用tcpdump去分析這些問題,tcpdump是個很棒的工具,但是很多情況下,strace可以給你提供更簡潔的信息。如果你的程序里有很多進程連接到某臺服務器,用tcpdump來處理就是很蛋疼的事情,因為你會看到太多的信息,沒法抓到重點。

    以下是一個跟蹤“nc”命令連接到www.news.com的80端口的例子:

    $ strace -e poll,select,connect,recvfrom,sendto nc www.news.com 80
    sendto(3, "\\24\\0\\0\\0\\26\\0\\1\\3\\255\\373NH\\0\\0\\0\\0\\0\\0\\0\\0", 20, 0, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 20
    connect(3, {sa_family=AF_FILE, path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
    connect(3, {sa_family=AF_FILE, path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
    connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("62.30.112.39")}, 28) = 0
    poll([{fd=3, events=POLLOUT, revents=POLLOUT}], 1, 0) = 1
    sendto(3, "\\213\\321\\1\\0\\0\\1\\0\\0\\0\\0\\0\\0\\3www\\4news\\3com\\0\\0\\34\\0\\1", 30, MSG_NOSIGNAL, NULL, 0) = 30
    poll([{fd=3, events=POLLIN, revents=POLLIN}], 1, 5000) = 1
    recvfrom(3, "\\213\\321\\201\\200\\0\\1\\0\\1\\0\\1\\0\\0\\3www\\4news\\3com\\0\\0\\34\\0\\1\\300\\f"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("62.30.112.39")}, [16]) = 153
    connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("62.30.112.39")}, 28) = 0
    poll([{fd=3, events=POLLOUT, revents=POLLOUT}], 1, 0) = 1
    sendto(3, "k\\374\\1\\0\\0\\1\\0\\0\\0\\0\\0\\0\\3www\\4news\\3com\\0\\0\\1\\0\\1", 30, MSG_NOSIGNAL, NULL, 0) = 30
    poll([{fd=3, events=POLLIN, revents=POLLIN}], 1, 5000) = 1
    recvfrom(3, "k\\374\\201\\200\\0\\1\\0\\2\\0\\0\\0\\0\\3www\\4news\\3com\\0\\0\\1\\0\\1\\300\\f"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("62.30.112.39")}, [16]) = 106
    connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("62.30.112.39")}, 28) = 0
    poll([{fd=3, events=POLLOUT, revents=POLLOUT}], 1, 0) = 1
    sendto(3, "\\\\\\2\\1\\0\\0\\1\\0\\0\\0\\0\\0\\0\\3www\\4news\\3com\\0\\0\\1\\0\\1", 30, MSG_NOSIGNAL, NULL, 0) = 30
    poll([{fd=3, events=POLLIN, revents=POLLIN}], 1, 5000) = 1
    recvfrom(3, "\\\\\\2\\201\\200\\0\\1\\0\\2\\0\\0\\0\\0\\3www\\4news\\3com\\0\\0\\1\\0\\1\\300\\f"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("62.30.112.39")}, [16]) = 106
    connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("216.239.122.102")}, 16) = -1 EINPROGRESS (Operation now in progress)
    select(4, NULL, [3], NULL, NULL)        = 1 (out [3])

    這個連接嘗試訪問了/var/run/nscd/socket,這意味著nc命令首先嘗試連接NSCD服務(名稱緩存守護進程,通常用于NIS,YP,LDAP中的名字查找)。在上面的例子里執行失敗。

    nc命令轉而使用DNS(DNS的端口是53,"sin_port=htons(53)" )。可以看到程序調用”sendto()"發送包含www.news.com信息的DNS數據包。因為某些原因,嘗試了3次。為什么會這樣呢?我猜測可能www.news.com是CNAME ,最后,程序連接從DNS獲取到的IP,注意這里,返回EINPROGRESS。這意味這這個連接是非堵塞的。連接成功后nc調用select。

    添加read和write到跟蹤的系統調用列表里,連接上后敲入test,你會看到如下信息:

    read(0, "test\\n", 1024)                 = 5
    write(3, "test\\n", 5)                   = 5
    poll([{fd=3, events=POLLIN, revents=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1
    read(3, "

    你可以看到,程序從標準輸入中讀取到“test”,寫到網絡連接中,然后調用poll()等待響應,讀取響應然后寫入到標準輸出中。

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全