Распределённые системы

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 (сер/десер)Читаемость
JSON100%ВысокийЧеловекочитаем
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
8 заблуждений о распределённых системах

0

1

Войти

Сервис A вызывает сервис B 1000 раз подряд в цикле. Latency B - 2 мс. Что произойдёт?

Какое из 8 заблуждений является причиной большинства каскадных сбоев (cascade failures)?