亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.430618.com 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

strace是什么?

按照strace官網的描述, strace是一個可用于診斷、調試和教學的linux用戶空間跟蹤器。我們用它來監控用戶空間進程和內核的交互,比如系統調用、信號傳遞、進程狀態變更等。

strace底層使用內核的ptrace特性來實現其功能。

在運維人員的日常工作中,故障處理和問題診斷是個主要的內容,也是必備的技能。strace作為一種動態跟蹤工具,能夠幫助運維高效地定位進程和服務故障。它像是一個偵探,通過系統調用的蛛絲馬跡,告訴你異常的真相。

strace能做什么?

運維工程師都是實踐派的人,我們還是先來個例子吧。

我們從別的機器copy了個叫做some_server的軟件包過來,開發說直接啟動就行,啥都不用改。可是嘗試啟動時卻報錯,根本起不來!

啟動命令:

./some_server ../conf/some_server.conf

輸出:

FATAL: InitLogFile failed iRet: -1!
Init error: -1655

為什么起不來呢?從日志看,似乎是初始化日志文件失敗,真相到底怎樣呢?我們用strace來看看。

strace -tt -f  ./some_server ../conf/some_server.conf

輸出:

我們注意到,在輸出InitLogFile failed錯誤的前一行,有個open系統調用:

23:14:24.448034 open("/usr/local/Apps/some_server/log//server_agent.log", O_RDWR|O_CREAT|O_APPEND|O_LARGEFILE, 0666) = -1 ENOENT (No such file or directory)

它嘗試打開文件/usr/local/apps/some_server/log//server_agent.log來寫(不存在則創建),可是卻出錯了,返回碼是-1, 系統錯誤號errorno為ENOENT。 查下open系統調用的手冊頁:

man 2 open

搜索ENOENT這個錯誤號errno的解釋

ENOENT O_CREAT is not set and the named file does not exist. Or, a directory component in pathname does not exist or is a dangling symbolic link.

這里說得比較清楚,因為我們例子中的open選項指定了O_CREAT選項,這里errno為ENOENT的原因是日志路徑中某個部分不存在或者是一個失效的符號鏈接。我們來一級一級看下路徑中的哪部分不存在:

ls -l /usr/local/apps/some_server/log
ls: cannot access /usr/local/apps/some_server/log: No such file or directory
ls -l /usr/local/apps/some_server
total 8
drwxr-xr-x 2 root users 4096 May 14 23:13 bin
drwxr-xr-x 2 root users 4096 May 14 22:48 conf

原來是log子目錄不存在!上層目錄都是存在的。手工創建log子目錄后,服務就能正常啟動了。

回過頭來, strace究竟能做什么呢?

它能夠打開應用進程的這個黑盒,通過系統調用的線索,告訴你進程大概在干嘛。

strace怎么用?

既然strace是用來跟蹤用戶空間進程的系統調用和信號的,在進入strace使用的主題之前,我們的先理解什么是系統調用。

關于系統調用:

按維基百科中的解釋,在計算機中,系統調用(英語:system call),又稱為系統呼叫,指運行在用戶空間的程序向操作系統內核請求需要更高權限運行的服務。

系統調用提供用戶程序與操作系統之間的接口。操作系統的進程空間分為用戶空間和內核空間:

  • 操作系統內核直接運行在硬件上,提供設備管理、內存管理、任務調度等功能。
  • 用戶空間通過API請求內核空間的服務來完成其功能——內核提供給用戶空間的這些API, 就是系統調用。

在Linux系統上,應用代碼通過glibc庫封裝的函數,間接使用系統調用。

Linux內核目前有300多個系統調用,詳細的列表可以通過syscalls手冊頁查看。這些系統調用主要分為幾類:

文件和設備訪問類 比如open/close/read/write/chmod等
進程管理類 fork/clone/execve/exit/getpid等
信號類 signal/sigaction/kill 等
內存管理 brk/mmap/mlock等
進程間通信IPC shmget/semget * 信號量,共享內存,消息隊列等
網絡通信 socket/connect/sendto/sendmsg 等
其他

熟悉Linux系統調用/系統編程,能夠讓我們在使用strace時得心應手。不過,對于運維的問題定位來說,知道strace這個工具,會查系統調用手冊,就差不多夠了。

想要深入了解的同學,建議閱讀《Linux系統編程》, 《Unix環境高級編程》等書籍。

