Centos 5 上的慢 cron 作业

Posted

技术标签:

【中文标题】Centos 5 上的慢 cron 作业【英文标题】:Slow cronjobs on Cent OS 5 【发布时间】:2011-12-15 04:59:24 【问题描述】:

我有 1 个每 60 分钟运行一次的 cronjob,但由于某种原因,最近它运行缓慢。

环境:centos5 + apache2 + mysql5.5 + php 5.3.3 / raid 10/10k HDD / 16gig ram / 4 xeon 处理器

这是 cronjob 的作用:

    解析最近 60 分钟的数据

    a) 1 个进程解析用户代理并将数据保存到数据库

    b) 1 个进程解析网站上的展示次数/点击次数并将其保存到数据库中

    来自步骤 1 中的数据

    a) 建立一个小报告并向管理员/企业发送电子邮件

    b) 将报告保存到每日表格中(在管理部分可用)

当我运行命令 ps auxf | grep process_stats_hourly.php(在 *** 中找到此命令)时,我现在看到了 8 个进程(同一个文件)

从技术上讲,我应该只有 1 个而不是 8 个。

Cent OS 中是否有任何工具或我可以做些什么来确保我的 cronjob 每小时运行一次并且不会与下一个重叠?

谢谢

【问题讨论】:

你看到了 8 个。你确定前7个成功完成了吗?你能看到数据库中的数据逐渐减少(如果你刷新,你会看到这个过程仍在积极工作吗?)? 【参考方案1】:

您的硬件似乎足以处理这个问题。

1) 检查您是否已经有挂起的进程。使用ps auxf(参见 tcurvelo 答案),检查您是否有一个或多个进程占用过多资源。也许你没有足够的资源来运行你的 cronjob。

2) 检查您的网络连接: 如果您的数据库和您的 cronjob 在不同的服务器上,您应该检查这两台机器之间的响应时间。也许你有网络问题导致 cronjob 等待网络将包发回。

您可以使用:Netcat、Iperf、mtr 或 ttcp

3) 服务器配置 你的服务器配置正确吗?您的操作系统、MySQL 设置正确吗?我建议阅读这些文章:

http://www3.wiredgorilla.com/content/view/220/53/

http://www.vr.org/knowledgebase/1002/Optimize-and-disable-default-CentOS-services.html

http://dev.mysql.com/doc/refman/5.1/en/starting-server.html

http://www.linux-mag.com/id/7473/

4) 检查您的数据库: 确保您的数据库具有正确的索引并确保您的查询得到优化。阅读这篇关于explain command的文章

如果一个包含几十万条记录的查询需要花费一些时间来执行,这将影响你的 cronjob 的其余部分,如果你有一个循环内的查询,那就更糟了。

阅读这些文章:

http://dev.mysql.com/doc/refman/5.0/en/optimization.html

http://20bits.com/articles/10-tips-for-optimizing-mysql-queries-that-dont-suck/

http://blog.fedecarg.com/2008/06/12/10-great-articles-for-optimizing-mysql-queries/

5) 跟踪和优化 PHP 代码? 确保您的 PHP 代码尽可能快地运行。

阅读这些文章:

http://phplens.com/lens/php-book/optimizing-debugging-php.php

http://code.google.com/speed/articles/optimizing-php.html

http://ilia.ws/archives/12-PHP-Optimization-Tricks.html

验证您的 cronjob 的一个好方法是跟踪您的 cronjob 脚本: 根据您的 cronjob 进程,放置一些调试跟踪,包括多少内存、执行最后一个进程所花费的时间。例如:

<?php

echo "\n-------------- DEBUG --------------\n";
echo "memory (start): " . memory_get_usage(TRUE) . "\n";

$startTime = microtime(TRUE);
// some process
$end = microtime(TRUE);

echo "\n-------------- DEBUG --------------\n";
echo "memory after some process: " . memory_get_usage(TRUE) . "\n";
echo "executed time: " . ($end-$start) . "\n";

通过这样做,您可以轻松找到哪个进程占用了多少内存以及执行它需要多长时间。

