LibreNMS 的設備一多,輪詢時寫 RRD 檔的磁碟 I/O 會越來越重,官方建議啟用 rrdcached 把寫入集中、批次處理,效果很明顯。但啟用之後,我發現 Weathermap 的流量圖不會更新了,地圖上的連線全部沒有數字。
追下去是 Weathermap 外掛在 rrdcached 模式下的兩個路徑處理問題,改兩個檔案就好了。這篇記錄原因與修改方式。
環境
| 項目 | 內容 |
|---|---|
| LibreNMS | 安裝於 /opt/librenms,RRD 目錄 /opt/librenms/rrd |
| rrdcached | 與 LibreNMS 同一台,以 TCP 連線 localhost:42217 |
| Weathermap | LibreNMS 官方外掛(librenms-plugins/Weathermap),位於 /opt/librenms/html/plugins/Weathermap |
LibreNMS 這邊的 rrdcached 設定:
lnms config:set rrdcached "localhost:42217"
lnms config:get rrd_dir
症狀
- LibreNMS 本身的流量圖正常,代表 rrdcached 運作沒問題
- Weathermap 的地圖會產生,但連線上的流量都是 0 或沒有數值
- 手動執行 Weathermap 的輪詢,記錄裡看得到 rrdtool 找不到 RRD 檔案的錯誤
手動執行的方式:
cd /opt/librenms/html/plugins/Weathermap
sudo -u librenms php map-poller.php
要看更詳細的過程,可以直接對單一地圖加上 --debug:
sudo -u librenms php weathermap.php --config configs/core.conf --debug \
--daemon localhost:42217 --chdir /opt/librenms/rrd
原因
Weathermap 地圖設定裡的資料來源,通常是像這樣的相對路徑:
TARGET ./core-sw01/port-id12.rrd
沒有 rrdcached 時,Weathermap 會先切換到 RRD 目錄(--chdir)再讀檔,相對路徑沒有問題。啟用 rrdcached 後,讀取改由 rrdtool 透過 --daemon 交給 rrdcached 處理,路徑的處理就出了兩個問題。
問題一:--chdir 傳了空字串
map-poller.php 在 rrdcached 走 TCP 連線時,組出來的指令是:
$cmd = $cmd." --daemon ".$config['rrdcached']." --chdir ''";
--chdir '' 等於沒有切換到 RRD 目錄,相對路徑就對不到正確的檔案。
問題二:trim() 的用法錯了
資料來源的程式 WeatherMapDataSource_rrd.php 想把路徑開頭的 ./ 拿掉,寫成:
$rrdfile = trim($rrdfile, "^./");
但 PHP 的 trim() 第二個參數是字元清單,不是正規表示式:它會把字串兩端所有的 ^、.、/ 字元都去掉,^ 在這裡沒有「開頭」的意思。所以只要路徑是絕對路徑,例如 /opt/librenms/rrd/core-sw01/port-id12.rrd,開頭的 / 也會被拿掉,變成錯誤的相對路徑。
修改方式
map-poller.php
cp /opt/librenms/html/plugins/Weathermap/map-poller.php{,.bak}
nano /opt/librenms/html/plugins/Weathermap/map-poller.php
找到 TCP 連線那一段:
$cmd = $cmd." --daemon ".$config['rrdcached']." --chdir ''";
改成切換到 LibreNMS 的 RRD 目錄:
$cmd = $cmd." --daemon ".$config['rrdcached']." --chdir ".$config['rrd_dir'];
同一段上面還有一個判斷:rrdcached 用 unix socket(設定值含 unix:)時走的是另一個分支,這裡改的只影響 TCP 連線的情況。
WeatherMapDataSource_rrd.php
cp /opt/librenms/html/plugins/Weathermap/lib/datasources/WeatherMapDataSource_rrd.php{,.bak}
nano /opt/librenms/html/plugins/Weathermap/lib/datasources/WeatherMapDataSource_rrd.php
找到:
$rrdfile = trim($rrdfile,"^./");
改成用正規表示式,只拿掉開頭的 ./:
$rrdfile = preg_replace('/^\.\//', '', $rrdfile);
這個檔案裡有兩個讀取 RRD 的函式,都有一段「rrdcached Support: strip "./" from Data Source」,兩處都要檢查。我在寫這篇時看了上游最新的程式碼,其中一處已經改成 preg_replace,另一處(wmrrd_read_from_real_rrdtool_aggregate)還是 trim();你手上的版本可能兩處都還是舊寫法。
可以用 grep 確認:
grep -n 'rrdfile = ' /opt/librenms/html/plugins/Weathermap/lib/datasources/WeatherMapDataSource_rrd.php
驗證
cd /opt/librenms/html/plugins/Weathermap
sudo -u librenms php map-poller.php
ls -l output/
output/ 裡的地圖圖檔時間有更新,打開 Weathermap 頁面看到連線上的流量數字,就修好了。Weathermap 的排程一般是放在 cron 每 5 分鐘跑一次:
*/5 * * * * librenms /opt/librenms/html/plugins/Weathermap/map-poller.php >> /dev/null 2>&1
注意事項
- 外掛更新會蓋掉修改:Weathermap 是用 git 放在
html/plugins/底下的,之後git pull更新時這兩處修改可能被覆蓋或造成衝突。建議把修改存成 patch,更新後再套用一次:
cd /opt/librenms/html/plugins/Weathermap
git diff > ~/weathermap-rrdcached.patch
# 更新後
git apply ~/weathermap-rrdcached.patch
- 檔案權限:改完後確認檔案擁有者仍是
librenms,否則網頁或排程讀不到 - rrdcached 在其他主機時:rrdcached 在遠端主機時,路徑是以遠端 rrdcached 的基底目錄(
-b參數)為準,LibreNMS 這邊的rrd_dir不一定適用,要依實際架構調整
結論
rrdcached 對 LibreNMS 的效能幫助很大,但外掛不一定都跟上了。這次的兩個問題,一個是傳了空的工作目錄,一個是把 trim() 當成正規表示式在用,改起來不難,難的是從「圖不會動」找到這兩行。有在用 Weathermap 又想啟用 rrdcached 的朋友,可以先照這篇檢查一下。
參考資料
- LibreNMS 文件:RRDCached
https://docs.librenms.org/Extensions/RRDCached/ - LibreNMS Weathermap 外掛(GitHub)
https://github.com/librenms-plugins/Weathermap - PHP 手冊:trim
https://www.php.net/manual/en/function.trim.php



