Пять обрывов за три дня: как я искал, где рвётся связь у своего сервера

За три дня сайт пять раз пропадал из сети, самый долгий раз на пять часов. Сервер при этом работал без единой ошибки: не перезагружался, не падал, исправно собирал статистику. Пропадала только дорога от него до интернета. Вот как я это выяснял и что поменял, чтобы в следующий раз ответ был готов сам.

Стенд

Небольшой сервер, на котором живут мой сайт-портфолио и SSH-ловушка для ботов. Сайт в Docker за обратным прокси, рядом — сторож на bash и systemd-таймерах: раз в десять минут проверяет, что всё работает, и шлёт пуш, если что-то сломалось. Снаружи сайт раз в пять минут проверяет внешний монитор.

«Проблем: 0», а сайт лежит

Первыми о сбоях узнал не я, а внешний монитор: он присылает письмо, когда сайт перестаёт отвечать. Своя проверка на сервере в это же время каждые десять минут писала в журнал «проблем: 0».

Ошибки в ней не было. Она проверяет то, что внутри: свежие ли данные, работают ли контейнеры и службы, хватает ли места на диске. Внутри всё было в порядке. Это первый урок истории: проверка изнутри видит сервер, но не путь до него. Посетителю всё равно, что процессы живы, если до них нельзя достучаться.

Что показали журналы

Сначала я исключил очевидное: сервер не перезагружался шесть дней, контейнеры не перезапускались, в журнале ядра нет ни нехватки памяти, ни ошибок диска. Зато Docker в нужные минуты сыпал одной и той же ошибкой: не может спросить у DNS адрес чего угодно, от удостоверяющего центра до собственных доменов. Тайм-аут, тайм-аут, тайм-аут.

Чтобы увидеть границы сбоев, достаточно разложить эти ошибки по десятиминуткам:

journalctl -u docker --since today -o short-iso --no-pager | grep 'failed to query external DNS' | cut -c1-15 | uniq -c

Получилась аккуратная картина: тишина, всплеск на полчаса, снова тишина, потом полтора часа сплошных ошибок. Время всплесков с точностью до минут совпало с письмами монитора. Сервер одновременно не мог выйти наружу и не принимал соединений снаружи, то есть пропадала связь целиком.

Сторож учится замечать обрыв

Первое исправление очевидное: проверять ещё и внешнюю связь. Теперь сторож раз в десять минут спрашивает DNS и пробует подключиться к паре публичных адресов.

Сложность в другом: пока связи нет, сообщить о сбое нельзя, пуш просто не уйдёт. Поэтому сторож запоминает время первой неудачной проверки, а когда связь возвращается, присылает одно сообщение «был без связи с … до …» и сам готовит черновик разбора. На странице доступности день сразу краснеет, не дожидаясь, пока я сяду писать текст.

Ложная тревога

Через два дня сторож поймал три обрыва. Я уже собирался писать разборы, но сначала решил проверить, видели ли сбой посетители. Лучший свидетель тут журнал самого сайта: если внешние запросы продолжали приходить, сайт был доступен, что бы ни думал сторож.

python3 -c 'import sys, json, datetime, ipaddress, collectionsc = collections.Counter()for line in sys.stdin: e = json.loads(line) if ipaddress.ip_address(e["request"]["remote_ip"]).is_global: c[datetime.datetime.fromtimestamp(e["ts"]).strftime("%H:%M")[:4] + "0"] += 1print(sorted(c.items()))' < access.log

Скрипт считает запросы только с внешних адресов: внутренние, например проверки из локальной сети, не в счёт.

Два обрыва подтвердились: в эти часы снаружи не пришло ни одного запроса. А вот первый, десятиминутный, оказался ложным. Отказывал только DNS, а посетители спокойно заходили. Сторож увидел, что сервер не может выйти наружу, и решил, что сайт недоступен.

Это второй урок: «сервер не может выйти наружу» и «сайт недоступен» — разные события, и проверять нужно оба. Теперь, прежде чем писать черновик, сторож сам смотрит журнал сайта. Если запросы шли хотя бы в половине отрезков перерыва, придёт только пуш с пометкой «сайт при этом был доступен», а полоса доступности не покраснеет.

Где именно рвётся

Осталось понять, на чьей стороне обрыв. Для этого нужно знать два адреса: шлюз, через который сервер выходит в сеть, и первый узел провайдера за ним. Шлюз берётся из таблицы маршрутов, а первый узел провайдера можно найти простым приёмом: отправить ping с временем жизни 2.

ping -n -c1 -t 2 1.1.1.1

Пакет умрёт на втором прыжке, и именно этот узел ответит «Time to live exceeded», назвав свой адрес. Пока связь есть, сторож раз в сутки запоминает оба адреса. Во время обрыва он каждые десять минут пингует их и по итогам пишет вывод в черновик:

  • не отвечал шлюз — сбой на нашей стороне;

  • шлюз отвечал, а узел провайдера нет — обрыв на линии провайдера;

  • отвечали оба — проблема дальше, в сети провайдера, или только у DNS.

С таким выводом уже можно идти в поддержку не с «у меня иногда не работает», а с точным временем и участком.

Взгляд снаружи, который работает во время сбоя

Последний штрих: страница статуса, которая открывается, даже когда сайт недоступен. Она живёт на GitHub Pages, проверяет сайт каждые пять минут из GitHub Actions и стоит на поддомене status.ogurexxx.ru.

Тут нашлась своя ловушка. У сайта включён HSTS для всех поддоменов: браузер открывает их только по HTTPS с действующим сертификатом и не даёт пропустить предупреждение. Пока сертификат на новом поддомене не выпущен, страница просто не открывается, даже если DNS настроен правильно. А некоторые сервисы мониторинга выпускают сертификат для своего домена только на платном тарифе.

Сколько простоя можно себе позволить

После этой истории на странице инцидентов появилась таблица надёжности: число сбоев, суммарный простой, среднее время восстановления (MTTR) и среднее время между сбоями (MTBF). И бюджет ошибок, как в SRE. Цель — 99,5% доступности в месяц, то есть около 3 часов 40 минут простоя.

Ноябрь этот бюджет исчерпал за первую неделю: только два сбоя 5 ноября дали больше пяти часов. Это неприятная цифра, но полезная. Пока бюджет не потрачен, можно спокойно экспериментировать. Когда он исчерпан, приоритет один — найти причину обрывов, а новые функции подождут.

Что я вынес

  1. Проверка изнутри и проверка снаружи отвечают на разные вопросы. Нужны обе.

  2. Во время обрыва сервер не может сообщить о нём сам. Значит, сообщение должно прийти после восстановления и сразу с фактами: сколько длилось и где рвалось.

  3. Прежде чем писать разбор, стоит спросить свидетеля, которого сбой не касается. Журнал сайта честно показал, какой обрыв был настоящим.

  4. Пять обрывов за три дня — уже не случайность, а неисправность. Теперь у меня есть данные, чтобы её найти.

Разборы каждого сбоя — на странице «Инциденты», текущее состояние — на status.ogurexxx.ru.

Источник: habr.com

0 0 голоса
Рейтинг новости
1
0
Подписаться
Уведомить о
0 комментариев