現有的CACTI服務器只有一臺,被監控的網絡設備有332臺,所以每5分鐘須要對332個節點進行一次數據採集,9518個RRD文件進行寫入,致使磁盤出現了嚴重的IO瓶頸,導致在WEB界面上的操做速度慢的讓人沒法忍受,嚴重的影響了Cacti平常管理。所以決定將其改造爲分佈 式。這樣,一方面能夠解決性能問題,另外一方面能夠解決異網內無公網IP地址設備的監控。php
整個分佈式Cacti由三臺服務器組成:數據庫
一、cacti78.cm3用來採集CDN的數據,同時接收CDN二層設備被動監控的數據;服務器
主動採集CDN設備的RRD數據存放在/home/cacti/rra/cacti78.cm3目錄下網絡
被動採集CDN設備的RRD數據存放在/home/cacti/rra/passive目錄下架構
二、cacti79.cm3用來採集主站的數據。分佈式
採主站的RRD數據存放在/home/cacti/rra/cacti79.cm3目錄下ide
三、cacti80.cm3用來作WEB界面展現;函數
生成圖像時用到的RRD數據經過NFS,將cacti78.cm3和cacti79.cm3採集的數據加載到本地。性能
因爲Cacti的數據庫主要是用來存儲配置信息的,所以個人第一個想法就是用一個數據庫來支撐三臺Cacti,這看起來是個不錯的想法,因而 就按這種方法搭建了起了分佈式Cacti。當一切配置完成以後,繪出的圖讓我失望了,開始時是斷斷續續,到了後面乾脆就沒了圖像。一開始我並 沒有想明白是怎麼回事,就處處查資料,結果好不容易找到了一個方法,就是在crontab裏的按期執行命令:php poller.php命令後面加個「--force」參數,強制執行這個命令,這 次讓我看到了一點點的但願,終於能夠繪出斷斷續續的圖來。可爲何會斷斷續續的繪圖呢?fetch
經過閱讀源代碼,我發現原來Cacti每次採集數據的時候,不只僅要讀數據庫,還要寫數據庫。具體的要寫哪些表呢?第一個就是settings表的name字段名爲poller_lastrun的行,該行後 面的value字 段存儲的是上次進行數據採集的時間截,每當採集數據以前,都會讀取這個值,並用當前時間截減去上次時間截,並判斷是否爲300秒(即數據採集間隔5分鐘),若是爲300秒,則進行數據採集,並將當前時間截 寫入數據庫;不然不進行數據採集。加了「--force」參數就是爲了避免進行採集間隔的判斷,直接採集數據,由於有兩臺採集服務器同時寫表,致使時間不對。 加了該參數以後圖是繪出來了,但是不連續。
爲了解決圖不連續的問題,我再次深刻研究,發現Cacti除了寫這個settings的表,還寫了名爲poller的相關表,這些表是用來存儲poller須要的一些臨時數據的。因爲兩個採集服務器同時對這些表進行寫和刪除操盤,形成數據混亂。
基於以上分析,分佈式Cacti只能擁有各自的數據庫,而不能共享同一個庫。所以採用三個庫,一主兩從的方法。cacti80.cm3上的數據庫爲主庫,cacti78.cm三、cacti79.cm3上的庫爲從庫,咱們 平時的配置修改操做都在cacti80.cm3上,這個庫的數據變化都會同步到其它兩個庫上,而對每次數據採集都會寫入數據的幾個表則不進行同步, 這幾個表分別是:poller、poller_command、poller_output、poller_reindex、poller_time。
爲了讓兩臺服務器(cacti78.cm三、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 = "<path_rra>/$host_spine/$host_id/$local_data_id.rrd";
$new_path = "<path_rra>/$host_spine/$host_part$ds_part" . "_" . "$local_data_id.rrd";
修改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);