我們回到strace的使用上來。strace有兩種運行模式。

一種是通過它啟動要跟蹤的進程。用法很簡單,在原本的命令前加上strace即可。比如我們要跟蹤 "ls -lh /var/log/messages" 這個命令的執行,可以這樣:

strace ls -lh /var/log/messages

另外一種運行模式,是跟蹤已經在運行的進程,在不中斷進程執行的情況下,理解它在干嘛。 這種情況,給strace傳遞個-p pid 選項即可。

比如,有個在運行的some_server服務,第一步,查看pid:

pidof some_server                      
17553

得到其pid 17553然后就可以用strace跟蹤其執行:

strace -p 17553

完成跟蹤時,按ctrl + C 結束strace即可。

strace有一些選項可以調整其行為,我們這里介紹下其中幾個比較常用的,然后通過示例講解其實際應用效果。

strace常用選項:

從一個示例命令來看:

strace -tt -T -v -f -e trace=file -o /data/log/strace.log -s 1024 -p 23489

-tt 在每行輸出的前面,顯示毫秒級別的時間
-T 顯示每次系統調用所花費的時間
-v 對于某些相關調用,把完整的環境變量,文件stat結構等打出來。
-f 跟蹤目標進程,以及目標進程創建的所有子進程
-e 控制要跟蹤的事件和跟蹤行為,比如指定要跟蹤的系統調用名稱
-o 把strace的輸出單獨寫到指定的文件
-s 當系統調用的某個參數是字符串時,最多輸出指定長度的內容,默認是32個字節
-p 指定要跟蹤的進程pid, 要同時跟蹤多個pid, 重復多次-p選項即可。

實例:跟蹤Nginx, 看其啟動時都訪問了哪些文件

strace -tt -T -f -e trace=file -o /data/log/strace.log -s 1024 ./nginx

部分輸出:

輸出中,第一列顯示的是進程的pid, 接著是毫秒級別的時間,這個是-tt 選項的效果。

每一行的最后一列,顯示了該調用所花的時間,是-T選項的結果。

這里的輸出只顯示和文件訪問有關的內容,這是因為我們通過-e trace=file 選項指定了。

strace問題定位案例

1、定位進程異常退出

問題:機器上有個叫做run.sh的常駐腳本,運行一分鐘后會死掉。需要查出死因。

定位:進程還在運行時,通過ps命令獲取其pid, 假設我們得到的pid是24298

strace -o strace.log -tt -p 24298

查看strace.log, 我們在最后2行看到如下內容:

22:47:42.803937 wait4(-1,  <unfinished ...>
22:47:43.228422 +++ killed by SIGKILL +++

這里可以看出,進程是被其他進程用KILL信號殺死的。

實際上,通過分析,我們發現機器上別的服務有個監控腳本,它監控一個也叫做run.sh的進程,當發現run.sh進程數大于2時,就會把它殺死重啟。結果導致我們這個run.sh腳本被誤殺。

進程被殺退出時,strace會輸出killed by SIGX(SIGX代表發送給進程的信號)等,那么,進程自己退出時會輸出什么呢?

這里有個叫做test_exit的程序,其代碼如下:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
       exit(1);
}

我們strace看下它退出時strace上能看到什么痕跡。

strace -tt -e trace=process -f ./test_exit

說明: -e trace=process 表示只跟蹤和進程管理相關的系統調用。

輸出:

23:07:24.672849 execve("./test_exit", ["./test_exit"], [/* 35 vars */]) = 0
23:07:24.674665 arch_prctl(ARCH_SET_FS, 0x7f1c0eca7740) = 0
23:07:24.675108 exit_group(1)           = ?
23:07:24.675259 +++ exited with 1 +++

可以看出,進程自己退出時(調用exit函數,或者從main函數返回), 最終調用的是exit_group系統調用, 并且strace會輸出exited with X(X為退出碼)。

可能有人會疑惑,代碼里面明明調用的是exit, 怎么顯示為exit_group?

這是因為這里的exit函數不是系統調用,而是glibc庫提供的一個函數,exit函數的調用最終會轉化為exit_group系統調用,它會退出當前進程的所有線程。實際上,有一個叫做_exit()的系統調用(注意exit前面的下劃線), 線程退出時最終會調用它。

2、定位共享內存異常

有個服務啟動時報錯:

shmget 267264 30097568: Invalid argument
Can not get shm...exit!

