Надежность
Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems
Главная книга для тех, кто хочет научиться создавать крупные, быстрые и надежные ИТ-системы вроде Telegram, Netflix или крупных интернет-магазинов.
Работать правильно, даже когда всё идёт не так
Каждый интуитивно понимает, что значит «надёжно». Книга раскладывает это ожидание на четыре части — и называет надёжностью способность выполнять их, даже когда что-то ломается.
Делает то, что ожидает пользователь
Приложение выполняет ожидаемую пользователем функцию — это база, без которой остальное бессмысленно.
Переживает ошибочные действия
Выдерживает ошибки пользователя и применение программного обеспечения неожиданным образом.
Достаточно быстро для своего сценария
Производительность достаточна для текущего сценария — при предполагаемой нагрузке и объёме данных.
Не пускает, кого не звали
Предотвращает любой несанкционированный доступ и злоупотребления.
Сбой ≠ отказ
В разговорной речи эти слова путают, а книга разводит их намеренно: вся идея устойчивых систем живёт в промежутке между ними. Мы учимся строить надёжные системы из ненадёжных частей.
Один компонент отклонился от нормы
Умер диск, зависла одна из копий базы, оператор ввёл не ту команду. Снизить вероятность сбоев до нуля невозможно.
Фильтр между сбоем и отказом
Резервирование, изоляция, перезапуск, откат. Задача проектирования — предотвращать переход сбоев в отказы.
Система перестала работать для пользователя
Вся система в целом прекратила предоставлять требуемый сервис. Именно этого мы избегаем.
Сбой случится всё равно → его перехватывают механизмы устойчивости → до отказа он не доходит.
- Устойчивость — только к определённым типам сбоев. Если Землю поглотит чёрная дыра, спасёт лишь хостинг данных в космосе — удачи с одобрением такой статьи бюджета.
- Сбои полезно вызывать намеренно. Звучит парадоксально — следующий слайд разбирает это на примере Chaos Monkey из Netflix.
- Исключение — безопасность. Обычно устойчивость важнее предотвращения, но утечку не «вылечишь»: если атакующий уже забрал данные — поздно. Здесь предотвратить важнее, чем пережить.
Chaos Monkey: ломаем нарочно, чтобы не сломалось само
По книге, в устойчивой к сбоям системе имеет смысл повысить частоту сбоев, генерируя их умышленно — например, прерывать работу случайно выбранных процессов без предупреждения. Зачем добровольно устраивать себе аварии?
Код обработки ошибок почти не выполняется
Многие критические ошибки происходят из-за недостаточной обработки ошибок. Этот код пишут «на всякий случай» и годами не запускают — пока сбой не случится по-настоящему, никто не знает, работает ли он.
Сервис, который убивает случайные машины
Chaos Monkey случайным образом выключает виртуальные машины Netflix прямо в проде — в рабочее время, когда инженеры на месте. Ни один сервис не может рассчитывать, что его машина будет жить вечно.
Механизмы устойчивости проверяются каждый день
Умышленные сбои гарантируют постоянное тестирование резервирования, перезапуска и отката. Растёт уверенность, что при «естественном» сбое система справится — уверенность, а не надежда.
Аппаратные сбои: случайные и независимые
Умирают диски, появляются дефекты в памяти, отключается электропитание, кто-то выдернул не тот сетевой кабель. При большом количестве машин это происходит постоянно.
Первая реакция — избыточность железа
RAID-массивы, дублированное электропитание, CPU с горячей заменой, батареи и дизель-генераторы в ЦОД. Пока отказавший компонент меняют, его работу берёт на себя резервный. Отказы не исчезают, но машины работают бесперебойно годами.
Сдвиг: переживать потерю целых машин
Данных и вычислений всё больше → машин больше → отказов пропорционально больше. В облаках вроде AWS виртуалки пропадают без предупреждения: платформа ценит гибкость выше надёжности одной машины. Ответ — программные методы устойчивости вместо аппаратной избыточности или вдобавок к ней.
Программные ошибки: одна на всех узлах
Аппаратные сбои случайны и независимы: диск одного сервера ничего не знает о диске другого. Систематическая ошибка в софте — наоборот: она коррелирует между узлами, поэтому системных отказов от неё гораздо больше.
Как это выглядит
- Ошибка роняет экземпляр сервера при конкретных «плохих» входных данных. Пример — високосная секунда (leap second) 30 июня 2012: лишняя секунда в системном времени спровоцировала баг в ядре Linux, и разом зависло множество приложений.
- Вышедший из-под контроля процесс исчерпал общий ресурс: время CPU, память, диск или полосу сети.
- Сервис, от которого зависит система, замедлился, перестал отвечать или возвращает испорченные ответы.
- Каскадные сбои: крошечный сбой в одном компоненте вызывает сбой в другом — и дальше по цепочке.
Что с этим делать
- Быстрого решения нет — помогает множество мелочей.
- Тщательно обдумывать допущения и взаимодействия внутри системы.
- Всестороннее тестирование; изоляция процессов; возможность перезапуска после фатального сбоя.
- Измерять, мониторить и анализировать поведение в проде.
- Постоянная самопроверка инвариантов — условий, которые должны выполняться всегда. Например: в очередь вошло столько сообщений, сколько из неё вышло; расхождение — сразу алерт.
Человеческий фактор: люди ненадёжны
Системы проектируют, пишут и эксплуатируют люди — и даже с самыми благими намерениями они ошибаются. Вопрос книги: как обеспечить надёжность системы, несмотря на ненадёжность людей?
Оптимальные системы сочетают несколько подходов
Ни один пункт справа не работает сам по себе — надёжность даёт их комбинация.
- Минимизировать возможности ошибиться. Хорошие абстракции, API и админ-интерфейсы упрощают «правильные» действия и усложняют «неправильные». Но слишком жёсткие интерфейсы люди начнут обходить — нужно равновесие.
- Развести места, где люди чаще ошибаются, и места, где ошибка становится отказом. Полнофункциональная «песочница» с настоящими данными, где можно экспериментировать, не влияя на реальных пользователей.
- Тестировать на всех уровнях. От модульных тестов до комплексных и ручных; автоматизация особенно ценна для пограничных случаев.
- Быстрое и удобное восстановление. Быстрый откат конфигурации, постепенное внедрение кода на малую долю пользователей, инструменты пересчитать данные, если прошлые вычисления оказались неверны.
- Подробный и ясный мониторинг. Метрики производительности и частоты ошибок — телеметрия, как у ракеты после отрыва от земли.
- Управленческие практики и обучение — важно, но уже за рамками книги.
Надёжность нужна не только АЭС и авиадиспетчерам
От «обычных» приложений тоже ожидают надёжной работы — и у ненадёжности всегда есть цена.
Потерянные рабочие часы и юристы
Ошибки в коммерческих приложениях — это простой сотрудников и юридические риски, если цифры в отчётах оказались неточны.
Простой = недополученный доход
Простои сайта приводят к колоссальным убыткам: недополученные доходы и ущерб для репутации.
Ответственность перед пользователями
Родители хранят все фото и видео детей в вашем приложении. Что они почувствуют, если база окажется испорчена? Смогут ли они восстановить данные из резервной копии?
Те же три источника сбоев — в браузере
Клеппман пишет про информационные системы, но словарь раздела 1.2 переносится на фронтенд без изменений: сбой компонента не должен становиться отказом страницы.
| Источник | Как выглядит в браузере | Чтобы сбой не стал отказом |
|---|---|---|
| Устройство и сеть пользователя | Пропал Wi-Fi, слабый телефон, ОС выгрузила вкладку в фоне | Повторы запросов с нарастающей задержкой, офлайн-состояния, плавная деградация (graceful degradation) вместо белого экрана |
| Программная ошибка | Неожиданный null в ответе API роняет всё дерево компонентов; CDN ответил 502, сторонний скрипт не загрузился | Error boundaries (React; в Vue — errorCaptured): падает виджет, а не страница; валидация данных на границе; таймауты для зависимостей; мониторинг ошибок в проде |
| Человеческий фактор | Опечатка в конфиге или релиз с багом уехал сразу на 100 % пользователей | Постепенная раскатка и feature flags, быстрый откат, телеметрия — три пункта из списка книги |
Надёжность — в четырёх строках
- Надёжность — «продолжать работать нормально, когда что-то пошло не так». Ожидаемая функция, устойчивость к ошибкам пользователя, достаточная производительность, защита от несанкционированного доступа и злоупотреблений.
- Сбой ≠ отказ. Сбои неизбежны; проектируем так, чтобы сбой компонента не превращался в отказ системы. Надёжные системы строятся из ненадёжных частей.
- Три источника сбоев — три набора мер. Аппаратные: избыточность и устойчивость к потере целых машин. Программные: тестирование, изоляция, мониторинг, самопроверки. Человеческие: хорошие интерфейсы, песочницы, быстрый откат, телеметрия.
- Надёжность — ответственность, а не роскошь. Ей можно жертвовать ради скорости или цены, но осознанно и очень осторожно.