2023-09-15 11:24:38

Мониторинг скорости интернета без MRTG

Linux RRDtool

Speedtest graph

Популярный много лет назад MRTG давно ушел в историю и уступил место collectd в связке с RRDtool, или другим, более удобным решениям для мониторинга. Но тут пойдет речь о метрике, до которой collectd не смог дотянуться, а именно о реальной скорости подключения к Интернет.


Есть хорошо известный Speedtest от Ookla, который привычно использовать в виде приложения или на сайте, чтоб узнать скорость после смены тарифа или провайдера, но что делать, когда хочется понимать какая скорость была на протяжении времени, если канал от провайдера оставляет желать лучшего?

Именно с этим я столкнулся, когда перешел на домашний интернет от мегафона (он же нет-бай-нет), вечером скорость заметно проседала, а днем вроде все работало нормально, мне нужны были данные, чтоб мотивировать провайдера заниматься поблемой.

Как выяснилось, существует Speedtest CLI, который было решено использовать для сбора данных. Этот инструмент умеет выдавать результаты в разных форматах, включая JSON и CSV (см. актуальный хелп в приложении, а не тот что от 2018 года разбросан по интернету, с тех пор все немного изменилось).

Завести этот инструмент в collectd через exec-plugin не получилось, приложение speedtest, запускаемое collectd насыпает в STDERR и в результаты exec-plugin попадает не пойми что. Зато оно прекрасно работает чрез cron от текущего пользователя. Поскольку сбор метрик от speedtest нужен совсем не часто, раз в 10 минут или реже, и разбираться с collectd было совсем неохота, то остановился на решении, которое по крону собирает метрики скорости и записывает в RRD. А данные из RRD рисуются на страничке мониторинга рядом с графиками собранными collectd.

Для реализации задуманного понадобится rrdtool и nginx, предполагается, что это все уже было установлено вместе с collectd.

Создаем базу для хранения данных (краткий мануал тут, подробнее тут):

rrdtool create /var/lib/collectd/rrd/speedtest.rrd \
        --step 10m \
        DS:download:GAUGE:30m:0:U \
        DS:upload:GAUGE:30m:0:U \
        RRA:AVERAGE:0.5:10m:7d \
        RRA:AVERAGE:0.5:1h:2M \
        RRA:AVERAGE:0.5:1d:3y

И ставим в крон раз в 10 минут скрипт:

#!/bin/sh

TEST=$(/usr/bin/speedtest -f csv)
RET=$?

if [ $RET -eq 0 ]; then
    D=$(echo \"$TEST\" | cut -d, -f6 | tr -d '\"')
    U=$(echo \"$TEST\" | cut -d, -f7 | tr -d '\"')
else
    D="0"
    U="0"
fi

rrdtool update /var/lib/collectd/rrd/speddtest.rrd N:$D:$U

Важный момент, Speedtest CLI в машинных форматах скорости загрузки и скачивания выдает в байтах в секунду (Bps), поэтому чтоб получить привычные мегабиты из, например, CSV, нужно значение умножить на 8 и поделить на 1000000 (ну или просто поделить значение на 125000). Это будет сделано ниже при рисовании графика.

На веб сервере в конфиге убеждаемся что есть для нужного хоста:

location ~ \.cgi {
        fastcgi_pass unix:/var/run/fcgiwrap.socket;
        include fastcgi_params;
    }

И создаем или изменяем файл collectd.cgi (он должен лежать где-то в document_root и быть исполняемым):

#!/usr/bin/rrdcgi
<RRD::GOODFOR 60>
<RRD::SETENV LANG ru_RU.UTF-8>
<RRD::SETENV LC_TIME ru_RU.UTF-8>
<RRD::SETVAR dt '<RRD::TIME::NOW "%d.%m.%Y %H:%M">'>

<RRD::SETVAR graph_w 900>
<RRD::SETVAR graph_h 200>
<RRD::SETVAR graph_path "graph">
<RRD::SETVAR font "DEFAULT:9:">
<RRD::SETVAR start "-12 hours">

<RRD::SETVAR data_dir "/var/lib/collectd/rrd">
<RRD::SETVAR speedtestdb "<RRD::GETVAR data_dir>/speedtest.rrd">
<!DOCTYPE html>
<html lang="ru-RU">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="refresh" content="60">
    <title><RRD::GETVAR dt></title>
</head>
<body>

<RRD::GRAPH <RRD::GETVAR graph_path>/speedtest-<RRD::CV show>.png
    --lazy
    --imginfo '<img src="<RRD::GETVAR graph_path>/%s" width="%lu" height="%lu">'
    --title="Speedtest"
    --vertical-label="Mbits"
    -w <RRD::GETVAR graph_w> -h <RRD::GETVAR graph_h>
    --slope-mode
    --font <RRD::GETVAR font>
    --start "-1 <RRD::CV show>" --end "-0"
    --lower-limit 0

    DEF:down=<RRD::GETVAR speedtestdb>:download:AVERAGE
    DEF:up=<RRD::GETVAR speedtestdb>:upload:AVERAGE
    CDEF:in=down,125000,/
    CDEF:out=up,125000,/

    AREA:in#6afff380:"Download" GPRINT:in:MIN:"Min\: %1.1lf%s" GPRINT:in:MAX:"Max\: %1.1lf%s" GPRINT:in:AVERAGE:"Avg\: %.1lf%s" GPRINT:in:LAST:"Last\: %.1lf%s\j"
    LINE2:out#bf71ff:"Upload" GPRINT:out:MIN:"Min\: %.1lf%s" GPRINT:out:MAX:"Max\: %.1lf%s" GPRINT:out:AVERAGE:"Avg\: %.1lf%s" GPRINT:out:LAST:"Last\: %.1lf%s\j"
    LINE:in#00b3a4
>

</body>
</html>

Подробнее по работе с rrdcgi можно посмотреть в официальном мануале. А обращаться к нему нужно по ссылкам вида http://myhost/collectd.cgi?show=[hour|day|week|month|year]. Результат такого графика в самом верху.