定位一个进程出现超时或卡死的方法

当定位一个进程出现超时或者卡死的问题,我们通常会怀疑是否是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
2
3
4
5
6
7
$ cat /proc/2406/stack
[<ffffffff810fa996>] futex_wait_queue_me+0xc6/0x130
[<ffffffff810fb05d>] futex_wait+0x17d/0x270
[<ffffffff810fd2d5>] do_futex+0xd5/0x520
[<ffffffff810fd791>] SyS_futex+0x71/0x150
[<ffffffff8180cc76>] entry_SYSCALL_64_fastpath+0x16/0x75
[<ffffffffffffffff>] 0xffffffffffffffff

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

 

  


posted @ 2018-09-27 11:18  行木辛  阅读(6555)  评论(0编辑  收藏  举报