为什么 Cacti 一直在等待死亡的轮询进程?

为什么 Cacti 一直在等待死亡的轮询进程?

我目前正在设置一个新的 Debian (6.0.5) 服务器。昨天我把 Cacti (0.8.7g) 放在上面,从那以后就一直在与它斗争。

创刊号

我观察到的第一个问题是,我的图表没有更新。所以我检查了一下cacti.log,发现了这条令人担忧的消息:

POLLER: Poller[0] Maximum runtime of 298 seconds exceeded. Exiting.

那可不是什么好事,对吧?所以我去查看了一下,然后开始poller.php我自己(通过sudo -u www-data php poller.php --force)。它会发出很多消息(看起来都像我期望的那样),然后挂起一分钟。一分钟后,它会循环显示以下消息:

Waiting on 1 of 1 pollers.

这会持续 4 分钟,直到该进程因运行时间超过 298 秒而被强制终止。

到目前为止,一切都很好

我花了一个小时试图确定哪个轮询器可能仍在运行,直到我得出结论:没有正在运行的轮询器

调试

我检查了poller.php看看这个警告是如何发出的以及为什么会发出。在第 368 行,Cacti 将从数据库中检索已完成进程的数量,并使用该值计算仍在运行的进程数。那么,让我们看看这个值!

我将以下调试代码添加到poller.php

$finished_processes = db_fetch_cell("SELECT count(*) FROM cacti.poller_time WHERE poller_id=0 AND end_time>'0000-00-00 00:00:00'");
print "Finished: " . $finished_processes . " - Started: " . $started_processes . "\n";

结果

这将在启动后一秒内打印以下内容poller.php

Finished: 0 - Started: 1
Waiting on 1 of 1 pollers.
Finished: 1 - Started: 1

因此这些值正在被读取并且是有效的。直到我们到了它不断循环的部分:

Finished:  - Started: 1
Waiting on 1 of 1 pollers.

突然,值消失了。为什么?输入var_dump()以下内容可确认问题:

NULL
Finished:  - Started: 1
Waiting on 1 of 1 pollers.

返回值为NULL。查询时怎么会这样SELECT COUNT()...?(SELECT COUNT()应该始终返回一个结果行,不是吗?)

更多调试

所以我进入lib\database.php并查看了它db_fetch_cell()。经过一些测试确认,结果集实际上是空的。

因此我添加了自己的数据库查询代码来查看其作用:

$finished_processes = db_fetch_cell("SELECT count(*) FROM poller_time WHERE poller_id=0 AND end_time>'0000-00-00 00:00:00'");
print "Finished: " . $finished_processes . " - Started: " . $started_processes . "\n";

$mysqli = new mysqli("localhost","cacti","cacti","cacti");
$result = $mysqli->query("SELECT COUNT(*) FROM poller_time WHERE poller_id=0 AND end_time>'0000-00-00 00:00:00';");
$row = $result->fetch_assoc();
var_dump( $row );

这将输出

Finished:  - Started: 1
array(1) {
  ["COUNT(*)"]=>
  string(1) "2"
}
Waiting on 1 of 1 pollers.

那么,数据是存在的,并且可以毫无问题地访问,只是不能使用 Cacti 使用的方法吗?

再检查一下!

我启用了 MySQL 日志记录以确保我没有想象到这些事情。果然,当错误消息循环播放时,读取cacti.log的内容就像是在疯狂查询:

06/29/2012 08:44:00 PM - CMDPHP: Poller[0] DEVEL: SQL Cell: "SELECT count(*) FROM cacti.poller_time WHERE poller_id=0 AND end_time>'0000-00-00 00:00:00'"
06/29/2012 08:44:01 PM - CMDPHP: Poller[0] DEVEL: SQL Cell: "SELECT count(*) FROM cacti.poller_time WHERE poller_id=0 AND end_time>'0000-00-00 00:00:00'"
06/29/2012 08:44:02 PM - CMDPHP: Poller[0] DEVEL: SQL Cell: "SELECT count(*) FROM cacti.poller_time WHERE poller_id=0 AND end_time>'0000-00-00 00:00:00'"

没有任何这些查询都由 MySQL 记录。但是,当我添加自己的数据库查询代码时,它却显示正常。

在此处输入图片描述
点击放大

这到底发生什么事了?

深层发掘...

我的结论是,数据库连接一定是在某个过程中丢失了,而 adodb 根本不在乎。

经过一番研究,我最终将调试消息放在了函数drivers/adodb-mysql.inc.php的第 529 行_close。我想查看连接何时关闭。

我实际上(终于)打开了 PHP 调试并意识到mysql_query()它是用布尔连接 ID(表示有意关闭的连接)调用的。

// returns true or false
function _close()
{
    @mysql_close($this->_connectionID);
    echo "!!!! CLOSED !!!!\n";
    debug_print_backtrace();
    $this->_connectionID = false;
}

这打印了什么?