錯誤日志大概告訴我們是獲取共享內存出錯,通過strace看下:

strace -tt -f -e trace=ipc ./a_mon_svr     ../conf/a_mon_svr.conf

輸出:

22:46:36.351798 shmget(0x5feb, 12000, 0666) = 0
22:46:36.351939 shmat(0, 0, 0)          = ?
Process 21406 attached
22:46:36.355439 shmget(0x41400, 30097568, 0666) = -1 EINVAL (Invalid argument)
shmget 267264 30097568: Invalid argument
Can not get shm...exit!

這里,我們通過-e trace=ipc 選項,讓strace只跟蹤和進程通信相關的系統調用。

從strace輸出,我們知道是shmget系統調用出錯了,errno是EINVAL。同樣, 查詢下shmget手冊頁,搜索EINVAL的錯誤碼的說明:

EINVAL A new segment was to be created and size < SHMMIN or size > SHMMAX, or no new segment was to be created, a segment with given key existed, but size is greater than the size of that segment

翻譯下,shmget設置EINVAL錯誤碼的原因為下列之一:

  • 要創建的共享內存段比 SHMMIN小 (一般是1個字節)
  • 要創建的共享內存段比 SHMMAX 大 (內核參數kernel.shmmax配置)
  • 指定key的共享內存段已存在,其大小和調用shmget時傳遞的值不同。

從strace輸出看,我們要連的共享內存key 0x41400, 指定的大小是30097568字節,明顯與第1、2種情況不匹配。那只剩下第三種情況。使用ipcs看下是否真的是大小不匹配:

ipcs  -m | grep 41400
key        shmid      owner      perms      bytes      nattch     status    
0x00041400 1015822    root       666        30095516   1

可以看到,已經0x41400這個key已經存在,并且其大小為30095516字節,和我們調用參數中的30097568不匹配,于是產生了這個錯誤。

在我們這個案例里面,導致共享內存大小不一致的原因,是一組程序中,其中一個編譯為32位,另外一個編譯為64位,代碼里面使用了long這個變長int數據類型。

把兩個程序都編譯為64解決了這個問題。

這里特別說下strace的-e trace選項。

要跟蹤某個具體的系統調用,-e trace=xxx即可。但有時候我們要跟蹤一類系統調用,比如所有和文件名有關的調用、所有和內存分配有關的調用。

如果人工輸入每一個具體的系統調用名稱,可能容易遺漏。于是strace提供了幾類常用的系統調用組合名字。

-e trace=file 跟蹤和文件訪問相關的調用(參數中有文件名)
-e trace=process 和進程管理相關的調用,比如fork/exec/exit_group
-e trace=network 和網絡通信相關的調用,比如socket/sendto/connect
-e trace=signal 信號發送和處理相關,比如kill/sigaction
-e trace=desc 和文件描述符相關,比如write/read/select/epoll等
-e trace=ipc 進程見同學相關,比如shmget等

絕大多數情況,我們使用上面的組合名字就夠了。實在需要跟蹤具體的系統調用時,可能需要注意C庫實現的差異。

比如我們知道創建進程使用的是fork系統調用,但在glibc里面,fork的調用實際上映射到了更底層的clone系統調用。使用strace時,得指定-e trace=clone, 指定-e trace=fork什么也匹配不上。

3、 性能分析

假如有個需求,統計Linux 4.5.4 版本內核中的代碼行數(包含匯編和C代碼)。這里提供兩個Shell腳本實現:

poor_script.sh:

 

!/bin/bash

total_line=0
while read filename; do
line=$(wc -l $filename | awk ‘{print $1}’)
(( total_line += line ))
done < <( find linux-4.5.4 -type f ( -iname ‘.c’ -o -iname ‘.h’ -o -iname ‘*.S’ ) )
echo “total line: $total_line”

good_script.sh:

 

!/bin/bash

find linux-4.5.4 -type f ( -iname ‘.c’ -o -iname ‘.h’ -o -iname ‘*.S’ ) -print0
| wc -l —files0-from - | tail -n 1

兩段代碼實現的目的是一樣的。 我們通過strace的-c選項來分別統計兩種版本的系統調用情況和其所花的時間(使用-f同時統計子進程的情況)

從兩個輸出可以看出,good_script.sh 只需要2秒就可以得到結果:19613114行。它大部分的調用(calls)開銷是文件操作(read/open/write/close)等,統計代碼行數本來就是干這些事情。

