6

Linux cron运行原理

 2 years ago
source link: https://blogread.cn/it/article/7437?f=hot1
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Linux cron运行原理

浏览:1998次  出处信息

   1. 前言

   本文介绍的是由Paul Vixie开发的运行在SuSE Linux上的Cron。可以通过“man cron”进行确认。

   2. 示例

   # 示例用来配合本文的说明

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

   3. 工作过程

   cron运行原理

   Cron每分钟做一次检查,看看哪个命令可执行。

   从上图可以看到,有4次fork,这4次fork分别是:

   1) 第一个fork,让Cron自己成为Daemon进程,即成为守护进程;

   2) 第二个fork,当Cron检查到有命令需要执行时被创建,但注意它并不执行命令,执行命令由它的子进程来做;

   3) 第三个fork,有些版本调用的是vfork,但有些版本却是fork,它是负责执行Cron命令的进程,即会调用execle()的进程;

   4) 第四个fork不是必须的,只有为Cron命令配置了标准输入才会用:

   */1 * * * * /tmp/X/x%1234567890

   像上面有个百分符“%”,后面跟一串,则会有第四个fork,它的作用是将“%”后面的内容作为标准输入传递给第三个fork出来的进程。

   注意fork出来的进程没有忽略(ignore)管道信号(SIGPIPE),所以如果遇到SIGPIPE,则会导致进程无声无息的退出,比如标准输主输出重定向管道的读端被关闭了,写时就会触发SIGPIPE。

   实践中,可能会遇到child_process()在做上述所说的第三个fork前因SIGPIPE信号退出,导致难以理解的问题。其中一个现象是:Cron命令被执行了若干次,但之后再也不执行了,原因在于第二个fork出来的进程因SIGPIPE退出了,导致没有进行第三个fork,因此Cron命令没有被调用(总是由execle()调用)。

   cron运行原理

   4. 一个诡异的问题

   你有可能遇到这样的情况,假设在cron中有如下一条配置:

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

   观察到它正常运行几次后,就不再运行了,或者一次也不能,但确认无其它问题,因此十分诡异。

   这个问题的原因,有可能是因为有共享库Hook了cron,共享库代码触发了SIGPIPE,导致了第二个fork出的进程退出,没来得及执行vfork。

   fork出来的子进程,没有对SIGPIPE进行任何处理,默认行为是悄悄退出进程。通过修改/etc/ld.so.preload,可以将共享库注入到非关联的进程中,可通过ldd观察到这种依赖,使用LD_PRELOAD也可以达到同样的效果。

   5. cron&crontab

   cron是一个在后台运行的守护进程,而crontab是一个设置cron的工具。cron调度的是/etc/crontab文件。

   6. cron.allow&cron.deny

   crontab使用的两个文件,cron不会用到它们。

   7. cron.daily&cron.hourly&cron.weekly&cron.monthly

   cron.daily、cron.hourly、cron.weekly和cron.monthly这四个目录均位于/etc下,但cron和crontab两个并不处理。它们是由配置在/etc/crontab中的run-crons处理,run-crons是位于目录/usr/lib/cron下的一个Shell脚本文件:

   # cat /etc/crontab

   SHELL=/bin/sh

   PATH=/usr/bin:/usr/sbin:/sbin:/bin:/usr/lib/news/bin

   MAILTO=root

   # check scripts in cron.hourly, cron.daily, cron.weekly, and cron.monthly

   -*/15 * * * *   root  test -x /usr/lib/cron/run-crons && /usr/lib/cron/run-crons >/dev/null 2>&1

   8. crontab编辑后cron异常

   使用crontab编辑后,cron卡住不动(不是指进程卡住了,而是指命令没有被调用),原因可能是因为“tcb table full”,最简单的办法是重启cron。

   建议避免写下面这样的嵌套命令语句,它有可能导致cron不能正常工作:

   */1 * * * * echo "`date +%H:%M:%S` hello" >> /tmp/hello.txt

   “echo”中嵌套了“date”,可以改成脚本调用,或者不嵌套命令,如:

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

   一个现象是有一个cron子进程(如下述的14786)不退出了:

   # ps -ef|grep cron

   root     10325     1  0 15:08 ?        00:00:00 /usr/sbin/cron

   root     14786 10325  0 15:13 ?        00:00:00 /usr/sbin/cron

   gdb看到的调用栈为:

   #0  0xffffe410 in __kernel_vsyscall ()

   #1  0xb7e88a63 in __read_nocancel () from /lib/libc.so.6

   #2  0xb7e38e38 in _IO_file_read_internal () from /lib/libc.so.6

   #3  0xb7e3a0bb in _IO_new_file_underflow () from /lib/libc.so.6

   #4  0xb7e3a7fb in _IO_default_uflow_internal () from /lib/libc.so.6

   #5  0xb7e3bb2d in __uflow () from /lib/libc.so.6

   #6  0xb7e35b7b in getc () from /lib/libc.so.6

   #7  0x80005d73 in ?? () from /usr/sbin/cron

   strace看到如下:

   # strace -f -p 14786

   Process 14786 attached

   read(7,

   借助lsof可以看到:

   cron    14786 root    7r  FIFO        0,6         117960708 pipe

   为一个管道,read()挂住的原因可能是因为管道另一端所在进程调用_exit()退出而不是调用exit()退出。

   这个时候只有人工kill这个挂起的cron子进程。

建议继续学习:

QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK