English· Español· Deutsch· Nederlands· Français· 日本語· ქართული· 繁體中文· 简体中文· Português· Русский· العربية· हिन्दी· Italiano· 한국어· Polski· Svenska· Türkçe· Українська· Tiếng Việt· Bahasa Indonesia

un

гость
1 / ?
назад к урокам

Два направления трафика, один модуль

Добро пожаловать

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

Входящий трафик: внешние клиенты добираются до ваших сервисов по этому пути. Обратный прокси на границе вашей сети завершает TLS, маршрутизирует запросы и применяет политику доступа.

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

Многие архитектуры начинают с одного модуля, обрабатывающего и входящий, и исходящий трафик. Это работает, пока не наступит день, когда это не сработает. Нераспознаваемный режим отказа проявляется только после того, как возникнет достаточно внутренних сервисов, и преподносит важный урок разделения забот.

К концу этого урока вы сможете понять:

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

- Что такое Hairpin NAT и почему прокси, пытаясь подключиться к самому себе, терпит неудачу

- Архитектурный разветвление: один модуль превращается в два, и что каждый из них владеет исключительно

- Преимущества изоляции безопасности: каждый из сторон может закрывать доступ к своим реальным допустимым партнерам

- Как определить, когда ваша монолитная схема перешла порог, после которого разделение необходимо

Почему разные направления требуют разных инструментов

Два разных рабочих процесса на одной границе сети

Характеристики входящего трафика:

- Инициируется сторонами снаружи (интернет)

- Объем пропорционален базе пользователей

- Требует завершения TLS, маршрутизации запросов, ограничения скорости на источник

- Важность многослойной защиты: DDoS, злоупотребление правами, скрапинг

- Общественный IP должен принимать подключения от любого

Характеристики исходящего трафика:

- Инициируется вашими собственными сервисами (ограниченный набор клиентов)

- Объем пропорционален паттернам вызова сервиса-ко-сервиса и API внешних сервисов

- Раз 允олистинг IP-источника на удаленных конечных точках (у вас есть одна фиксированная исходящая IP, которую партнеры доверяют)

- Вопросы глубокой защиты: вытеснение данных, компрометированные внутренние сервисы, обращающиеся в исходящем режиме

- Должно отклонять соединения от любых других, чем ваши собственные сервисы

Ключевая асимметрия: вход принимает трафик из мира; исходящий принимает трафик только от ваших собственных сервисов. Разместить их на одной машине означает, что эта машина должна быть одновременно доступна из мира (для входа) & доступна только от ваших сервисов (для исходящего). Правила файрвола, удовлетворяющие одному, работают против другого.

Путь роста: маленький проект может прятать оба за одной IP и одной инструментальной средой, потому что объем мал и партнерский IP-разрешительный список короткий. По мере роста проекта, напряжение между двумя ролями увеличивается, и однажды специфический режим ошибки (внутренний NAT) заставляет разделить их.

Вход против исходящего: разные источники, разные назначения, разные требования

Маленькая стартап-компания использует один виртуальный сервер (VM) для выполнения всех задач (обратный прокси для входящего трафика, прямой прокси / NAT для исходящего трафика, внутренние сервисы) с одним общим IP-адресом. На данном этапе это кажется нормальным. Укажите два конкретных режима отказа или операционные проблемы, которые эта схема столкнется при росте компании, и для каждого из них объясните причину.

Баг, который заставляет разделить

Санированный отчет об отключении

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

Организация работает на одном прокси-сервере 203.0.113.5. Он обрабатывает вход (порт 443 для пользователей) и исходящий (порт 1080 SOCKS5 для внутренних сервисов, обращающихся в исходящем режиме). Внутренние сервисы находятся в приватных подсетях и направляют все исходящее подключение через этот SOCKS5-прокси на 203.0.113.5:1080.

Один из сервисов, размещенных за тем же 203.0.113.5, - api.example.com. Общественный DNS разрешает api.example.com на 203.0.113.5.

Теперь другой внутренний сервис должен позвонить api.example.com. Его исходящий путь:

1. Внутренний сервис разрешает api.example.com203.0.113.5

2. Внутренний сервис отправляет запрос через SOCKS5 исходящий прокси на 203.0.113.5:1080

3. Прокси пытается открыть соединение от себя к 203.0.113.5:443

4. Соединение отклонено. Пакет должен выйти и вернуться обратно в тот же самый NAT, который большинство сетевых стеков отклоняют. Прокси не может подключиться к себе через свою собственную публичную IP.

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

Почему это проявляется поздно

На ранней стадии жизни проекта каждое внутреннее служебное программное обеспечение либо общалось с другими внутренними служебными программами по приватному имени хоста (internal-api.local), либо не вызывало свои собственные общественные сервисы. Путь hairpin просто не существовал.

Затем новая функция потребовала, чтобы служба A вызывала api.example.com (общедоступное имя хоста). Активировался путь hairpin. Отказ в подключении. Сбой.

Правильное решение устранило симптом (обязать разрешающий передать приватный IP вместо общественного). Корень проблемы: одна коробка выполняла слишком много работ.

Hairpin NAT: пакет выходит и не может повторно войти в тот же NAT

Архитектурный разветвление