而poor_script.sh完成同樣的任務則花了539秒。它大部分的調用開銷都在進程和內存管理上(wait4/mmap/getpid…)。

實際上,從兩個圖中clone系統調用的次數,我們可以看出good_script.sh只需要啟動3個進程,而poor_script.sh完成整個任務居然啟動了126335個進程!

而進程創建和銷毀的代價是相當高的,性能不差才怪。

總結

當發現進程或服務異常時,我們可以通過strace來跟蹤其系統調用,“看看它在干啥”,進而找到異常的原因。熟悉常用系統調用,能夠更好地理解和使用strace。

當然,萬能的strace也不是真正的萬能。當目標進程卡死在用戶態時,strace就沒有輸出了。

這個時候我們需要其他的跟蹤手段,比如gdb/perf/SystemTap等。

備注:

1、perf原因kernel支持

2、ftrace kernel支持可編程

3、systemtap 功能強大,RedHat系統支持,對用戶態,內核態邏輯都能探查,使用范圍更廣

本文永久更新鏈接地址:http://www.linuxidc.com/Linux/2018-01/150654.htm

原文鏈接:http://blog.51cto.com/10541556/1793898

strace常用來跟蹤進程執行時的系統調用和所接收的信號。 在Linux世界,進程不能直接訪問硬件設備,當進程需要訪問硬件設備(比如讀取磁盤文件,接收網絡數據等等)時,必須由用戶態模式切換至內核態模式,通 過系統調用訪問硬件設備。strace可以跟蹤到一個進程產生的系統調用,包括參數,返回值,執行消耗的時間。

strace命令是一個集診斷、調試、統計與一體的工具,我們可以使用strace對應用的系統調用和信號傳遞的跟蹤結果來對應用進行分析,以達到解決問題或者是了解應用工作過程的目的。當然strace與專業的調試工具比如說gdb之類的是沒法相比的,因為它不是一個專業的調試器。 strace的最簡單的用法就是執行一個指定的命令,在指定的命令結束之后它也就退出了。在命令執行的過程中,strace會記錄和解析命令進程的所有系統調用以及這個進程所接收到的所有的信號值。

root@ubuntu:/usr# strace cat /dev/ 
execve(, [, ], []) = 
brk()                                  = 
access(, F_OK)      = - ENOENT (No such file or directory)
mmap(NULL, , PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -, ) = 
access(, R_OK)      = - ENOENT (No such file or directory)
...
brk() = 
brk() = 
fstat(, {st_mode=S_IFCHR|, st_rdev=makedev(, ), ...}) = 
open(, O_RDONLY) = 
fstat(, {st_mode=S_IFCHR|, st_rdev=makedev(, ), ...}) = 
read(, , ) = 
close() = 
close() = 
close() = 
exit_group() = ?

每一行都是一條系統調用,等號左邊是系統調用的函數名及其參數,右邊是該調用的返回值。
strace 顯示這些調用的參數并返回符號形式的值。strace 從內核接收信息,而且不需要以任何特殊的方式來構建內核。

strace參數

