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

Порядок важен, потому что ранние шаги закрывают самые частые причины простоев и стоят заметно меньше поздних. Какие отказы бывают и как выбирать уровень защиты, описано на странице «Разработка отказоустойчивого веб-сервиса»; здесь только последовательность действий.

Коротко. Сначала список одиночных точек отказа, затем копии, которые вы действительно восстановили, потом второй узел приложения, таймауты и откат выкладки. Реплику базы с переключением ставьте, когда простой в часы дороже её содержания. Каждый шаг проверяйте учением, иначе защита существует только на бумаге.

Шаг 0. Найти одиночные точки отказа

Одиночная точка отказа — всё, без чего сервис не работает и что существует в одном экземпляре. Составьте перечень компонентов и для каждого ответьте на два вопроса: что увидит пользователь при отказе и как быстро вы об этом узнаете.

КомпонентЧто увидит пользователь при отказеКак об этом узнаетеС какого шага закрывается
Сервер приложенияСайт не открываетсяВнешняя проверка сценарияШаг 2: второй узел
База данныхСтраницы открываются, операции падаютДоля ошибок и задержка запросовШаги 1 и 5: копии, затем реплика
Хранилище файловНе загружаются документы и картинкиОшибки на маршрутах с файламиШаги 1 и 2: копии и отдельное хранилище
Внешняя система (платежи, 1С, почта)Оформление зависает или сообщения не приходятВремя ответа и доля ошибок по системеШаг 3: таймауты, очередь
ВыкладкаСервис падает после обновленияДоля ошибок после отметки выкладкиШаг 4: откат
ЧеловекТолько один сотрудник знает, как восстановитьНикак, пока он не в отпускеИнструкция и учение

Последняя строка часто самая опасная. Если восстановление знает один человек и нигде не записано, отказоустойчивость сервиса равна отказоустойчивости этого человека. Результат шага 0 — таблица и ответ на вопрос, сколько потери данных и простоя бизнес готов терпеть. Эти допустимые значения определяют, как далеко идти по лестнице.

Шаг 1. Копии, которые вы восстанавливали

Это самый дешёвый и самый важный шаг. Копия, которую ни разу не разворачивали, считается неработающей, пока не доказано обратное.

  • Что копируется. База, загруженные файлы, конфигурация, секреты в защищённом виде. Код хранится в репозитории и в копиях не нуждается, но нужен способ собрать ту же версию.
  • Где лежит. Хотя бы одна копия вне сервера, на котором работает сервис, и желательно вне площадки. Копия на том же диске переживает ошибку человека, но не отказ диска. Копия, доступная с боевого сервера на запись и удаление, не защитит от вредоносного ПО.
  • Глубина. Нужны и свежие копии, и старые. Ошибку в данных иногда замечают через дни, и последняя копия к тому времени уже содержит порчу.
  • Возврат на момент времени. Для базы, где важна потеря последних минут, включают непрерывное архивирование журнала изменений: тогда можно вернуться к состоянию за минуту до ошибки.
  • Проверка. Раз в квартал копию разворачивают на чистом сервере по письменной инструкции, запускают приложение, сверяют число и суммы записей с боевой системой и записывают время. Если оно больше допустимого, шаги ниже ускоряют восстановление.

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

Шаг 2. Приложение без состояния и второй узел

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

Что хранится на узлеЧто ломается при втором узлеКуда вынести
Сессии пользователей в памятиПользователь «разлогинивается», попав на другой узелОбщее хранилище сессий или токены, которые проверяются без обращения к узлу
Загруженные файлы на дискеФайл есть на одном узле, на втором ссылка ведёт в пустотуОбщее файловое или объектное хранилище
Задания по расписаниюЗадание запускается на каждом узле и выполняется дваждыОдин планировщик с блокировкой или очередь с одним потребителем на задание
Кэш в памятиДанные расходятся между узламиОбщий кэш или допустимое расхождение, записанное как решение
Локальная конфигурацияУзлы ведут себя по-разномуКонфигурация из репозитория и один способ развёртывания

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

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

Шаг 3. Защита от чужих сбоев

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

