微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

壳中的 Gearman 工人像僵尸一样挂起

如何解决壳中的 Gearman 工人像僵尸一样挂起

我在以 Gearman 开头的 shell 脚本中有一个 perp 工作线程,如下所示:

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 和 gds-rel-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),worker 不会挂起。不幸的是,我不知道是什么导致了问题。脚本 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,"\0REQ\0\0\0'\0\0\0\0",12,MSG_NOSIGNAL,NULL,0) = 12
recvfrom(5,"\0RES\0\0\0\n\0\0\0\0",8192,NULL) = 12
sendto(5,"\0REQ\0\0\0\4\0\0\0\0",0) = 12
poll([{fd=5,events=POLLIN},{fd=3,events=POLLIN}],2,1000) = 1 ([{fd=5,revents=POLLIN}])
sendto(5,"\0RES\0\0\0\6\0\0\0\0\0RES\0\0\0(\0\0\0QH:terra-"...,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.3\n",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-agent,这会打开一个套接字,并且由于 Gearman 重定向了所有输出,即使在脚本成功完成后,worker 仍会继续读取打开的文件描述符。

我通过检查 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-agent 打开的文件,并找到了文件描述符 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-agent,现在没有由于僵尸进程而挂起的作业。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?