阅读(1897)评论(2)

banner

前因

开发环境没问题的代码,在线上服务器运行总是会卡顿几分钟,即使代码里只有一句

<?php
echo 'hello cli' . PHP_EOL;

也会卡住,且这个卡顿非常奇怪,它并不是100%复现的,而是随机性的,随即做了N次追踪(因为他无法稳定复现

开始排查

最开始挺烦的,在挂追踪的时候总是会因为运行的不是特定文件导致追踪过长丢失记录.

所以说调试时候一定注意最好搞个专门的文件做测试,或者 嗯没有或者

首先 ps -aux | grep php 来找出你需要调试的进程的pid 如果是进程已经运行并卡住了的话

输出大概这样

root     21596  0.5  0.5 430188 19912 pts/4    S+   22:29   0:00 php test.php
root     21598  0.0  0.0 112736   976 pts/1    S+   22:29   0:00 grep --color=auto php

看到进程的pid为21596 执行 strace -yy -p 21596 获得输出

restart_syscall(<... resuming interrupted poll ...>) = 1
ioctl(3114.114.114.114:53]>, FIONREAD, [26]) = 0
recvfrom(3114.114.114.114:53]>, "\372\236\203\203\0\1\0\0\0\0\0\0\10host-name\0\0\34\0\1", 65536, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("114.114.114.114")}, [16]) = 26
close(3114.114.114.114:53]>) = 0
socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("114.114.114.114")}, 16) = 0
writev(3114.114.114.114:53]>, [{"\0\32", 2}, {"\322\221\1\0\0\1\0\0\0\0\0\0\10host-name\0\0\1\0\1", 26}, {"\0\32", 2}, {"\372\236\1\0\0\1\0\0\0\0\0\0\10host-name\0\0\34\0\1", 26}], 4) = 56
read(3114.114.114.114:53]>, 0x7fffc188e5b0, 2) = -1 ETIMEDOUT (Connection timed out)
close(3114.114.114.114:53]>) = 0
socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("223.5.5.5")}, 16) = 0
writev(3223.5.5.5:53]>, [{"\0\32", 2}, {"\322\221\1\0\0\1\0\0\0\0\0\0\10host-name\0\0\1\0\1", 26}, {"\0\32", 2}, {"\372\236\1\0\0\1\0\0\0\0\0\0\10host-name\0\0\34\0\1", 26}], 4) = 56
read(3223.5.5.5:53]>, "\0e", 2) = 2
read(3223.5.5.5:53]>, "\322\221\201\203\0\1\0\0\0\1\0\0\10host-name\0\0\1\0\1\0\0\6\0\1\0"..., 101) = 101
read(3223.5.5.5:53]>, "\0e", 2) = 2
read(3223.5.5.5:53]>, "\372\236\201\203\0\1\0\0\0\1\0\0\10host-name\0\0\34\0\1\0\0\6\0\1\0"..., 101) = 101
close(3223.5.5.5:53]>) = 0
open("/usr/local/lib/libnss_myhostname.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)

其他地方不重要所以我删除了,我们分析一下它干了什么

  1. ioctl(3<UDP:[xxx.xxx.xxx.xxx:58453->114.114.114.114:53]>udp 访问 114.114.114.114 的 53 端口
  2. recvfrom(3<UDP:[xxx.xxx.xxx.xxx:58453->114.114.114.114:53]>, "\372\236\203\203\0\1\0\0\0\0\0\0\10host-name\0\0\34\0\1", 65536, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("114.114.114.114")}, [16]) = 26 发送数据包
  3. close(3<UDP:[xxx.xxx.xxx.xxx:58453->114.114.114.114:53]>) = 0 关闭
  4. read(3<TCP:[xxx.xxx.xxx.xxx:47930->114.114.114.114:53]>, 0x7fffc188e5b0, 2) = -1 ETIMEDOUT (Connection timed out) 重点 读取响应超时
  5. 下面基本同理不讲了.

显然 知道原因了 众所周知 53是dns端口 114*4是电信(好像?)的dns服务器 它访问失败了或者请求解析超时了.

我们看一下包体 \372\236\203\203\0\1\0\0\0\0\0\0\10host-name\0\0\34\0\1 注意 host-name 是服务器的hostname 就是 [root@host-name ~]

很明显了,它去请求host-name 这个玩意dns服务器没有 自然不理他 于是它换个dns服务器继续请求 所以就在这卡了半天

修复

找到原因了自然就要修复,这个其实再做一个追踪就能看出来,大致信息如下

read(3, "127.0.0.1   localhost localhost."..., 4096) = 158
read(3, "", 4096)           = 0
read(3,

在这里,它请求了hosts之后去调用dns了,因为libnss是负责dns的so

显然是因为hosts没有host-name

快速修复代码

echo "127.0.0.1 host-name" >> /etc/hosts
或
vim /etc/hosts
127.0.0.1 host-name

接下来跑一次测试,就会发现不再调用/usr/lib64/libnss_dns了

read(3, "127.0.0.1   localhost localhost."..., 4096) = 158
read(3, "", 4096)           = 0
read(3, "# Configuration snippets may be "..., 4096) = 641

原因

尚不明确为什么一定会请求解析hosts 可能是我编译的php本身的问题? 等我有空之后补充2333

发表评论

评论

暂无评论

    本日の格言
    博主闪亮登场!

    喂,前面可是地狱啊!おい、この先は地狱だぜ!
    by Fate/stay night

    超想说
    博主の友人
    对!就是这种低调,如同吃了炫迈
    超有爱
    TOP