• Cron连接正常工作5次后异常原因分析


    目录

    目录 1

    问题描述 1

    分析定位 1

    解决方法 2

    附1:Cron工作流 3

    附2:SIGPIPE发生的位置 3

     

    如果一个shell命令的“$?”值为141,则它是收到了SIGPIPE信号。一些shell脚本中的sleep或ps、wc等命令无效,也可能是本文描述的原因,解决办法是忽略掉SIGPIPE,脚本中可以加句:trap "" SIGPIPE。

    问题描述

    在Crontab中仅配置如下一条命令(为简化问题的描述和定位,剔除所有其它的):

    */1 * * * * echo hello >> /tmp/hello.txt

     

    也就是每分钟执行一下“echo hello >> /tmp/hello.txt”。

     

    通过观察发现:

    每次重启cron进程后,都只能连续正常工作5次,也就是可以看到“/tmp/hello.txt”新增5行“hello”。

    分析定位

    借助strace工具,cron进程仍然在工作,只是发生了异常:

    [pid 12497] select(5, NULL, [4], NULL, {0, 10000}) = 1 (out [4], left {0, 10000})

    [pid 12497] --- SIGPIPE (Broken pipe) @ 0 (0) ---

    Process 12497 detached

    --- SIGCHLD (Child exited) @ 0 (0) ---

     

    发生了SIGPIPE,导致了子进程退出。翻阅cron的源代码,确认cron没有调用“signal(SIGPIPE, SIG_IGN);”来忽略SIGPIPE,因此当收到SIGPIPE信号时,进程必然退出。

     

    进一步追踪发现,PIPE连接的是“/usr/local/sa/agent/log/sap1012.sock”,另一端则是sap1012

    # lsof /usr/local/sa/agent/log/sap1012.sock

    COMMAND   PID USER   FD   TYPE     DEVICE SIZE       NODE NAME

    sap1012 15415 root    5u  unix 0xd940de40      3985983520 /usr/local/sa/agent/log/sap1012.sock

    sap1012 15415 root   11u  unix 0xe22fa3c0      3970596394 /usr/local/sa/agent/log/sap1012.sock

    # ls -l /proc/15415

    lrwxrwxrwx  1 root root 0 Apr 17 12:43 exe -> /usr/local/sa/agent/plugins/sap1012-v5.1.4

     

    使用valgrind可以看到对PIPE的写(send)是在“/lib/libsandbox_web_ips.so”中进行的,利用ldd可以发现这个共享库在编译期间就被链接进了cron程序文件中:

    # ldd /usr/sbin/cron

            linux-gate.so.1 =>  (0xffffe000)

            /lib/libbash_strip_env.so (0xb7f8c000)

            /lib/libsandbox_web_ips.so (0xb7f85000)

            libpam.so.0 => /lib/libpam.so.0 (0xb7f70000)

            libpam_misc.so.0 => /lib/libpam_misc.so.0 (0xb7f6d000)

            libc.so.6 => /lib/libc.so.6 (0xb7e4b000)

            libdl.so.2 => /lib/libdl.so.2 (0xb7e47000)

            libpthread.so.0 => /lib/libpthread.so.0 (0xb7e32000)

            libaudit.so.0 => /lib/libaudit.so.0 (0xb7e1f000)

            /lib/ld-linux.so.2 (0xb7f90000)

     

    在Google和Baidu中找不到任何有关“libsandbox_web_ips.so”的踪影,猜测是有可能是私有的。Cron的Makefile本身并没有包含libsandbox_web_ips.so”和“/lib/libbash_strip_env.so”,如:

    cc  -o cron cron.o database.o user.o entry.o job.o do_command.o misc.o env.o popen.o compat.o

     

    经实践确认,编译生成可执行文件后,可执行文件都会依赖“libsandbox_web_ips.so”和“/lib/libbash_strip_env.so”两个共享库,而且它们可能会在被加载时自动执行,但因为符号被stripped掉了,看不到细节。

     

    终于在/etc/ld.so.preload中找到了两者:

    # cat /etc/ld.so.preload

    /lib/libbash_strip_env.so

    /lib/libsandbox_web_ips.so

     

    它们两个如同木马,会伴随任一程序一起运行,但libsandbox_web_ips.so可能存在问题,导致cron运行异常。

    解决方法

    kill掉sap1012进程,然后重启cron进程,这样cron就可以正常工作了。cron必须在sap1012之前启动,以规避问题。通过strace会发现变成如下:

    [pid 11704] socket(PF_FILE, SOCK_STREAM, 0) = 3

    [pid 11704] fcntl64(3, F_GETFL)         = 0x2 (flags O_RDWR)

    [pid 11704] fcntl64(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0

    [pid 11704] connect(3, {sa_family=AF_FILE, path="/usr/local/sa/agent/log/sap1012.sock"}, 110) = -1 ECONNREFUSED (Connection refused)

    [pid 11704] close(3) 

     

    更好的解决办法将/lib/libbash_strip_env.so和/lib/libsandbox_web_ips.so,从/etc/ld.so.preload中剔除,但是它们就不能发挥作用了。

    附1:Cron工作流

    真正运行Cron命令的是vfork(有些版本为fork调用)出来的进程,写标准输出的fork是可选的,只有当存在“%”配置时才会生效,目的是通过写标准输出往vfork产生的进程输入内容。

    附2:SIGPIPE发生的位置

    SIGPIPE正是发生在下图所示的“send()”调用,至于是因为sap1012关闭了读端,还是其它原因,暂不清楚原因。

     

  • 相关阅读:
    mongodb修改bindIp和启动关闭
    把eclipse上的web项目导入IDEA
    项目重构也许更好——《梦断代码》读后感
    安卓记账本开发——数据库创建和数据测试
    开源的魅力——《梦断代码》读后感
    GitHub 网站上不去/加载慢/加载不全 解决办法
    安卓记账本开发——适配器编写和测试
    上传和下载
    cookie
    分页sql
  • 原文地址:https://www.cnblogs.com/aquester/p/9891471.html
Copyright © 2020-2023  润新知