6) 外部服务器/网络服务调用 您的 cronjob 是调用外部服务器还是 Web 服务?如果是这样,请确保尽可能快地加载这些内容。如果您从第三方服务器请求数据,并且该服务器需要几秒钟来返回一个答案,这将影响您的 cronjob 的速度,特别是如果这些调用处于循环状态。

试试看,然后告诉我你发现了什么。

【讨论】:

调试代码后,我们发现主 cronjob 服务器和我们正在使用的第三方soap web 服务之间存在延迟。每小时我们需要汇总的记录超过 150,000 条,而这个调用的执行时间太长(每次调用平均需要 2 到 4 秒)。几个小时后,我们找到了解决此问题的方法。我们还使用您提供的命令对我们的服务器进行了一些优化。非常感谢您的帮助【参考方案2】:

ps 的输出还显示进程何时开始(参见列STARTED)。

$ ps auxf
USER    PID  %CPU %MEM     VSZ    RSS   TTY  STAT  STARTED    TIME   COMMAND
root      2   0.0  0.0       0      0   ?    S     18:55      0:00   [ktrheadd]
                                                   ^^^^^^^
(...)

或者你可以自定义输出:

$ ps axfo start,command
STARTED   COMMAND
18:55     [ktrheadd]
(...)

因此,您可以确定它们是否重叠。

【讨论】:

【参考方案3】:

您应该在您的 process_stats_hourly.php 脚本中使用锁定文件机制。不必过于复杂,您可以让 php 将启动进程的 PID 写入 /var/mydir/process_stats_hourly.txt 之类的文件。因此,如果处理统计数据的时间超过一个小时,并且 cron 启动了 process_stats_hourly.php 脚本的另一个实例,它可以检查锁定文件是否已经存在,如果存在则不会运行。

但是,如果每小时脚本确实找到了锁定文件并且无法启动,您将面临如何“重新排队”的问题。

【讨论】:

【参考方案4】:

您可以在其中一个运行时间过长的进程上使用strace -p 1234,其中 1234 是相关的进程 ID。也许你会明白为什么它这么慢,甚至被阻塞。

【讨论】:

【参考方案5】:

Cent OS 中是否有任何工具或我可以做些什么来确保我的 cronjob 每小时运行一次并且不会与下一个重叠?

是的。 CentOS 的标准util-linux 软件包为文件系统锁定提供了命令行便利。正如 Digital Precision suggested,锁文件是同步进程的一种简单方法。

尝试按如下方式调用您的 cronjob:

flock -n /var/tmp/stats.lock process_stats_hourly.php || logger -p cron.err 'Unable to lock stats.lock'

您需要编辑路径并根据需要调整 $PATH。该调用将尝试锁定stats.lock,如果成功则生成您的统计脚本,否则放弃并记录失败。

或者,您的脚本可以调用 PHP 的 flock() 本身来实现相同的效果,但 flock(1) 实用程序已经为您准备好了。

【讨论】:

【参考方案6】:

该日志文件多久轮换一次?

日志解析工作突然比平时花费更长的时间,听起来好像日志没有被轮换,而且现在对于解析器来说太大而无法有效处理。

尝试重置日志文件,看看作业是否运行得更快。如果这样可以解决问题,我建议使用logrotate 作为防止将来出现问题的方法。

【讨论】:

【参考方案7】:

您可以在 cronjob 中添加一个步骤来检查上述命令的输出:

ps auxf | grep process_stats_hourly.php

继续循环,直到命令没有返回任何内容,表明进程没有运行,然后让剩余的代码执行。

【讨论】:

这并不能解决问题,只能延迟它

以上是关于Centos 5 上的慢 cron 作业的主要内容,如果未能解决你的问题,请参考以下文章

在 CentOS 7 上使用 cron 作业运行服务

Centos / Red Hat 服务器中 Cron 作业的退出代码存储在哪里?

如何防止 cron 作业执行(如果它已经在运行)

Docker 并行运行 cron 作业

列出 apscheduler 安排的 cron 作业

我centOS上的MySQL速度很慢