oliver@j27773:/etc/php5/conf.d$ sudo -u www-data php /usr/share/cacti/site/poller.php --force
06/30/2012 01:33:49 AM - POLLER: Poller[0] NOTE: Poller Int: '60', Cron Int: '300', Time Since Last: '61', Max Runtime '298', Poller Runs: '5'
06/30/2012 01:33:49 AM - POLLER: Poller[0] DEBUG: About to Spawn a Remote Process [CMD: /usr/bin/php, ARGS: -q "/usr/share/cacti/site/cmd.php" 0 3]
Finished: 0 - Started: 1
Waiting on 1 of 1 pollers.
Finished: 1 - Started: 1
06/30/2012 01:33:50 AM - POLLER: Poller[0] CACTI2RRD: /usr/bin/rrdtool update /var/lib/cacti/rra/j27773_servers_jiffybox_net_apache_sb_keepalive_100.rrd --template apache_sb_keepalive 1341012829:0
06/30/2012 01:33:50 AM - POLLER: Poller[0] CACTI2RRD: /usr/bin/rrdtool update /var/lib/cacti/rra/j27773_servers_jiffybox_net_apache_reqpersec_95.rrd --template apache_reqpersec 1341012829:.0228409
06/30/2012 01:33:50 AM - POLLER: Poller[0] CACTI2RRD: /usr/bin/rrdtool update /var/lib/cacti/rra/j27773_servers_jiffybox_net_apache_bytesperreq_90.rrd --template apache_bytesperreq 1341012829:13925.7
06/30/2012 01:33:50 AM - POLLER: Poller[0] CACTI2RRD: /usr/bin/rrdtool update /var/lib/cacti/rra/j27773_servers_jiffybox_net_cpu_85.rrd --template cpu 1341012829:1
OK u:0.00 s:0.00 r:1.00
06/30/2012 01:33:50 AM - POLLER: Poller[0] CACTI2RRD: /usr/bin/rrdtool update /var/lib/cacti/rra/j27773_servers_jiffybox_net_hdd_used_80.rrd --template hdd_used:hdd_total 1341012829:924741632:2677886976
OK u:0.00 s:0.00 r:1.00
OK u:0.00 s:0.01 r:1.00
OK u:0.00 s:0.01 r:1.00
06/30/2012 01:33:50 AM - POLLER: Poller[0] CACTI2RRD: /usr/bin/rrdtool update /var/lib/cacti/rra/j27773_servers_jiffybox_net_apache_sb_wait_105.rrd --template apache_sb_wait 1341012829:9
OK u:0.00 s:0.01 r:1.00
OK u:0.00 s:0.01 r:1.00
06/30/2012 01:33:50 AM - SYSTEM STATS: Time:1.1261 Method:cmd.php Processes:1 Threads:N/A Hosts:2 HostsPerProcess:2 DataSources:7 RRDsProcessed:6
Loop  Time is: 1.1291718482971
Sleep Time is: 58.867464065552
Total Time is: 1.1325359344482
!!!! CLOSED !!!!
#0  ADODB_mysql->_close() called at [/usr/share/php/adodb/adodb.inc.php:2141]
#1  ADOConnection->Close() called at [/usr/share/cacti/site/lib/database.php:68]
#2  db_close() called at [/usr/share/cacti/site/poller.php:455]
^C06/30/2012 01:33:55 AM - CMDPHP: Poller[0] WARNING: Cacti Master Poller process terminated by user

现在我太累了,不想再调查这件事了……

答案1

我做了进一步调查,发现关闭与数据库的连接是故意的。应该在下一次轮询运行前重新建立连接。但事实并非如此。

以下为摘录poller.php

if ($poller_runs_completed < $poller_runs) {
    db_close();
    // Debug message by myself
    echo "RECONNECTING IN " . $sleep_time . "\n";
    usleep($sleep_time * 1000000);
    db_connect_real($database_hostname, $database_username, $database_password, $database_default, $database_type, $database_port);
}

我还检查了一下db_connect_real,它实际上是在usleep完成后调用的。所以我将继续深入研究这个问题。

暂时,我修改了如下部分:

if ($poller_runs_completed < $poller_runs) {
    //db_close();
    // Debug message by myself
    echo "RECONNECTING IN " . $sleep_time . "\n";
    usleep($sleep_time * 1000000);
    //db_connect_real($database_hostname, $database_username, $database_password, $database_default, $database_type, $database_port);
}

现在轮询器运行没有任何警告,我的图表也绘制出来了。然而,还有一个问题。并非所有的图表都绘制正确,如下图所示:

显示解决方法结果的渲染图
点击放大

我认为这是由于轮询器对某些数据源运行得太少。为了解决这个问题,我切换到脊柱(无论如何我都想这么做)并将其设置为使用 4 个线程。

Cacti 轮询器配置

到目前为止,一切都很好...

更新

我深入研究了这个问题,并认为我已经解决了它。我假设在轮询器尝试重新连接后,连接没有正确存储。

我解决这个问题的尝试一开始看起来很有希望,但得到的图表仍然有缺陷。所以问题更深层。

我之前开发并在此答案中介绍的解决方法仍然有效。我决定不再在这个问题上投入更多时间,而是继续使用解决方法。抱歉。

相关内容