炮弹中的齿轮工像僵尸一样挂着



我在一个shell脚本中有一个Gearman工作程序,它以以下方式用perl启动:

runuid -s gds 
/usr/bin/gearman -h 127.0.0.1 -t 1000 -w -f gds-rel 
-- xargs /home/gds/gds-rel-worker.sh < /dev/null 2>/dev/null

worker只做一些输入验证,并调用另一个shell脚本run.sh,该脚本调用bash、curl、Terragrunt、Terraform、Ansible和gcloud来提供和更新GCP中的资源,如下所示:

./run.sh --release 1.2.3 2>&1 >> /var/log/gds-release

该脚本打算在无人参与的情况下运行。我遇到的问题是,在作业成功完成后(这是shell脚本run.sh和gdsrel-worker.sh(,Gearman作业仍在执行,因为子进程变成了僵尸(请参阅下面的最后一行(。

root      144748       1  0 Apr29 ?        00:00:00 perpboot -d /etc/perp
root      144749  144748  0 Apr29 ?        00:00:00  _ tinylog -k 8 -s 100000 -t -z /var/log/perp/perpd-root
root      144750  144748  0 Apr29 ?        00:00:00  _ perpd /etc/perp
root     2492482  144750  0 May14 ?        00:00:00      _ tinylog (gearmand) -k 10 -s 100000000 -t -z /var/log/perp/gearmand
gearmand 2492483  144750  0 May14 ?        00:00:08      _ /usr/sbin/gearmand -L 127.0.0.1 -p 4730 --verbose INFO --log-file stderr --keepalive --keepalive-idle 120 --keepalive-interval 120 --keepalive-count 3 --round-robin --threads 36 --worker-wakeup 3 --job-retries 1
root     2531800  144750  0 May14 ?        00:00:00      _ tinylog (gds-rel-worker) -k 10 -s 100000000 -t -z /var/log/perp/gds-rel-worker
gds      2531801  144750  0 May14 ?        00:00:00      _ /usr/bin/gearman -h 127.0.0.1 -t 1000 -w -f gds-rel -- xargs /home/gds/gds-rel-worker.sh
gds      2531880 2531801  0 May14 ?        00:00:00          _ [xargs] <defunct>

到目前为止,我已经将问题追溯到run.sh,因为如果我用更简单的东西替换它的调用(例如,echo"Hello";sleep 5(,工作程序就不会挂断。不幸的是,我不知道是什么导致了这个问题。脚本run.sh相当长且复杂,但到目前为止一直工作正常。追踪工人流程我看到的是:

getpid()                                = 2531801
write(2, "gearman: ", 9)                = 9
write(2, "gearman_worker_work", 19)     = 19
write(2, " : ", 3)                      = 3
write(2, "gearman_wait(GEARMAN_TIMEOUT) ti"..., 151) = 151
write(2, "n", 1)                       = 1
sendto(5, "REQ'", 12, MSG_NOSIGNAL, NULL, 0) = 12
recvfrom(5, "RESn", 8192, MSG_NOSIGNAL, NULL, NULL) = 12
sendto(5, "REQ4", 12, MSG_NOSIGNAL, NULL, 0) = 12
poll([{fd=5, events=POLLIN}, {fd=3, events=POLLIN}], 2, 1000) = 1 ([{fd=5, revents=POLLIN}])
sendto(5, "REQ'", 12, MSG_NOSIGNAL, NULL, 0) = 12
recvfrom(5, "RES6RES(QH:terra-"..., 8192, MSG_NOSIGNAL, NULL, NULL) = 105
pipe([6, 7])                            = 0
pipe([8, 9])                            = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fea38480a50) = 2531880
close(6)                                = 0
close(9)                                = 0
write(7, "1.2.3n", 18)                 = 6
close(7)                                = 0
read(8, "which: no terraform-0.14 in (/us"..., 1024) = 80
read(8, "Identity added: /home/gds/.ssh/i"..., 1024) = 54
read(8, 0x7fff6251f5b0, 1024)           = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=2531880, si_uid=1006, si_status=0, si_utime=0, si_stime=0} ---
read(8,

因此,即使孩子已经成功完成并可能关闭了标准输出,工人仍会继续阅读。有什么想法可以找出导致这个问题的原因吗?

我解决了这个问题。脚本run.sh启动了ssh代理,它打开了一个套接字,由于Gearman重定向了所有输出,即使在脚本成功完成后,工作人员也会继续读取打开的文件描述符。

我通过检查Gearman工作进程挂起后的打开文件描述符找到了它:

# ls -l /proc/2531801/fd/*
lr-x------. 1 gds devops 64 May 17 11:26 /proc/2531801/fd/0 -> /dev/null
l-wx------. 1 gds devops 64 May 17 11:26 /proc/2531801/fd/1 -> 'pipe:[9356665]'
l-wx------. 1 gds devops 64 May 17 11:26 /proc/2531801/fd/2 -> 'pipe:[9356665]'
lr-x------. 1 gds devops 64 May 17 11:26 /proc/2531801/fd/3 -> 'pipe:[9357481]'
l-wx------. 1 gds devops 64 May 17 11:26 /proc/2531801/fd/4 -> 'pipe:[9357481]'
lrwx------. 1 gds devops 64 May 17 11:26 /proc/2531801/fd/5 -> 'socket:[9357482]'
lr-x------. 1 gds devops 64 May 17 11:26 /proc/2531801/fd/8 -> 'pipe:[9369888]'

然后在文件描述符8中识别出使用文件节点的进程,德国工人继续读取:

# lsof | grep 9369888
gearman   2531801                              gds    8r     FIFO               0,13      0t0    9369888 pipe
ssh-agent 2531899                              gds    9w     FIFO               0,13      0t0    9369888 pipe

最后列出了ssh代理打开的文件,并找到了文件描述符3:背后的内容

# ls -l /proc/2531899/fd/*
lrwx------. 1 root root 64 May 17 11:14 /proc/2531899/fd/0 -> /dev/null
lrwx------. 1 root root 64 May 17 11:14 /proc/2531899/fd/1 -> /dev/null
lrwx------. 1 root root 64 May 17 11:14 /proc/2531899/fd/2 -> /dev/null
lrwx------. 1 root root 64 May 17 11:14 /proc/2531899/fd/3 -> 'socket:[9346577]'
# lsof | grep 9346577
ssh-agent 2531899                              gds    3u     unix 0xffff89016fd34000      0t0    9346577 /tmp/ssh-0b14coFWhy40/agent.2531898 type=STREAM

作为一个解决方案,我在从run.sh脚本退出之前添加了ssh代理的kill,现在没有由于僵尸进程而挂起的作业。

相关内容

  • 没有找到相关文章

最新更新