當定位一個進程出現超時或者卡死的問題,我們通常會懷疑是否是io超時或者其他調度問題,我們需要在這個進程出現卡死或超時,獲取當時的調用棧信息,通過調用棧信息來分析可能的原因。如下為一個journald進程監控的方法:
workdir=/root/journald coredir=${workdir}/cores function prepare() { mkdir -p ${workdir} mkdir -p ${coredir} systemctl start systemd-journald systemctl start rsyslog } function monitor_one() { local -i count="$1" message="${count}: this is a log to monitor journald." logger "${message}" & sleep 2 contents=$(cat /var/log/messages | grep "${message}") if [ -z "$contents" ] ; then echo "journald in stuck...." pid=$(pgrep -f /usr/lib/systemd/systemd-journald) filename="journald-$(date +%s)-${count}" cat /proc/${pid}/stack > ${coredir}/${filename}.stack gcore -o ${coredir}/${filename} "${pid}" local -i core_count=$(ls -l ${coredir} | grep journald | wc -l) if [ ${core_count} -gt 100 ] ; then exit fi fi } function monitor_journal() { local -i count=0 while : ; do ((count++)) monitor_one $count sleep 4 done } prepare monitor_journal
這里主要的內容是當出現進程卡住時,獲取進程的stack信息,使用gcore工具,在進程不重啟的情況下,獲取進程的core信息。獲取到這些后用於問題分析。
/proc/[pid]/stack
/proc/[pid]/stack 示當前進程的內核調用棧信息,只有內核編譯時打開了 CONFIG_STACKTRACE 編譯選項,才會生成這個文件。舉例如下:
1 |
$ cat /proc/2406/stack |
gcore
當調試一個程序的時候,理想狀態是不重啟應用程序就獲取core文件。
gcore命令可以使用下面步驟來獲取core文件:
1. 確認gdb軟件包已經被正確安裝。
2. 使用調試參數編譯程序(例如: gcc中使用"-g"選項),編譯后不要去除文件的調試符號信息。
3. 執行應用程序。
4. 執行gcore命令生成指定應用程序的core文件並且保存在當前目錄下。
下面為一個監控dbus的腳本:
workdir=/root/dbus coredir=${workdir}/cores function prepare() { mkdir -p ${workdir} mkdir -p ${coredir} systemctl start systemd-journald systemctl start rsyslog systemctl start sshd systemctl start dbus } function monitor_dbus() { local -i count=0 local -i ecount=0 while : ; do ((count++)) /usr/bin/ssh 127.0.0.1 pwd >/dev/null 2>&1 & local -i ssh_pid=$! sleep 4 process=$(ps -Lwwo pid,ppid,tid,psr,pri,stat,wchan:30,uname,vsize,rss,start_time,args --no-header -p ${ssh_pid} | grep "/usr/bin/ssh") if [ -n "${process}" ] ; then ##當ssh進程超過4s都還沒有退出的話,說明dbus可能占用了很長時間 echo "dbus in stuck...." date_text=$(date +%s) dbus_pid=$(pgrep -f /bin/dbus-daemon) machined_pid=$(pgrep -f /usr/lib/systemd/systemd-machined) dbus_filename="dbus-${date_text}-${count}" machined_filename="machined-${date_text}-${count}" systemd_filename="systemd-${date_text}-${count}" cat /proc/1/stack > ${coredir}/${systemd_filename}.stack ps -eLwwo pid,ppid,tid,psr,pri,stat,wchan:30,uname,vsize,rss,start_time,args > ${coredir}/${systemd_filename}.ps top > ${coredir}/${systemd_filename}.top cat /proc/meminfo > ${coredir}/${systemd_filename}.mem cat /proc/interrupts > ${coredir}/${systemd_filename}.intr #gcore -o ${coredir}/${dbus_filename} "${dbus_pid}" #gcore -o ${coredir}/${machined_filename} "${machined_pid}" #gcore -o ${coredir}/${systemd_filename} 1 local -i core_count=$(ls -l ${coredir} | grep dbus | wc -l) ((ecount++)) if [ $ecount -gt 3 ] ; then cp -frpa /run/cgroup_time.txt ${coredir}/cgroup_time.txt echo 3 > /proc/sys/vm/drop_caches echo c >/proc/sysrq-trigger fi if [ ${core_count} -gt 100 ] ; then exit fi else ((ecount=0)) fi done } prepare monitor_dbus