Распределённые системы
8 заблуждений о распределённых системах
Цели урока
- Знать все 8 заблуждений Deutsch и понимать почему каждое нарушается в production
- Применять паттерны защиты: retry, circuit breaker, idempotency, service discovery
- Понимать стоимость сетевого трафика и выбирать формат сериализации осознанно
- Проектировать системы с расчётом на неоднородность и множество администраторов
Предварительные знания
- Базовое понимание HTTP и сетевых протоколов
- Опыт работы с REST API
- Понятие микросервисной архитектуры на базовом уровне
Peter Deutsch сформулировал 8 заблуждений в 1994 году. За 30 лет они не изменились - каждый год новые компании платят миллионами за те же ошибки.
- **Amazon Prime Day 2012** - переполнение сетевых буферов, миллионы молчаливо потерянных запросов (заблуждение 1)
- **Netflix** - экономия десятков миллионов долларов в год после перехода на Protobuf (заблуждение 3)
- **Juniper Networks backdoor (2015)** - годами перехватывали VPN-трафик внутри корпоративных сетей (заблуждение 4)
- **Fastly CDN outage (2021)** - 1 час и Reddit, GitHub, Financial Times упали вместе с одним провайдером (заблуждение 6)
- **Uber gRPC migration (2018)** - latency -40%, трафик -5-10x, CPU на сериализацию вдвое меньше (заблуждения 3, 7)
Peter Deutsch и 8 заблуждений
Peter Deutsch - один из создателей Smalltalk и разработчик Ghostscript. В 1994 году, работая в Sun Microsystems, он перечислил первые 7 заблуждений на доске во время обсуждения проблем distributed объектных систем. Джеймс Гослинг (создатель Java) дополнил список 8-м пунктом. Список никто не публиковал официально - он распространился как устная традиция и только в 2006 году был оформлен в статью Arnon Rotem-Gal-Oz.
Сеть надёжна и latency равна нулю
**2012 год. Amazon Prime Day. Трафик вырос в 4 раза по сравнению с прогнозом. Сетевые буферы переполнились за секунды. Миллионы запросов молча потерялись - никаких ошибок, просто тишина. Сервисы ждали ответов, которые никогда не приходили.** Это первые два заблуждения в действии: сеть не надёжна, и latency - не ноль. Те же blind spots всплывают при partition в уроке про CAP.
В 1994 году Peter Deutsch из Sun Microsystems сформулировал **8 заблуждений о распределённых вычислениях** - ложных предположений, которые разработчики несут в production. Позже Джеймс Гослинг (создатель Java) дополнил список до 8 пунктов. Каждое нарушается рано или поздно.
Заблуждение 1: сеть надёжна
Пакеты теряются. Соединения разрываются. Свитчи падают. Буферы переполняются. В 2008 году акула перекусила подводный кабель у берегов Египта - упал 25% интернет-трафика Индии. Сеть - ненадёжный транспорт по определению.
| Паттерн | Применение |
|---|---|
| Retry с exponential backoff | Повторить запрос через 1с, 2с, 4с, 8с - не сразу |
| Идемпотентные операции | Повторный вызов с тем же idempotency-key не дублирует эффект |
| Circuit breaker | После N ошибок подряд - перестать слать запросы, дать время восстановиться |
| Timeout на каждый вызов | Без таймаута поток зависает навсегда |
Заблуждение 2: latency равна нулю
Вызов функции в памяти занимает ~1 наносекунду. Запрос к сервису в том же дата-центре - 1-2 миллисекунды, то есть в 1 000 000 раз медленнее. Между регионами - 50-150 мс. Через океан - 100-300 мс. Код который работает через один сетевой вызов не масштабируется до тысячи вызовов без переосмысления архитектуры. Механика TCP за этим latency-полом разобрана в уроке про TCP basics.
| Паттерн | Применение |
|---|---|
| Батчинг | 100 запросов одним вызовом вместо 100 последовательных |
| Кэширование | Частые запросы - из памяти, не по сети |
| Асинхронная обработка | Не ждать ответа - отправить в очередь и продолжить |
| CDN / edge | Данные географически ближе к пользователю |
Если сервис работает локально без ошибок - в production будет то же самое
Localhost скрывает оба заблуждения: локальная сеть надёжна и имеет ~0 latency. Production - другой мир
Именно поэтому chaos engineering (Netflix Chaos Monkey, 2010) - вводить случайные сбои в production намеренно. Системы должны проектироваться с расчётом на отказы, а не тестироваться на идеальных условиях.
Bandwidth безграничен и сеть безопасна
**2020 год. Netflix - 15% мирового интернет-трафика в пиковые часы. Переход на Protobuf вместо JSON сократил трафик в 3-7 раз. Экономия - десятки миллионов долларов в год только на bandwidth costs.** Это третье заблуждение: bandwidth не бесконечен и стоит денег.
Заблуждение 3: bandwidth безграничен
| Трафик AWS | Стоимость |
|---|---|
| Внутри одной AZ | Бесплатно |
| Между AZ одного региона | 0.01 USD/GB |
| Между регионами | 0.02-0.09 USD/GB |
| В интернет | 0.09 USD/GB |
100 TB трафика между регионами в месяц - это 2000 долларов только за transfer. При микросервисной архитектуре каждый сервис общается с несколькими другими. Умножить на 100 сервисов - получается ощутимая часть инфраструктурного бюджета.
- **Сжатие:** gzip на HTTP, Protobuf или MessagePack вместо JSON (3-10x меньше)
- **Пагинация:** не возвращать 10 000 записей когда нужна 1 страница из 20
- **Delta sync:** передавать только изменения, не полный объект
- **Локальность данных:** обработка там, где хранятся данные
Заблуждение 4: сеть безопасна
В 2015 году Juniper Networks обнаружила в своих VPN-устройствах бэкдор - кто-то на протяжении нескольких лет мог расшифровывать весь трафик через эти устройства. Пакеты перехватываются на любом hop-е между источником и получателем. Внутренняя корпоративная сеть не делает данные безопасными автоматически.
| Паттерн | Применение |
|---|---|
| TLS везде | Даже внутри дата-центра между сервисами |
| mTLS (mutual TLS) | Оба участника аутентифицируют друг друга сертификатами |
| Zero-trust архитектура | Никакой сети по умолчанию не доверяем, каждый запрос аутентифицируется |
| Шифрование at rest | Данные на диске зашифрованы, даже если диск украли |
Микросервис возвращает JSON-список из 500 пользователей (каждый ~2KB). Какая оптимизация даст наибольший эффект?
Топология статична и есть один администратор
**Kubernetes rolling update: 50 pod-ов заменяются новой версией. За 2 минуты IP-адреса меняются у 50 компонентов. Сервис, который хардкодировал IP в конфиге, теряет половину соединений.** Это заблуждение 5: в production топология меняется постоянно. Подробная оркестрация живёт в уроке про Kubernetes.
Заблуждение 5: топология не меняется
IP-адреса меняются при деплое, failover, автоскейлинге, миграции. В облачных средах сервер может быть пересоздан с новым IP в любой момент. Hardcoded IP в конфиге - это техдолг с коротким сроком жизни.
Заблуждение 6: есть один администратор
Реальная система зависит от десятков внешних компонентов: AWS, Stripe, Twilio, Auth0, GitHub. У каждого своё SLA, своё расписание обслуживания, свои инциденты. В 2021 году падение Fastly CDN на 1 час вывело из строя Reddit, GitHub, Financial Times и The Guardian - все они не контролировали CDN-провайдера. Паттерны связности микросервисов каталогизированы в уроке про микросервисы.
- **Graceful degradation:** при недоступности Stripe - показать кешированные данные, не упасть полностью
- **Fallback стратегии:** альтернативный провайдер или упрощённый путь
- **SLA-мониторинг:** не узнавать о проблемах внешних зависимостей от пользователей
- **Contract testing:** тестировать граничные условия интеграции, не только happy path
Если в SLA внешнего провайдера написано 99.9% uptime - проблем не будет
99.9% uptime = 8.76 часов даунтайма в год. Если 10 внешних зависимостей по 99.9% - суммарная доступность 99%^10 = 99%, то есть 87 часов в год
Availability систем перемножается, а не суммируется. Чем больше внешних зависимостей, тем ниже реальная доступность системы даже при хороших SLA у каждого.
Сервис оплаты падает - Stripe вернул 503. Как должна реагировать система интернет-магазина?
Транспорт бесплатен и сеть однородна
**Uber, 2018. Переход с REST/JSON на gRPC/Protobuf для внутренней коммуникации микросервисов. Результат: latency упала на 30-40%, CPU нагрузка на сериализацию сократилась вдвое, сетевой трафик - в 5-10 раз.** Это итоговые два заблуждения: транспорт не бесплатен, и сеть не однородна.
Заблуждение 7: транспорт бесплатен
Сетевые вызовы стоят: деньги за трафик, CPU на сериализацию/десериализацию, память на буферы, время на latency. JSON-объект в 1KB после сериализации, передачи и десериализации тратит в 10-100 раз больше ресурсов, чем кажется.
| Формат | Размер (пример) | CPU (сер/десер) | Читаемость |
|---|---|---|---|
| JSON | 100% | Высокий | Человекочитаем |
| MessagePack | ~50% | Средний | Бинарный |
| Protobuf | ~20-30% | Низкий | Требует схему |
| Avro | ~20% | Низкий | Требует схему |
Заблуждение 8: сеть однородна
В production одновременно работают: Linux серверы и Windows, Java 8 и Java 17, разные версии Kubernetes, разные encoding (UTF-8, Latin-1), big-endian и little-endian процессоры. Микросервис на Node.js общается с сервисом на Go и получает данные от Python-скрипта. Формат данных - контракт, нарушение которого приводит к silent data corruption.
Реальный баг: endianness mismatch
Сервис на x86 (little-endian) записывает int32 в файл: байты [01 00 00 00] = число 1. Сервис на SPARC (big-endian) читает те же байты: [01 00 00 00] = 16 777 216. Данные прошли без ошибки, но число неверное. Аналогичная проблема возникает с float, timestamp, любым бинарным форматом без явного указания byte order.
- **Стандартные форматы:** JSON, Protobuf, Avro с явной схемой - порядок байт определён
- **API версионирование:** `/v1/users`, `/v2/users` - не ломать совместимость
- **Backward compatibility:** новые поля опциональны, старые клиенты продолжают работать
- **Contract testing:** Pact, Dredd - тестировать контракт, а не реализацию
8 заблуждений - исторические артефакты 1990-х, современные cloud-native системы решили эти проблемы
Cloud native инструменты (Kubernetes, service mesh) смягчают некоторые заблуждения, но не устраняют их - переносят ответственность на другой уровень
Kubernetes решает топологию через service discovery. Istio решает mTLS. Но bandwidth, latency, надёжность сети - физические ограничения. А однородность и администрирование стали сложнее, не проще: теперь ещё и Kubernetes, Helm, Terraform, несколько облаков.
Ключевые идеи
- **Сеть ненадёжна** - пакеты теряются, буферы переполняются, кабели режут акулы; паттерны защиты: retry с exponential backoff, circuit breaker, timeout на каждый вызов
- **Latency не ноль** - в памяти ~1нс, в одном DC ~1-2мс, между регионами 50-150мс; решение: батчинг, кэш, async, CDN
- **Bandwidth не бесконечен** - кросс-региональный трафик в AWS стоит $0.02-0.09/GB; Protobuf вместо JSON даёт 3-7x экономию
- **Сеть небезопасна** - пакеты перехватываются на любом hop-е; паттерны: TLS везде, mTLS, zero-trust
- **Топология меняется** - IP меняются при деплое, failover, автоскейлинге; использовать service discovery, не хардкодировать адреса
- **Администраторов много** - внешние зависимости (AWS, Stripe, CDN) живут по своим SLA; 10 зависимостей по 99.9% = ~99% суммарно
- **Транспорт не бесплатен** - JSON горит CPU и память; Protobuf: размер -70-80%, CPU на сер/десер значительно ниже
- **Сеть неоднородна** - разные OS, версии, encoding, endianness; контракт данных обязателен: Protobuf/Avro со схемой, API versioning
Вопросы для размышления
- Вспомни последний сервис, который разрабатывался или отлаживался. Какие из 8 заблуждений были нарушены неявно? Где был hardcoded IP, не было timeout или JSON гонялся туда-обратно без сжатия?
Связанные уроки
- ds-02-cap-theorem — Понимание ненадёжной сети готовит почву для CAP partition
- sd-10-microservices — Любой mesh микросервисов спотыкается о те же восемь предположений
- net-15-tcp-basics — TCP retransmit и таймауты прямо отвечают на заблуждения 1 и 2
- ds-01-intro — Модель сбоев Лэмпорта формализует допущения Deutsch
- st-04-leverage — Скрытые допущения в любой сложной системе зеркалят эти заблуждения
- isd-11-load-balancing
- isd-09-caching-strategies
- net-01-intro