使用 Strace 進行故障排除的五種簡單方法
我一直感到驚訝的是,很少有人知道他們可以使用strace的所有事情。它始終是我推出的第一個調試工具之一,因為它通常在我運行的 Linux 系統(tǒng)上可用,并且可用于解決如此廣泛的問題。
什么是strace?
Strace 非常簡單地是一個跟蹤系統(tǒng)調用執(zhí)行的工具。在最簡單的形式中,它可以從頭到尾跟蹤二進制文件的執(zhí)行,并輸出一行文本,其中包含系統(tǒng)調用的名稱、參數(shù)和進程生命周期內每個系統(tǒng)調用的返回值。 但它可以做更多的事情:
- 它可以根據(jù)特定的系統(tǒng)調用或系統(tǒng)調用組進行過濾
- 它可以通過計算特定系統(tǒng)調用的使用次數(shù)、所用時間以及成功和錯誤的數(shù)量來分析系統(tǒng)調用的使用情況。
- 它跟蹤發(fā)送到進程的信號。
- 它可以通過 pid 附加到任何正在運行的進程。
如果你使用過其他Unix系統(tǒng),這類似于“truss”。另一個(更全面)是Sun的Dtrace。
如何使用它
這只是皮毛,沒有特別的重要性順序:
1) 找出程序在啟動時讀取哪些配置文件
有沒有嘗試過弄清楚為什么某些程序不讀取您認為應該讀取的配置文件?不得不與自定義編譯或特定于發(fā)行版的二進制文件搏斗,這些二進制文件從您認為的“錯誤”位置讀取其配置? 幼稚的方法:所以這個版本的PHP從/usr/local/lib/php.ini讀取php.ini(但它首先嘗試/usr/local/bin)。 如果我只關心特定的系統(tǒng)調用,更復雜的方法:同樣的方法適用于許多其他事情。在不同的路徑上安裝了多個版本的庫,并想知道實際加載了哪個版本?等。
2)為什么這個程序打不開我的文件?
曾經遇到過一個程序,它默默地拒絕讀取它沒有讀取訪問權限的文件,但你只是在發(fā)誓多年后才發(fā)現(xiàn),因為你認為它實際上沒有找到該文件?好吧,您已經知道該怎么做:查找失敗的 open() 或 access() 系統(tǒng)調用
3)這個過程現(xiàn)在在做什么?
曾經有一個進程突然占用大量 CPU 嗎?還是一個過程似乎懸而未決? 然后你找到pid,然后這樣做:啊。所以在這種情況下,它掛在對futex()的調用中。順便說一下,在這種情況下,它并沒有告訴我們那么多 - 掛在 futex 上可能是由很多事情引起的(futex 是 Linux 內核中的鎖定機制)。以上來自一個正常工作但空閑的 Apache 子進程,該進程正在等待收到請求。 但是“strace -p”非常有用,因為它消除了大量的猜測,并且通常不需要重新啟動具有更廣泛日志記錄的應用程序(甚至重新編譯它)。
4)什么是花時間?
你始終可以在打開分析的情況下重新編譯應用,并獲得準確的信息,尤其是關于你自己的代碼的哪些部分需要時間,這是你應該做的。但通常,能夠快速將 strace 附加到流程以查看它當前花費的時間(尤其是診斷問題)是非常有用的。這是 90% 的 CPU 使用率,因為它實際上正在做真正的工作,還是失控的東西。 以下是您的操作:使用 -c -p 啟動 strace 后,您只需等待多長時間,然后使用 ctrl-c 退出。Strace 將按上述方式吐出分析數(shù)據(jù)。 在這種情況下,它是一個空閑的 Postgres “postmaster” 進程,它花費大部分時間在 select() 中安靜地等待。在這種情況下,它在每次select()調用之間調用getppid()和time(),這是一個相當標準的事件循環(huán)。 你也可以運行這個“從頭到尾”,這里用“l(fā)s”: 幾乎你所期望的,它大部分時間都花在兩次調用上來讀取目錄條目(只有兩次,因為它是在一個小目錄上運行的)。
5) 為什么 **** 我無法連接到該服務器?
調試某些進程未連接到遠程服務器的原因可能非常令人沮喪。DNS 可能會失敗,連接可能會掛起,服務器可能會發(fā)送一些意外的內容等。你可以使用 tcpdump 來分析很多,這也是一個非常好的工具,但很多時候 strace 會給你更少的喋喋不休,僅僅是因為它只會返回與“你的”進程生成的系統(tǒng)調用相關的數(shù)據(jù)。例如,如果您試圖弄清楚連接到同一數(shù)據(jù)庫服務器的數(shù)百個正在運行的進程中的一個是做什么的(其中挑選與 tcpdump 的正確連接是一場噩夢),strace 使生活變得容易得多。 這是“nc”跟蹤連接到端口 80 上的 www.news.com 的示例,沒有任何問題: 那么這里會發(fā)生什么? 注意到 /var/run/nscd/socket 的連接嘗試了嗎?這意味著 nc 首先嘗試連接到 NSCD - 名稱服務緩存守護程序 - 通常用于依賴 NIS、YP、LDAP 或類似目錄協(xié)議進行名稱查找的設置中。在這種情況下,連接失敗。 然后它移動到 DNS(DNS 是端口 53,因此在下面的連接中是“sin_port=htons(53)”。您可以看到它隨后執(zhí)行“sendto()”調用,發(fā)送包含 www.news.com 的DNS數(shù)據(jù)包。然后,它會讀回一個數(shù)據(jù)包。無論出于何種原因,它嘗試了三次,最后一次請求略有不同。在這種情況下,我最好的猜測是 www.news.com 是一個 CNAME(“別名”),多個請求可能只是 nc 如何處理它的人工制品。 最后,它最終向它找到的 IP 發(fā)出 connect()。請注意,它返回 EINPROGRESS。這意味著連接是非阻塞的 - nc 想要繼續(xù)處理。然后,它調用 select(),當連接成功時成功。 嘗試將“read”和“write”添加到提供給strace的系統(tǒng)調用列表中,并在連接時輸入一個字符串,你會得到這樣的結果: 這表明它從標準輸入讀取“test”+換行,并將其寫回網絡連接,然后調用poll()等待回復,從網絡連接讀取回復并將其寫入標準輸出。一切似乎都正常。