Начну, как всегда, из далека. Мониторинг доступности – вещь обязательная для любого владельца сайта/системного администратора/студии. Крайне важно вовремя реагировать на сбои в работе и кибератаки.
Кучу лет назад, я воспользовался первым попавшимся сервисом, который позволял осуществлять мониторинг бесплатно – это был 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 $name=>$monitor) { echo "<b>".$monitor -> time."</b>: ".$name."<br>"; }