ПриёмЧто делаетКогда опасенКак проверить
ТаймаутОграничивает ожидание ответа каждого внешнего вызоваСлишком короткий таймаут даёт ложные ошибкиСравнить с реальным временем ответа системы в обычный день
Повтор с границейПовторяет неудачный вызов ограниченное число раз с растущей паузойПовтор небезопасной операции создаёт дубль платежа или заказаУбедиться, что повторяемая операция идемпотентна
ПредохранительПосле ряда неудач перестаёт вызывать систему и отвечает сразуМожет заблокировать вызовы к системе, которая уже восстановиласьПроверить, что есть пробный запрос и что видно состояние предохранителя
ОчередьОткладывает то, что можно сделать позжеОчередь растёт молча, и сообщения устареваютСледить за возрастом самого старого сообщения
Изоляция ресурсовВыделяет отдельный пул потоков или соединений под тяжёлую зависимостьЛишний пул отнимает ресурсы у остальныхНарочно замедлить зависимость и посмотреть, остальные ли страницы живы

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

Шаг 4. Выкладка, которую можно откатить

Заметная часть простоев начинается с обновления. Поэтому у выкладки должен быть порядок, как и у восстановления.

  1. Предыдущая версия лежит собранной, и вернуться к ней можно одной командой.
  2. Изменения структуры данных делаются в два этапа: сначала добавляется новое так, чтобы старая версия продолжала работать, потом переключается код, и только потом удаляется старое. Иначе откат кода невозможен.
  3. Новая версия сначала получает один узел или малую долю запросов. При росте ошибок выкладка останавливается.
  4. Выкладка оставляет отметку на графиках, чтобы связь между обновлением и ростом ошибок была видна.
  5. Откат хотя бы раз проведён на стенде до первой аварии.

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

Шаг 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 ₽ в час. Цены и сроки — на странице «Тарифы», описание услуги — на странице «Разработка отказоустойчивого веб-сервиса».

Частые вопросы

С чего начать повышение отказоустойчивости сервиса?

С перечня одиночных точек отказа и проверки копий. Выпишите, без чего сервис не работает и что существует в одном экземпляре, и разверните последнюю копию на чистом сервере. Эти два действия дешёвые и закрывают самые частые причины долгих простоев.

Достаточно ли резервных копий?

Для сервиса, где простой в несколько часов приемлем, достаточно, если копии проверены и известно время восстановления. Если простой дороже, добавляют второй узел приложения, а затем реплику базы. Копии нужны в любом случае: реплика не защитит от удаления данных.

Зачем нужен второй сервер, если есть резервные копии?

Копия восстанавливает данные, но на это нужно время, и всё это время сервис недоступен. Второй узел делает отказ одного сервера незаметным. Но он работает только если приложение не хранит важное состояние на своём диске.

Что такое одиночная точка отказа?

Любой компонент, без которого сервис не работает и которого в одном экземпляре: единственный сервер, база, балансировщик, канал связи, внешняя система, а иногда единственный человек, знающий порядок восстановления.

Как часто проверять восстановление из копии?

Хотя бы раз в квартал и после любых заметных изменений в схеме данных или развёртывании. Проверка должна доходить до запуска приложения и сверки данных, а не заканчиваться на том, что файл копии существует.

Нужно ли автоматическое переключение базы?

Не всегда. Оно полезно, когда простой в минуты стоит денег и есть команда, понимающая схему. Для многих систем хватает ручного переключения по инструкции или быстрого восстановления из копии. Автоматика без учений создаёт ложное чувство безопасности.

Помогают ли микросервисы сделать сервис устойчивее?

Сами по себе нет. Они позволяют изолировать сбой в одной части, но добавляют сетевые вызовы, которые ломаются чаще вызовов функций. Если разделение не продумано, отказоустойчивость падает. Подробнее в статье «Микросервисы или монолит».

Берёте ли вы на себя обязательства по доступности?

Нет. Доступность зависит от оборудования, площадки, вашей эксплуатации и внешних систем. Мы строим схему под ваши цели, проверяем её учениями и передаём измеренные значения. Круглосуточной дежурной смены у нас нет.