-c 統計每一系統調用的所執行的時間,次數和出錯的次數等. 
-d 輸出strace關于標準錯誤的調試信息. 
-f 跟蹤由fork調用所產生的子進程. 
-ff 如果提供-o filename,則所有進程的跟蹤結果輸出到相應的filename.pid中,pid是各進程的進程號. 
-F 嘗試跟蹤vfork調用.在-f時,vfork不被跟蹤. 
-h 輸出簡要的幫助信息. 
-i 輸出系統調用的入口指針. 
-q 禁止輸出關于脫離的消息. 
-r 打印出相對時間關于,,每一個系統調用. 
-t 在輸出中的每一行前加上時間信息. 
-tt 在輸出中的每一行前加上時間信息,微秒級. 
-ttt 微秒級輸出,以秒了表示時間. 
-T 顯示每一調用所耗的時間. 
-v 輸出所有的系統調用.一些調用關于環境變量,狀態,輸入輸出等調用由于使用頻繁,默認不輸出. 
-V 輸出strace的版本信息. 
-x 以十六進制形式輸出非標準字符串 
-xx 所有字符串以十六進制形式輸出. 
-a column 
設置返回值的輸出位置.默認 為40. 
-e expr 
指定一個表達式,用來控制如何跟蹤.格式如下: 
[qualifier=][!]value1[,value2]... 
qualifier只能是 trace,abbrev,verbose,raw,signal,read,write其中之一.value是用來限定的符號或數字.默認的 qualifier是 trace.感嘆號是否定符號.例如: 
-eopen等價于 -e trace=open,表示只跟蹤open調用.而-etrace!=open表示跟蹤除了open以外的其他調用.有兩個特殊的符號 all 和 none. 
注意有些shell使用!來執行歷史記錄里的命令,所以要使用\. 
-e trace= 
只跟蹤指定的系統 調用.例如:-e trace=open,close,rean,write表示只跟蹤這四個系統調用.默認的為set=all. 
-e trace=file 
只跟蹤有關文件操作的系統調用. 
-e trace=process 
只跟蹤有關進程控制的系統調用. 
-e trace=network 
跟蹤與網絡有關的所有系統調用. 
-e strace=signal 
跟蹤所有與系統信號有關的 系統調用 
-e trace=ipc 
跟蹤所有與進程通訊有關的系統調用 
-e abbrev= 
設定 strace輸出的系統調用的結果集.-v 等與 abbrev=none.默認為abbrev=all. 
-e raw= 
將指 定的系統調用的參數以十六進制顯示. 
-e signal= 
指定跟蹤的系統信號.默認為all.如 signal=!SIGIO(或者signal=!io),表示不跟蹤SIGIO信號. 
-e read= 
輸出從指定文件中讀出 的數據.例如: 
-e read=, 
-e write= 
輸出寫入到指定文件中的數據. 
-o filename 
將strace的輸出寫入文件filename 
-p pid 
跟蹤指定的進程pid. 
-s strsize 
指定輸出的字符串的最大長度.默認為32.文件名一直全部輸出. 
-u username 
以username 的UID和GID執行被跟蹤的命令

通用的完整用法:

strace -o output.txt -T -tt -e trace=all -p 28979

上面的含義是 跟蹤28979進程的所有系統調用(-e trace=all),并統計系統調用的花費時間,以及開始時間(并以可視化的時分秒格式顯示),最后將記錄結果存在output.txt文件里面。

語法

strace [ -dffhiqrtttTvxx ] [ -acolumn ] [ -eexpr ] ... [ -ofile ] [-ppid ] ... [ -sstrsize ] [ -uusername ] [ -Evar=val ] ... [ -Evar ]... [ command [ arg ... ] ]

strace -c [ -eexpr ] ... [ -Ooverhead ] [ -Ssortby ] [ command [ arg... ] ]
追蹤系統調用

現在我們做一個很簡單的程序來演示strace的基本用法。這個程序的C語言代碼如下:

#include<stdio.h>
int main()
{
    int a=0;
    printf("please input:n");
    scanf("%d",&a);
    printf("%9dn",a);                                                      
    return 0;
}
Linux診斷、調試利器strace命令詳解

 


 

 

Linux診斷、調試利器strace命令詳解

 


Linux診斷、調試利器strace命令詳解

 


Linux診斷、調試利器strace命令詳解

 

從trace結構可以看到,系統首先調用execve開始一個新的進行,接著進行些環境的初始化操作,最后停頓在”read(0,”上面,這也就是執行到了我們的scanf函數,等待我們輸入數字呢,在輸入完99之后,在調用write函數將格式化后的數值" 2″輸出到屏幕,最后調用exit_group退出進行,完成整個程序的執行過程。
 

跟蹤信號傳遞

我們還是使用上面的那個test程序,來觀察進程接收信號的情況。

Linux診斷、調試利器strace命令詳解

 


Linux診斷、調試利器strace命令詳解

 


Linux診斷、調試利器strace命令詳解

 

系統調用統計

strace不光能追蹤系統調用,通過使用參數-c,它還能將進程所有的系統調用做一個統計分析給你,下面就來看看strace的統計,這次我們執行帶-c參數的strace:

Linux診斷、調試利器strace命令詳解

 

這里很清楚的告訴你調用了那些系統函數,調用次數多少,消耗了多少時間等等這些信息,這個對我們分析一個程序來說是非常有用的。

Linux診斷、調試利器strace命令詳解

 


Linux診斷、調試利器strace命令詳解

 


Linux診斷、調試利器strace命令詳解

 


Linux診斷、調試利器strace命令詳解

 

 

 

原文地址:
https://www.cnblogs.com/machangwei-8/p/10388883.html

分享到:
標簽:命令 strace
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定