美文网首页
使用strace来查找php的坑

使用strace来查找php的坑

作者: killtl | 来源:发表于2018-11-21 19:10 被阅读0次

    一段废话

    之前的shell分享中提到过strace这个流弊的工具,当时也是用linux C的代码造了一个场景来演示,而今再使用php构造一个场景来演示下如何查找一些坑,尽管差异不是很大

    问题

    先看下问题,最后会描述下构造的问题,问题如下

    [root@c488ca153abc xiaoju]# php7/bin/php strace.php &
    

    执行了一个php脚本,没有按照预期时间内返回,目测是阻塞住了

    查问题

    首先查pid

    [root@c488ca153abc xiaoju]# ps aux | grep strace.php
    root     12052  0.0  0.0 222344 10816 pts/0    S    18:15   0:00 php7/bin/php strace.php
    

    通过strace看下12052进程的系统调用的阻塞情况

    [root@c488ca153abc ~]# strace -p 12052
    Process 12052 attached
    wait4(-1,
    

    可以看到当前阻塞在wait4,该系统调用会挂起当前进程,等待指定的子进程状态改变,其中参数是-1表示等待任一子进程的返回,如此我们去查看下12052下面的子进程

    [root@c488ca153abc ~]# pstree -p 12052
    php(12052)───php(12053)
    

    继续使用strace看看12503为什么死也不返回

    [root@c488ca153abc ~]# strace -p 12053
    Process 12053 attached
    flock(3, LOCK_EX
    

    好吧,是flock文件锁,还是排他锁,文件描述符是3,看下对应的文件名是啥
    可以通过lsof看,也可以通过/proc/12053/fd目录查看,该文件包含进程打开文件的情况

    [root@c488ca153abc fd]# ll
    总用量 0
    lrwx------ 1 root root 64 11月 21 18:16 0 -> /dev/pts/0
    lrwx------ 1 root root 64 11月 21 18:16 1 -> /dev/pts/0
    lrwx------ 1 root root 64 11月 21 18:16 2 -> /dev/pts/0
    lrwx------ 1 root root 64 11月 21 18:16 3 -> /home/xiaoju/lock
    lrwx------ 1 root root 64 11月 21 18:16 5 -> socket:[2333709193]
    

    倒数第三列就是文件描述符,3 -> /home/xiaoju/lock,找到12053心心念念的文件了,看下是谁占用了这个文件

    [root@c488ca153abc fd]# lsof /home/xiaoju/lock | grep -v 12053
    COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
    php     12052 root    3uW  REG  253,6        0 17725454 /home/xiaoju/lock
    

    至此,可以断定是一个'死锁'了,父进程锁着文件等待子进程返回,子进程一直在等待父进程释放文件锁,如果还要进一步确定,可以到/proc/12052/目录中看到更多详细的信息,这里不赘述.

    构造问题

    构造了一个如下的问题,使用pcntl_fork建立一个父子进程,父子进程同时打开一个文件(内核级别会是两个不同的句柄),父进程先锁住A文件,然后开始pcntl_wait等待子进程的返回,最后释放锁,子进程以阻塞模式去获取文件锁,造成一个双等待的阻塞,如下是php的代码

    <?php
    /**
     * Created by tanlin
     * Email: jokertanlin@didichuxing.com
     * Date: 2018/11/21
     * Time: 下午4:49
     */
    
    $pid = pcntl_fork();
    $fp = fopen("./lock", "a+");
    
    if ($pid == -1) {
        // failed to fork
        die('could not fork');
    } else if ($pid) {
        // parent wait
        flock($fp, LOCK_EX);
        pcntl_wait($status);
        flock($fp, LOCK_UN);
        exit(0);
    } else {
        // child
        sleep(5);
        $waitIfLocked = true;
        flock($fp, LOCK_EX, $waitIfLocked);
        exit(0);
    }
    

    相关文章

      网友评论

          本文标题:使用strace来查找php的坑

          本文链接:https://www.haomeiwen.com/subject/kdzcqqtx.html