123
分类: LINUX
2014-04-14 11:33:40
原文地址:Cacti分布式监控 作者:傲雪红梅
现有的CACTI服务器只有一台,被监控的网络设备有332台,因此每5分钟需要对332个节点进行一次数据采集,9518个RRD文件进行写入,导致磁盘出现了严重的IO瓶颈,致使在WEB界面上的操作速度慢的让人无法忍受,严重的影响了Cacti日常管理。因此决定将其改造为分布 式。这样,一方面可以解决性能问题,另一方面可以解决异网内无公网IP地址设备的监控。
整个分布式Cacti由三台服务器组成:
1、cacti78.cm3用来采集CDN的数据,同时接收CDN二层设备被动监控的数据;
主动采集CDN设备的RRD数据存放在/home/cacti/rra/cacti78.cm3目录下
被动采集CDN设备的RRD数据存放在/home/cacti/rra/passive目录下
2、cacti79.cm3用来采集主站的数据。
采主站的RRD数据存放在/home/cacti/rra/cacti79.cm3目录下
3、cacti80.cm3用来做WEB界面展示;
生成图像时用到的RRD数据通过NFS,将cacti78.cm3和cacti79.cm3采集的数据加载到本地。
由于Cacti的数据库主要是用来存储配置信息的,因此我的第一个想法就是用一个数据库来支撑三台Cacti,这看起来是个不错的想法,于是 就按这种方法搭建了起了分布式Cacti。当一切配置完成之后,绘出的图让我失望了,开始时是断断续续,到了后面干脆就没了图像。一开始我并 没有想明白是怎么回事,就到处查资料,结果好不容易找到了一个方法,就是在crontab里的定期执行命令:php poller.php命令后面加个“--force”参数,强制执行这个命令,这 次让我看到了一点点的希望,终于可以绘出断断续续的图来。可为什么会断断续续的绘图呢?
通过阅读源代码,我发现原来Cacti每次采集数据的时候,不仅仅要读数据库,还要写数据库。具体的要写哪些表呢?第一个就是settings表的name字段名为poller_lastrun的行,该行后 面的value字 段存储的是上次进行数据采集的时间截,每当采集数据之前,都会读取这个值,并用当前时间截减去上次时间截,并判断是否为300秒(即数据采集间隔5分钟),如果为300秒,则进行数据采集,并将当前时间截 写入数据库;否则不进行数据采集。加了“--force”参数就是为了不进行采集间隔的判断,直接采集数据,因为有两台采集服务器同时写表,导致时间不对。 加了该参数之后图是绘出来了,可是不连续。
为了解决图不连续的问题,我再次深入研究,发现Cacti除了写这个settings的表,还写了名为poller的相关表,这些表是用来存储poller需要的一些临时数据的。由于两个采集服务器同时对这些表进行写和删除操盘,造成数据混乱。
基于以上分析,分布式Cacti只能拥有各自的数据库,而不能共享同一个库。因此采用三个库,一主两从的方法。cacti80.cm3上的数据库为主库,cacti78.cm3、cacti79.cm3上的库为从库,我们 平时的配置修改操作都在cacti80.cm3上,这个库的数据变化都会同步到其它两个库上,而对每次数据采集都会写入数据的几个表则不进行同步, 这几个表分别是: poller、poller_command、poller_output、poller_reindex、poller_time。
为了让两台服务器(cacti78.cm3、cacti79.cm3)进行数据采集的分工合作,我们首先需要改造页面源代码,就是当我们新加一台被动监控设备时,要区 别这台设备由哪台服务器来采集数据。修改后的源代码如下图,从下图的“Choose Spine Agent”后面的下拉列表中即可以选择用哪台服务器采集数据。我们规 定,所有CDN的 设备均选择“cacti78.cm3”这台服务器来采集数据;主站的设备均选择“cacti79.cm3”这台服务器来采集数据;被动监控均选择“passive”,表示不采集数据。该下拉列表将直接更改host表的disabled字段的值,由于该字段只支持两个字符,因此需要修改表结构,我修改的是支持20个字符。
由于每个采集服务器采集的数据必须放在不同目录下,以便通过NFS加载到WEB服务器(cacti80.cm3)上。因此,还需要 修改源代码lib/function.php,以便创建图片时生成的数据源路径分别属于各自的目录,比如选择cacti78.cm3采集数据,则创建图片 时生成的数据源在/home/cacti/rra/cacti78.cm3目录下;选择cacti79.cm3采集数据,则创建图片时生成的数据源在/home/cacti/rra/cacti79.cm3目录下。因此,选择由谁来采集数据一定要在创建图片之前操作,否则数据源的路径是会出错的。
两台采集服务器采集数据使用的是spine,为了能让它们各自采集自己负责的设备,还需要修改 spine.c源代码。让它每次采集只选择host表的disabled为“cacti78.cm3”或“cacti79.cm3”的设备进行数据采 集。
php poller.php --collect=< 采集服务器>
采集服务器是指你在WEB界面上添加一台设备时,在“Choose Spine Agent”后 面的下拉框里选择的内容。
例如:
Cacti78.cm3 上的crontab里就写
*/5 * * * * /opt/php/bin/php pollerr.php --collect=cacti78.cm3
Cacti79.cm3 上的crontab里就写
*/5 * * * * /opt/php/bin/php pollerr.php --collect=cacti79.cm3
修改include/global_form.php
"disabled" => array(
"method" => "drop_array",
"friendly_name" => "Choose Spine Agent",
"description" => "Choose a spine agent to checks for
this host.",
"value" => "|arg1:disabled|",
"default" => read_disabled("hostname"),
"array" => $spine_agent
),
修改include/ global_arrays.php,添加以下内容
$spine_agent
= array(
0 =>
"",
"cacti78.cm3" => "cacti78.cm3",
"cacti79.cm3" => "cacti79.cm3",
"passive"
=> "passive");
修改lib/ functions.php,添加以下内容
function
read_disabled($ip) {
$disabled =
db_fetch_cell("select disabled from host where hostname='$ip'");
return $disabled;
}
修改lib/function.php
$host =
db_fetch_row("SELECT
host.id,
host.description,
host.disabled
FROM
(host, data_local)
WHERE
data_local.host_id=host.id
AND
data_local.id=$local_data_id
LIMIT
1");
$host_spine =
$host["disabled"];
$new_path
=
"
$new_path
= "
修改lib/snmp.php
,在“function cacti_snmp_walk”函数下面添加以下内容
$banned_snmp_strings
= array("End of MIB", "No
Such"); //Add by qiudi.
修改include/global.php
#$config["rra_path"]
= $config["base_path"]
. '/rra';
$config["rra_path"]
= "/home/cacti/rra";
(1)修改poller.php源代码
找到:foreach($parms as $parameter)
加入:
case
"--collect":
$spine_agent =
$value;
break;
修改:
$polling_hosts
= array_merge(array(0 => array("id"
=> "0")), db_fetch_assoc("SELECT id FROM host WHERE disabled
= '$spine_agent'
ORDER BY id"));
查找:“$poller == "2") {”
修改:
if ($poller ==
"2") {
$command_string = read_config_option("path_spine");
$extra_args =
"--collect=".$spine_agent;
(2)修改spine.c源代码
在main函
数里定义变量:
char
*spine_agent = NULL;
找到:for (argv++; *argv; argv++)
加入:
else if
(STRMATCH(arg,"-c") ||
STRMATCH(arg,"--collect")){
spine_agent =
strdup(getarg(opt,&argv));
}
修改:qp += sprintf(qp, " WHERE disabled=''");(两处)
为:
qp +=
sprintf(qp, " WHERE
disabled='%s'",spine_agent);