CentOS 5上的cronjobs运行缓慢

33

我有一个cronjob,每60分钟运行一次,但最近出现了运行缓慢的问题。

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

这是cronjob的执行步骤:

  1. 解析过去60分钟的数据

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

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

  2. 基于步骤1中的数据

    a)生成简要报告并向管理员/业务发送电子邮件

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

当我运行命令ps auxf | grep process_stats_hourly.php时,现在看到8个进程(相同的文件)。我应该只有一个而不是8个。

在CentOS中是否有任何工具或我可以做些什么来确保我的cronjob每小时运行一次而不会重叠?

谢谢


1
你看到了8个。你确定之前的7个任务都成功完成了吗?你能否观察数据库中数据的逐渐减少(如果刷新,则可以看到进程仍在积极工作中)? - Shackrock
7个回答

46

您的硬件似乎足够处理此任务。

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

2) 检查您的网络连接: 如果您的数据库和cron作业位于不同的服务器上,您应该检查这两台机器之间的响应时间。也许您遇到了网络问题,导致cron作业等待网络发送回复。

您可以使用 Netcat, Iperf, mtrttcp

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是否调用外部服务器或网络服务?如果是,请确保尽快加载。如果您从第三方服务器请求数据,并且该服务器需要几秒钟才能返回答案,那么这将影响cronjob的速度,特别是如果这些调用在循环中。

请尝试并告诉我您发现了什么。


2
调试代码后,我们发现主计划作业服务器和我们使用的第三方SOAP Web服务之间存在延迟。每小时我们有150,000多条记录需要总结,而这个调用执行时间太长(平均每个调用需要2到4秒)。几个小时后,我们找到了解决这个问题的方法。我们还使用您提供的命令对服务器进行了一些优化。非常感谢您的帮助。 - Tech4Wilco

6
< p > < code > ps 的输出还显示了进程何时启动(请参见列 < code > STARTED )。< /p >
$ 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]
(...)

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

4
你应该在process_stats_hourly.php脚本中使用锁定文件机制。这并不需要过于复杂,你可以让php将启动该进程的PID写入像/var/mydir/process_stats_hourly.txt这样的文件中。因此,如果处理统计数据需要超过一小时,且计划任务再次启动process_stats_hourly.php脚本,它可以检查锁定文件是否已经存在,如果存在则不会运行。
但是,如果找到锁定文件无法启动,则仍需解决“重新排队”每小时脚本的问题。

2

你可以使用strace -p 1234命令,其中1234是一个相关的进程ID,来跟踪运行时间过长的进程之一。也许你会明白它为什么如此缓慢,甚至被阻塞。


2
有没有在CentOS中的工具或者其他方法可以确保我的cronjob每小时运行一次,而不会与下一个cronjob重叠?
是的。CentOS标准的util-linux软件包提供了文件系统锁定的命令行工具。正如Digital Precision建议的那样,lockfile是同步进程的简单方法。
尝试按以下方式调用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) 实用程序已经为您准备好了。


1

日志文件轮换的频率是多少?

如果日志没有被轮换并且现在太大以至于解析器无法高效处理,那么日志解析作业突然变得比平常慢听起来就像这样。

尝试重置日志文件并查看作业是否运行更快。如果问题得到解决,我建议使用logrotate来防止未来出现类似问题。


-1
你可以在cronjob中添加一步骤来检查上述命令的输出: ps auxf | grep process_stats_hourly.php 循环执行,直到命令返回空值,表示进程未运行,然后允许剩余代码执行。

9
那样做无法解决问题,只会拖延。 - Pat R Ellery

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接