百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

Linux cron运行原理

bigegpt 2024-08-28 12:28 4 浏览

1. 前言

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

2. 示例

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

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

3. 工作过程

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()调用)。

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子进程。

相关推荐

Go语言泛型-泛型约束与实践(go1.7泛型)

来源:械说在Go语言中,Go泛型-泛型约束与实践部分主要探讨如何定义和使用泛型约束(Constraints),以及如何在实际开发中利用泛型进行更灵活的编程。以下是详细内容:一、什么是泛型约束?**泛型...

golang总结(golang实战教程)

基础部分Go语言有哪些优势?1简单易学:语法简洁,减少了代码的冗余。高效并发:内置强大的goroutine和channel,使并发编程更加高效且易于管理。内存管理:拥有自动垃圾回收机制,减少内...

Go 官宣:新版 Protobuf API(go pro版本)

原文作者:JoeTsai,DamienNeil和HerbieOng原文链接:https://blog.golang.org/a-new-go-api-for-protocol-buffer...

Golang开发的一些注意事项(一)(golang入门项目)

1.channel关闭后读的问题当channel关闭之后再去读取它,虽然不会引发panic,但会直接得到零值,而且ok的值为false。packagemainimport"...

golang 托盘菜单应用及打开系统默认浏览器

之前看到一个应用,用go语言编写,说是某某程序的windows图形化客户端,体验一下发现只是一个托盘,然后托盘菜单的控制面板功能直接打开本地浏览器访问程序启动的webserver网页完成gui相关功...

golang标准库每日一库之 io/ioutil

一、核心函数概览函数作用描述替代方案(Go1.16+)ioutil.ReadFile(filename)一次性读取整个文件内容(返回[]byte)os.ReadFileioutil.WriteFi...

文件类型更改器——GoLang 中的 CLI 工具

我是如何为一项琐碎的工作任务创建一个简单的工具的,你也可以上周我开始玩GoLang,它是一种由Google制作的类C编译语言,非常轻量和快速,事实上它经常在Techempower的基准测...

Go (Golang) 中的 Channels 简介(golang channel长度和容量)

这篇文章重点介绍Channels(通道)在Go中的工作方式,以及如何在代码中使用它们。在Go中,Channels是一种编程结构,它允许我们在代码的不同部分之间移动数据,通常来自不同的goro...

Golang引入泛型:Go将Interface「」替换为“Any”

现在Go将拥有泛型:Go将Interface{}替换为“Any”,这是一个类型别名:typeany=interface{}这会引入了泛型作好准备,实际上,带有泛型的Go1.18Beta...

一文带你看懂Golang最新特性(golang2.0特性)

作者:腾讯PCG代码委员会经过十余年的迭代,Go语言逐渐成为云计算时代主流的编程语言。下到云计算基础设施,上到微服务,越来越多的流行产品使用Go语言编写。可见其影响力已经非常强大。一、Go语言发展历史...

Go 每日一库之 java 转 go 遇到 Apollo?让 agollo 来平滑迁移

以下文章来源于GoOfficialBlog,作者GoOfficialBlogIntroductionagollo是Apollo的Golang客户端Apollo(阿波罗)是携程框架部门研...

Golang使用grpc详解(golang gcc)

gRPC是Google开源的一种高性能、跨语言的远程过程调用(RPC)框架,它使用ProtocolBuffers作为序列化工具,支持多种编程语言,如C++,Java,Python,Go等。gR...

Etcd服务注册与发现封装实现--golang

服务注册register.gopackageregisterimport("fmt""time"etcd3"github.com/cor...

Golang:将日志以Json格式输出到Kafka

在上一篇文章中我实现了一个支持Debug、Info、Error等多个级别的日志库,并将日志写到了磁盘文件中,代码比较简单,适合练手。有兴趣的可以通过这个链接前往:https://github.com/...

如何从 PHP 过渡到 Golang?(php转golang)

我是PHP开发者,转Go两个月了吧,记录一下使用Golang怎么一步步开发新项目。本着有坑填坑,有错改错的宗旨,从零开始,开始学习。因为我司没有专门的Golang大牛,所以我也只能一步步自己去...