Сделать веб-сервис отказоустойчивым можно за шесть шагов, и делать их надо в порядке возрастания цены: найти одиночные точки отказа, настроить копии и проверить восстановление, освободить приложение от локального состояния и добавить второй узел, защитить вызовы к внешним системам, научиться откатывать выкладки, и только потом ставить реплику базы с переключением. Каждый шаг проверяют учением, а вторая площадка нужна редко и стоит последней.
Порядок важен, потому что ранние шаги закрывают самые частые причины простоев и стоят заметно меньше поздних. Какие отказы бывают и как выбирать уровень защиты, описано на странице «Разработка отказоустойчивого веб-сервиса»; здесь только последовательность действий.
Шаг 0. Найти одиночные точки отказа
Одиночная точка отказа — всё, без чего сервис не работает и что существует в одном экземпляре. Составьте перечень компонентов и для каждого ответьте на два вопроса: что увидит пользователь при отказе и как быстро вы об этом узнаете.
| Компонент | Что увидит пользователь при отказе | Как об этом узнаете | С какого шага закрывается |
|---|---|---|---|
| Сервер приложения | Сайт не открывается | Внешняя проверка сценария | Шаг 2: второй узел |
| База данных | Страницы открываются, операции падают | Доля ошибок и задержка запросов | Шаги 1 и 5: копии, затем реплика |
| Хранилище файлов | Не загружаются документы и картинки | Ошибки на маршрутах с файлами | Шаги 1 и 2: копии и отдельное хранилище |
| Внешняя система (платежи, 1С, почта) | Оформление зависает или сообщения не приходят | Время ответа и доля ошибок по системе | Шаг 3: таймауты, очередь |
| Выкладка | Сервис падает после обновления | Доля ошибок после отметки выкладки | Шаг 4: откат |
| Человек | Только один сотрудник знает, как восстановить | Никак, пока он не в отпуске | Инструкция и учение |
Последняя строка часто самая опасная. Если восстановление знает один человек и нигде не записано, отказоустойчивость сервиса равна отказоустойчивости этого человека. Результат шага 0 — таблица и ответ на вопрос, сколько потери данных и простоя бизнес готов терпеть. Эти допустимые значения определяют, как далеко идти по лестнице.
Шаг 1. Копии, которые вы восстанавливали
Это самый дешёвый и самый важный шаг. Копия, которую ни разу не разворачивали, считается неработающей, пока не доказано обратное.
- Что копируется. База, загруженные файлы, конфигурация, секреты в защищённом виде. Код хранится в репозитории и в копиях не нуждается, но нужен способ собрать ту же версию.
- Где лежит. Хотя бы одна копия вне сервера, на котором работает сервис, и желательно вне площадки. Копия на том же диске переживает ошибку человека, но не отказ диска. Копия, доступная с боевого сервера на запись и удаление, не защитит от вредоносного ПО.
- Глубина. Нужны и свежие копии, и старые. Ошибку в данных иногда замечают через дни, и последняя копия к тому времени уже содержит порчу.
- Возврат на момент времени. Для базы, где важна потеря последних минут, включают непрерывное архивирование журнала изменений: тогда можно вернуться к состоянию за минуту до ошибки.
- Проверка. Раз в квартал копию разворачивают на чистом сервере по письменной инструкции, запускают приложение, сверяют число и суммы записей с боевой системой и записывают время. Если оно больше допустимого, шаги ниже ускоряют восстановление.
Результат шага: известное время восстановления из копии. Для многих небольших систем это и есть вся нужная отказоустойчивость: простой в несколько часов приемлем, потеря данных за сутки нет.
Шаг 2. Приложение без состояния и второй узел
Пока приложение хранит что-то важное на своём диске или в памяти процесса, второй узел его не заменит. Сначала состояние выносят, потом дублируют.
| Что хранится на узле | Что ломается при втором узле | Куда вынести |
|---|---|---|
| Сессии пользователей в памяти | Пользователь «разлогинивается», попав на другой узел | Общее хранилище сессий или токены, которые проверяются без обращения к узлу |
| Загруженные файлы на диске | Файл есть на одном узле, на втором ссылка ведёт в пустоту | Общее файловое или объектное хранилище |
| Задания по расписанию | Задание запускается на каждом узле и выполняется дважды | Один планировщик с блокировкой или очередь с одним потребителем на задание |
| Кэш в памяти | Данные расходятся между узлами | Общий кэш или допустимое расхождение, записанное как решение |
| Локальная конфигурация | Узлы ведут себя по-разному | Конфигурация из репозитория и один способ развёртывания |
После этого за балансировщик ставят два узла и добавляют проверку готовности: балансировщик перестаёт слать запросы узлу, который не отвечает. Проверка должна смотреть на реальную готовность (есть связь с базой), а не на то, что процесс жив. Иначе узел с оборванным подключением к базе будет получать запросы и отвечать ошибками.
Результат шага: падение процесса или узла приложения не заметно пользователям. Важное ограничение: два узла в одной стойке или на одном питании от общего отказа не спасают.
Шаг 3. Защита от чужих сбоев
Сервис падает не только из-за своих поломок. Чаще он зависает потому, что медленно отвечает система, от которой он зависит. Защита состоит из нескольких простых приёмов.
| Приём | Что делает | Когда опасен | Как проверить |
|---|---|---|---|
| Таймаут | Ограничивает ожидание ответа каждого внешнего вызова | Слишком короткий таймаут даёт ложные ошибки | Сравнить с реальным временем ответа системы в обычный день |
| Повтор с границей | Повторяет неудачный вызов ограниченное число раз с растущей паузой | Повтор небезопасной операции создаёт дубль платежа или заказа | Убедиться, что повторяемая операция идемпотентна |
| Предохранитель | После ряда неудач перестаёт вызывать систему и отвечает сразу | Может заблокировать вызовы к системе, которая уже восстановилась | Проверить, что есть пробный запрос и что видно состояние предохранителя |
| Очередь | Откладывает то, что можно сделать позже | Очередь растёт молча, и сообщения устаревают | Следить за возрастом самого старого сообщения |
| Изоляция ресурсов | Выделяет отдельный пул потоков или соединений под тяжёлую зависимость | Лишний пул отнимает ресурсы у остальных | Нарочно замедлить зависимость и посмотреть, остальные ли страницы живы |
Главное решение здесь не техническое, а продуктовое: что видит пользователь, когда система недоступна. «Платёж не прошёл, повторите позже» лучше пустой страницы. Если без системы нельзя оформить заказ, это записывается как принятый риск, а не оставляется на волю случая.
Шаг 4. Выкладка, которую можно откатить
Заметная часть простоев начинается с обновления. Поэтому у выкладки должен быть порядок, как и у восстановления.
- Предыдущая версия лежит собранной, и вернуться к ней можно одной командой.
- Изменения структуры данных делаются в два этапа: сначала добавляется новое так, чтобы старая версия продолжала работать, потом переключается код, и только потом удаляется старое. Иначе откат кода невозможен.
- Новая версия сначала получает один узел или малую долю запросов. При росте ошибок выкладка останавливается.
- Выкладка оставляет отметку на графиках, чтобы связь между обновлением и ростом ошибок была видна.
- Откат хотя бы раз проведён на стенде до первой аварии.
Результат шага: плохая выкладка превращается из аварии в неприятность на несколько минут. Отметки и доли ошибок для автоматической остановки дают метрики, см. страницу о мониторинге веб-сервисов.
Шаг 5. Реплика базы и переключение: когда оправдана
Это самый дорогой в эксплуатации шаг, поэтому его ставят после предыдущих. Реплика — вторая база, куда постоянно копируются изменения; при отказе главной её можно сделать главной.
| Вопрос | Если ответ «да» | Если ответ «нет» |
|---|---|---|
| Простой на время восстановления из копии (часы) обходится дороже содержания реплики? | Реплика оправдана | Хватит шага 1 с быстрым восстановлением |
| Допустима ли потеря последних секунд записей при аварии? | Подойдёт асинхронная репликация: быстрее и проще | Нужна синхронная: потери нет, но запись медленнее и зависит от реплики |
| Есть ли команда, готовая сопровождать автоматическое переключение? | Автоматическое: быстрее, но нужны внешний арбитр, мониторинг и учения | Переключение вручную по инструкции: медленнее, зато понятно и проверяемо |
| Есть ли защита от удаления данных человеком? | Реплика дополняет копии | Реплика не поможет: удаление повторится на ней сразу |
Отдельная опасность автоматического переключения: два узла одновременно считают себя главными. Поэтому решение принимает внешний арбитр, а не сам узел. Реплику можно также использовать для чтения отчётов и разгрузки главной базы, но тогда следите, чтобы нагрузка отчётов не мешала репликации: если реплика отстаёт, переключаться на неё опасно.
Шаг 6. Учения: ломайте сами, пока не сломалось само
Каждый шаг выше работает только если проверен. Проверка называется учением: на стенде или в согласованное окно на боевом сервисе нарочно создают отказ и сравнивают поведение с записанным.
| Сценарий | Как создаём | Что должно произойти | Что записываем |
|---|---|---|---|
| Отказ узла приложения | Останавливаем один узел | Пользователи ничего не замечают, оповещение пришло | Время обнаружения |
| Медленная внешняя система | Искусственно замедляем её ответы | Срабатывают таймаут и предохранитель, остальные страницы работают | Что увидел пользователь |
| Отказ базы | Останавливаем главную базу на стенде | Переключение по инструкции или автоматически | Время до возобновления записи, потеря данных |
| Плохая выкладка | Выкладываем версию с ошибкой | Выкладка остановлена или откат выполнен | Время отката |
| Полная потеря сервера | Разворачиваем сервис из копии на чистой машине | Сервис запущен по инструкции, данные сходятся | Общее время восстановления |
Результат каждого учения — запись: что сработало, что нет, что исправили. Расхождение с ожидаемым поведением — находка, а не провал: лучше найти её в тихий день.
Когда остановиться
Не каждому сервису нужна вся лестница. Остановитесь на шаге, после которого оставшийся риск дешевле следующего шага.
| Профиль сервиса | Обычно достаточно | Лишнее на этом этапе |
|---|---|---|
| Внутренний справочник, простой допустим в рабочий день | Шаги 0 и 1 | Реплика, второй узел |
| Кабинет клиентов, простой в час заметен, но не критичен | Шаги 0–4 | Автоматическое переключение базы, вторая площадка |
| Приём заказов или платежей, простой в минуты стоит денег | Шаги 0–6 | Вторая площадка, пока не посчитана цена её отсутствия |
| Сервис с обязательствами перед клиентами по доступности | Все шаги и расчёт второй площадки | Обещания, которые не подтверждены учением |
Цель по доступности («три девятки» и выше) выводится из этих решений, а не наоборот, как разобрано в статье о доступности «три девятки». Если причина сбоев не отказ, а наплыв пользователей, лечить нужно нагрузку: как подготовить B2C-сервис к высокой нагрузке.
Что делаем мы и с чего начать
Начинаем с обследования: 200 000 ₽ и 2–3 недели за один сервис, 350 000 ₽ и 3–4 недели, если вокруг несколько систем. На выходе перечень одиночных точек отказа, проверенное время восстановления из копии, допустимые потери и простой по частям сервиса, выбранный уровень защиты и вилка бюджета. Стоимость вычитается из первого этапа, если продолжаете с нами.
Дальше лёгкий пилот (150 000–400 000 ₽, 2–8 недель): копии, учение по восстановлению, второй узел. Тяжёлый пилот (400 000–1 200 000 ₽, 2–3 месяца) добавляет реплику, переключение и защиту внешних вызовов. Круглосуточной дежурной смены у нас нет, обязательств по доступности мы не берём; помесячное сопровождение — 20 000 / 60 000 / 120 000 ₽, сверх пакета 5 000 ₽ в час. Цены и сроки — на странице «Тарифы», описание услуги — на странице «Разработка отказоустойчивого веб-сервиса».
Частые вопросы
С чего начать повышение отказоустойчивости сервиса?
С перечня одиночных точек отказа и проверки копий. Выпишите, без чего сервис не работает и что существует в одном экземпляре, и разверните последнюю копию на чистом сервере. Эти два действия дешёвые и закрывают самые частые причины долгих простоев.
Достаточно ли резервных копий?
Для сервиса, где простой в несколько часов приемлем, достаточно, если копии проверены и известно время восстановления. Если простой дороже, добавляют второй узел приложения, а затем реплику базы. Копии нужны в любом случае: реплика не защитит от удаления данных.
Зачем нужен второй сервер, если есть резервные копии?
Копия восстанавливает данные, но на это нужно время, и всё это время сервис недоступен. Второй узел делает отказ одного сервера незаметным. Но он работает только если приложение не хранит важное состояние на своём диске.
Что такое одиночная точка отказа?
Любой компонент, без которого сервис не работает и которого в одном экземпляре: единственный сервер, база, балансировщик, канал связи, внешняя система, а иногда единственный человек, знающий порядок восстановления.
Как часто проверять восстановление из копии?
Хотя бы раз в квартал и после любых заметных изменений в схеме данных или развёртывании. Проверка должна доходить до запуска приложения и сверки данных, а не заканчиваться на том, что файл копии существует.
Нужно ли автоматическое переключение базы?
Не всегда. Оно полезно, когда простой в минуты стоит денег и есть команда, понимающая схему. Для многих систем хватает ручного переключения по инструкции или быстрого восстановления из копии. Автоматика без учений создаёт ложное чувство безопасности.
Помогают ли микросервисы сделать сервис устойчивее?
Сами по себе нет. Они позволяют изолировать сбой в одной части, но добавляют сетевые вызовы, которые ломаются чаще вызовов функций. Если разделение не продумано, отказоустойчивость падает. Подробнее в статье «Микросервисы или монолит».
Берёте ли вы на себя обязательства по доступности?
Нет. Доступность зависит от оборудования, площадки, вашей эксплуатации и внешних систем. Мы строим схему под ваши цели, проверяем её учениями и передаём измеренные значения. Круглосуточной дежурной смены у нас нет.