Одна коробка становится двумя

Чистое решение: разделить прокси на две машины.

Сервер входа (общедоступный IP 203.0.113.5):

- Caddy / обратный прокси на портах 80, 443

- Общедоступные записи DNS указывают сюда

- Хостит api.example.com, app.example.com и т.д.

Сервер выхода (другой общедоступный IP 203.0.113.99):

- SOCKS5 / прямой прокси на порту 1080

- Плита ограничивает входящие подключения только IP внутренних под сетей

- Внутренние служебные программы отправляют все транзитное через этот адрес

Что это дает:

1. Hairpin решен. Внутреннее служебное программное обеспечение, вызывающее api.example.com, маршрутизирует транзит через 203.0.113.99 (egress), который затем подключается нормально к 203.0.113.5 (ingress, другой IP). Петля NAT исчезает, потому что две IP-адреса живут на разных машинах.

2. Изоляция безопасности. Плита файрвола сервера выхода может ограничить небольшой набор внутренних IP. Плита файрвола сервера входа остается открытым для мира. Два разных набора правил, каждый из которых выражает одну роль чисто.

3. независимое масштабирование. Ширина канала входа масштабируется с увеличением пользователей; ширина канала выхода масштабируется с увеличением внутреннего сервисного активности. Обновление одного без касания другого.

4. Изоляция ошибок. Неправильная настройка сервера выхода больше не вызывает сбой на общественном сайте. DDoS против общественного сайта больше не истощает пропускную способность выхода.

5. Clearer mental model. Каждая машина имеет одну задачу. Инженеры думают о проблемах входа, не думая о выходе, и наоборот.

После разделения внутреннее служебное программное обеспечение все еще должно вызывать api.example.com. Пройдитесь по новому пути пакета от внутреннего сервиса до backend api. Включая: с какой IP внутреннее служебное программное обеспечение подключается в первую очередь, что делает эта машина с запросом, с какой IP она отправляет его дальше и куда идет ответ.

Два оси, две принятых решений

Независимое масштабирование

Перед разделением рост в любом направлении создавал проблемы для одной и той же машины. После разделения каждое направление имеет собственное обслуживание.

Размерность входа: масштабируется с пользователями. Принятие решений о вместимости находится в публичном фронтенд-уровне (более реплик обратного прокси, большие виртуальные машины, CDN перед фронтендом). Бюджет пропускной способности рассчитывается в соответствии с трафиком пользователей в пиковом режиме.

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

Изоляция сбоев: DDoS-атака против публичного ingress больше не съедает пропускную способность egress (т.е. вызовы платежных процессоров продолжаются). Сбой в проксе egress больше не приводит к падению публичного сайта (пользователи продолжают достигать сайта, а только внутренние вызовы выхода терпят неудачу).

Различные СLO: доступность ingress важна для пользователей (видимый сбой сайта); доступность egress важна для операторов (скрытые сбои, которые могут дольше обнаруживаться). Каждая сторона может поддерживать свой собственный СLO.

Множество серверов egress

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

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

Новый партнерский интеграции

Ваша организация использует разделение ingress / egress, как задано. Сервер egress имеет фиксированный публичный IP (203.0.113.99), который вы разрешили для трех существующих API-партнеров (платежный процессор, SMS-шлюз, поставщик почтовых услуг).

Команда продукта хочет добавить четвертую интеграцию: систему доставки вебhooks, которая вызывает обратно конечные точки клиентов по всему миру. Ожидаемый объем: 10 000 вызовов в минуту, с пиками до 30 000.

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

Проектирование границы сети для растущей службы

Синтез

Вы узнали, почему ingress и egress требуют разных инструментов, о провале hairpin NAT, который заставляет разделить реальные флиты, и как независимое масштабирование, изоляция безопасности и изоляция отказов накапливаются после того, как разделение становится реальностью.

Примените все четыре.

Среднего размера компания SaaS использует три поддоменные службы для своих пользователей (app, api, admin), а также четыре внешние интеграции (Stripe, Twilio, SendGrid, систему вебhooks для клиентов). Сегодня все живет за одной прокси-машины с одним IP-адресом. Они начали получать сообщения об интермиттирующих провалах hairpin, когда внутренние сервисы пытаются вызвать api.example.com. Они хотят разработать постоянное решение.

Предложите архитектуру ingress / egress для этой компании. Обратите внимание на количество машин, которые обслуживают какие-то IP-адреса, куда указывают каждая поддоменная DNS, какая интеграция должна использовать один путь выхода (и которые должны быть разделены) и одно конкретное мониторинговое обеспечение, которое новая архитектура позволяет, но старая не могла.

Где эта программа идет дальше

Где эта программа идет дальше

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

В следующем уроке (cs_distsys_failure_modes_and_blast_radius) расширение рассуждений об изоляции отказов. Вы прочтете саницифицированный DNS-SERVFAIL postmortem, определите паттерн каскадного провала и напишете безобидные меры, которые целятся на системы вместо людей.

Урок по теме: geometry_of_ingress_egress_separation преобразует разделение в бипартитную граф и исследует вершины разрыва, разделения сетей и то, что теория графов говорит вам о границе сети.

Хорошо сделано. Дальше.