Сервис мониторинга доступности сайтов своими руками
@low_digitalНачну, как всегда, из далека. Мониторинг доступности – вещь обязательная для любого владельца сайта/системного администратора/студии. Крайне важно вовремя реагировать на сбои в работе и кибератаки.
Кучу лет назад, я воспользовался первым попавшимся сервисом, который позволял осуществлять мониторинг бесплатно – это был Pingdom. Ограничения в 1 бесплатный аккаунт легко обходились алиасами почты (т.е. при регистрации я указываю разные ящики, но уведомления приходят все равно на мою основную почту) и публичной статистикой, где можно посмотреть скорость загрузки сайта и графики аптайма (просто сохраняешь публичные ссылки и периодически открываешь папку этих сохраненных ссылок для проверки).
Позже, Pingdom изменили ценовую политику и отказались от бесплатных тарифов – пришлось искать альтернативу. К тому моменту у меня у меня скопилось более 20 сайтов для мониторинга (при этом я мониторил не все сайты, а лишь те, которые находятся на разных серверах, т.к. основная моя проблема была в падающем MySQL при высокой нагрузке). Тарифы разных сервисов примерно одинаковые (10 сайтов / 50 сайтов / много сайтов), разница лишь в цене. Средний ценник за пакет из 50 сайтов на мониторинге - $50/мес., что довольно дорого, ведь клиенты (по крайней мере мои) не понимают зачем им этот мониторинг и не готовы платить за него.
В поисках самого бюджетного варианта, я наткнулся на сервис UpTimeRobot за $8/мес. и пользовался им последние 2 года. Но последнее время он всё чаще и чаще меня начал напрягать ложными срабатываниями, прилетает уведомление «САЙТ СДОХ», открываю, проверяю – всё нормально. Как оказалось, это работает и в обратную сторону – последнюю неделю я занимаюсь оптимизацией расходов на нашу ИТ-инфраструктуру (об этом тоже будет отдельный пост). Это подразумевает определенные работы, в том числе и остановку серверов, и что же UpTimeRobot? Он никак не отреагировал (либо отреагировал слишком поздно) на остановку половины серверов. И это касается не только уведомлений, в личном кабинете, спустя время UpTimeRobot также показывал 100% аптайм.
Такой казус заставил меня опять вернуться к поискам альтернативы, но все решения на рынке ужасно дорогие – под мои задачи, в среднем, 3 – 4 тыс. руб. И я подумал: «а что если поискать self-hosted альтернативы?». Сервер под такие задачи обойдется в 100-150 руб., а шанс, что одновременно упадет какой-то сайт вместе с сервисом мониторинга кране близок к нулю и этим вполне можно пренебречь.
В новых поисках я наткнулся на сервис «Upptime» и он оказался еще лучше, чем я желал – уведомления в любые мессенджеры, интерфейс приятней, чем у любой платной альтернативы и даже отдельный сервер под него не нужен – он работает на базе GitHub Pages, а это значит, что решение будет полностью бесплатным, а аптайм такого сервиса мониторинга еще выше, чем при любом self-hosted решении. Установка происходит в пару кликов: регистрируемся на GitHub, клонируем репозиторий и… ловим бан!
Я так и не понял, что произошло и что я успел нарушить за 30 секунд владения аккаунтом. Техподдержка не отвечает уже третий день. И это вынудило меня продолжить поиски.
Другие self-hosted решения на которые я натыкался оказались куском говна, ужасный интерфейс, добавление сайтов - через консоль, отсутствие уведомлений в мессенджеры или хотя бы веб-хуков. А ведь это и есть основной функционал сервиса мониторинга! Какой толк от уведомления на почту, если на нее и без того валится куча мусора, среди которого ты навряд ли заметишь нужное письмо с тревогой вовремя? Реагировать на проблемы с доступностью сайта необходимо молниеносно и лучший способ это обеспечить - уведомления в телегу.
В поисках подходящего решения я словил себя на мысли, что основной функционал подобных сервисов - это именно уведомления, а не куча настроек или графики аптайма (в личный кабинет UpTimeRobot за 2 года я заходил лишь пару раз).
А ведь уведомления - это не что-то шибко сложное, так почему бы самому не реализовать этот функционал? Сегодня мы опять будем решать свои проблемы "по бичу".
1) Создаем json-файл monitors.json, где мы будем хранить список сайтов для мониторинга
[
"https://yandex.ru",
"https://google.com"
]
2) Создаем php-файл check.php, который будет осуществлять замеры
<?php
//API-токен нашего Telegram-бота
$tg_token = "4555464:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
//кому шлем уведомления в Telegram
$tg_chat_id = 12345;
//загружаем список сайтов для мониторинга
$monitors = json_decode(file_get_contents('monitors.json'));
//создаем массив для работы
$output = array();
//загружаем предыдущий результат
$last_update = json_decode(file_get_contents('output.json'));
foreach ($monitors as $monitor) {
$status = "ok";
$http_code = "0";
$startScriptTime = microtime(TRUE);
file_get_contents($monitor, false, stream_context_create(['http' => ['ignore_errors' => true]]));
$endScriptTime = microtime(TRUE);
$totalScriptTime = $endScriptTime - $startScriptTime;
if ($http_response_header == NULL){
//сначала проверим ответ и отсечем несуществующие домены
$status = "connection error";
} elseif ($totalScriptTime > 30){
//укажем на слишком долгую загрузку страницы (более 30 секунд)
$status = "conection timeout";
} else {
//получим http-код ответа
$status_line = $http_response_header[0];
preg_match('{HTTP\/\S*\s(\d{3})}', $status_line, $match);
$http_code = $match[1];
//нас устраивает ответ только 2хх, остальные - ошибка
if ($http_code[0] != 2){
$status = "http error";
}
}
//сверим полученный статус доступности сайта с предыдущим
//если статус изменился с момента предыдущей проверки - шлем уведомление в Telegram
if ($last_update -> $monitor -> {'status'} != $status){
$tg_message = "$monitor: $status (previous value: ".$last_update -> $monitor -> status.")";
$tg_data = [
'parse_mode' => 'Markdown',
'chat_id' => $tg_chat_id,
'text' => $tg_message
];
$tg_response = file_get_contents("https://api.telegram.org/bot$tg_token/sendMessage?".http_build_query($tg_data));
}
$output_item['status'] = $status;
$output_item['http_code'] = $http_code;
$output_item['time'] = number_format($totalScriptTime * 1000, 0); //для удобства, преобразуем скорость загрузки в миллисекунды
$output[$monitor] = $output_item;
}
//сохраняем значения
file_put_contents('output.json', json_encode($output));
3) Теперь добавим наш скрипт в планировщик задач сервера, чтобы он выполнялся каждую минуту
В принципе готово - теперь мы будем получать уведомления в Telegram когда наши сайты падают и поднимаются.
Стоит отметить, что такой подход уже лучше, чем большинство представленных на рынке сервисов мониторинга, так как даёт более реальную скорость загрузки сайтов. Большинство существующих сервисов мониторинга - зарубежные, а это значит, что скорость загрузки отечественных сайтов (которую они рисуют в своих графиках) будет нерелевантной (2 000 мс против 30-50 мс в реальности на территории РФ).
Но мы пойдем еще дальше и обеспечим 100% качество статистики. Ранее я уже писал об основной проблеме self-hosted решений, которой я решил пренебречь - сервер мониторинга может упасть вместе с каким-нибудь из проверяемых сайтов - в этом случае мы не получим уведомление об инциденте. Да, шанс возникновения такой ситуации близок к нулю, но мы поправим и это.
4) Создаем файл status.txt со значением ok и переходим на другой сервер (хостинг) для настройки резервного скрипта
5) На втором сервере создаем файл reserve_check.php
<?php
if (file_get_contents('https://example.com/status.txt' == "ok"){
//таким нехитрым способом мы проверяем доступность нашего основного сервера для мониторинга
//если с ним всё хорошо - просто копируем от туда актуалный список сайтов для првоверки и статусы по ним
file_put_contents('monitors.json', file_get_contents('https://example.com/monitors.json'));
file_put_contents('output.json', file_get_contents('https://example.com/output.json'));
} else {
//сюда копируем весь скрипт из пункта №2
}
Ну и по аналогии, добавляем этот скрипт в планировщик задач на резервном сервере.
Таким образом, даже если наш основной сервер мониторинга упадёт, мониторинг будет осуществляться резервным сервером, а пока с основным всё хорошо - обновление списка сайтов для мониторинга будет производиться в автоматическом режиме.
В список monitors.json стоит добавить и адрес основного сервера мониторинга, в этом случае мы также получим уведомление, если он упадет.
Подобный скрипт не требует установки специального ПО, поэтому может размещаться не только на виртуальных/выделенных серверах, но и на обычном шаред-хостинге. Также, такой скрипт не создает практически никакой нагрузки, поэтому для него даже не нужен какой-то отдельный сервер - его можно разместить на каком-нибудь уже существующем сервере/хостинге, просто рядом с другими сайтами и получить свой бесплатный сервис мониторинга. При этом, информация о скорости загрузки и доступности будет куда более точной, чем при использовании платных зарубежных решений.
Ах да, и про скорость загрузки - если вдруг появится необходимость посмотреть на скорость загрузки твоих сайтов, чтобы не ждать выполнение скрипта - статистику лучше получать из файла output.json, для этого создадим файл view.php и разместим в нём следующее:
<?php
$monitors = json_decode(file_get_contents('output.json'));
foreach ($monitors as $monitor) {
echo "<b>".$monitor -> time."</b>: ".$monitor -> name."<br>";
}
Нет ничего более бескомпромиссного, чем решения, созданные своими руками. Особенно, когда ты четко знаешь как это работает и что не придется ждать сюрпризов от такого сервиса. А особенно приятно, что я сэкономил до 3 500 руб. в месяц - могу позволить себе Макалан <3