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

un

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

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

Вітаємо

Більшість архітектурних діаграм показують трафік, що рухається в одному напрямку: клієнт зверху, сервер знизу, стрілка вгору вниз. У реальності трафік рухається в обох напрямках.

Вхідний трафік (Ingress): зовнішні клієнти отримують доступ до ваших сервісів через цей шлях. Зворотний проксі на межі мережі завершує TLS, маршрутизує запити та застосовує політику доступу.

Вихідний трафік (Egress): ваші сервіси отримують доступ до зовнішніх сервісів через цей шлях. Виклик API платіжного процесора, отримання цілі вебхука, надсилання запиту до партнера. Часто через прямий проксі або NAT-шлюз із білим списком.

Багато архітектур починаються з одного вузла, який обробляє обидва напрямки. Це працює, доки одного дня не перестане. Режим збою є тонким, проявляється лише тоді, коли існує достатня кількість внутрішніх сервісів, та вчить важливого уроку про розділення обов'язків.

Наприкінці цього уроку ви зрозумієте:

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

- Hairpin NAT та чому проксі, який намагається з'єднатися з самим собою, зазнає невдачі

- Архітектурна розвилка: один вузол стає двома, та що саме кожен з них тоді виключно обслуговує

- Переваги в ізоляції безпеки: кожна сторона може обмежити доступ лише до своїх реальних дозволених партнерів

- Як визначити, коли ваш проєкт з одним вузлом перетнув поріг, за якого розділення стає необхідним

Чому напрямки вимагають різних інструментів

Дві різні навантаження на одному межі мережі

Характеристики вхідного трафіку:

- Ініціюється зовнішніми сторонами (інтернет загалом)

- Обсяг зростає пропорційно до вашої бази користувачів

- Завершення TLS, маршрутизація запитів, обмеження частоти запитів за джерелом

- Питання захисту в глибину: DDoS, зловживання, скрапінг

- Публічний IP має приймати з'єднання від будь-кого

Характеристики вихідного трафіку:

- Ініціюються вашими власними сервісами (відома, невелика множина клієнтів)

- Обсяг зростає відповідно до ваших патернів викликів між сервісами та зовнішніми API

- Білий список IP-адрес джерел на віддалених кінцях (у вас є один фіксований вихідний IP, якому партнери довіряють)

- Застосунки захисту в глибину (defense-in-depth): витік даних, скомпрометовані внутрішні сервіси, які виконують вихідні виклики

- Має відхиляти з'єднання від будь-кого, крім ваших власних сервісів

Ключова асиметрія: вхідний трафік (ingress) приймає з'єднання з усього світу; вихідний трафік (egress) приймає з'єднання лише від ваших власних сервісів. Розміщення їх на одному сервері означає, що цей сервер має одночасно бути доступним із зовнішнього світу (для вхідного трафіку) та бути доступним лише від ваших сервісів (для вихідного трафіку). Правила брандмауера, що задовольняють одне вимогу, суперечать іншій.

Шлях розвитку: невеликий проєкт може приховати обидва потоки за одним IP та одним інструментом, оскільки обсяг невеликий, а білий список IP партнерів короткий. З розвитком проєкту тертя між цими двома ролями зростає, і одного дня конкретний сценарій збою (hairpin NAT) змушує розділити їх.

Вхідний та вихідний трафік: різні джерела, різні призначення, різні вимоги

Невелика стартап-компанія розміщує все (інгресний зворотний проксі, егресний прямий проксі / NAT, внутрішні сервіси) на одному віртуальному сервері з одним публічним IP. На ранньому етапі це здається прийнятним. Назвіть два конкретні режими збою або операційні труднощі, з якими стикнеться ця архітектура під час зростання, та для кожного з них поясніть основну причину.

Баг, який вимагає розділення

Історія про інцидент із «hairpin»-маршрутизацією

Уявіть реальну архітектурну розвилку, яка трапляється у продуктивних середовищах. Назви нижче змінено; структура ж точно відповідає тим проблемам, з якими стикаються команди на практиці.

Організація експлуатує єдиний проксі-сервер за адресою 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.com → 203.0.113.5

2. Внутрішній сервіс надсилає запит через SOCKS5-проксі вихідного трафіку на 203.0.113.5:1080

3. Проксі намагається встановити з'єднання від себе до 203.0.113.5:443

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

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

Чому це виникає пізно

На ранніх етапах проєкту всі внутрішні сервіси або спілкувалися з іншими внутрішніми сервісами за приватним іменем хоста (internal-api.local), або не викликали публічні сервіси власної організації. Шлях hairpin просто не існував.

Потім нова функція вимагала, щоб сервіс A викликав api.example.com (публічне ім'я хоста). Шлях hairpin активовано. З'єднання відхилено. Збій.

Виправлення усунуло симптом (примусити резолвер надавати приватний IP для api.example.com замість публічного). Коренева причина: один вузол виконував надто багато функцій.

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. Ізоляція безпеки. Фаєрвол сервера egress може бути налаштований для допуску лише невеликого набору внутрішніх IP-адрес. Фаєрвол сервера ingress залишається відкритим для зовнішнього світу. Дві окремі настанови, кожна з яких чітко виконує одну роль.

3. Незалежне масштабування. Пропускна здатність ingress масштабується залежно від кількості користувачів; пропускна здатність egress — залежно від активності внутрішніх служб. Можна оновлювати одне, не чіпаючи інше.

4. Ізоляція збоїв. Неправильно налаштований egress більше не ламає публічний сайт. DDoS-атака на публічний сайт більше не виснажує пропускну здатність egress.

5. Чіткіша модель мислення. Кожна машина виконує одну задачу. Інженери розглядають питання ingress, не думаючи про egress, і навпаки.

Після розділення внутрішній сервіс все ще має викликати `api.example.com`. Опишіть новий шлях пакета від внутрішнього сервісу до бекенду API. Включіть: який IP-адресу спочатку використовує внутрішній сервіс для з'єднання, що робить ця машина із запитом, який IP-адресу вона надсилає далі та куди йде відповідь.

Дві осі, два рішення щодо масштабування

Незалежне масштабування

До розділення зростання в будь-якому напрямку навантажувало той самий сервер. Після розділення кожен напрямок має власне забезпечення ресурсами.

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

Розмір вихідного потоку (Egress): масштабується залежно від обсягу викликів від внутрішніх сервісів до зовнішніх API. Часто домінує доставка вебхуків, виклики платіжних процесорів або отримання даних від третіх сторін. Бюджет пропускної здатності розраховується на основі внутрішніх патернів викликів.

Ізоляція збоїв: DDoS-атака на публічний вхідний потік більше не «з’їдає» пропускну здатність вихідного потоку (виклики до платіжних процесорів все одно проходять). Збій проксі вихідного потоку більше не вимикає публічний сайт (користувачі продовжують отримувати доступ до сайту; збої відбуваються лише у внутрішніх вихідних викликах).

Різні SLO: доступність вхідного потоку важлива для користувачів (видимий збій сайту); доступність вихідного потоку важлива для операторів (фонові збої, які можуть потребувати більше часу для виявлення). Кожна сторона може мати власні SLO.

Кілька серверів вихідного потоку

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

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

Нова інтеграція з партнером

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

Команда продукту хоче додати четверту інтеграцію: систему доставки вебхуків, яка викликає ендпоінти клієнтів по всьому світу. Прогноз обсягу: 10 000 викликів за хвилину, з піками до 30 000.

Прийміть рішення: чи має ця нова інтеграція працювати на наявному сервері вихідного трафіку, чи їй потрібен окремий шлях вихідного трафіку? Розгляньте пропускну здатність, ізоляцію збоїв та те, чи потрібно оновлювати білі списки наявних партнерів у будь-якому разі.

Проєктуйте мережевий кордон для зростаючого сервісу

Синтез

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

Застосуйте всі чотири аспекти.

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

Запропонуйте архітектуру вхідного / вихідного трафіку для цієї компанії. Розгляньте: скільки машин потрібно, які IP-адреси виконують які ролі, на що вказує DNS для кожного піддомену, які вихідні інтеграції спільно використовують шлях вихідного трафіку (і які слід розділити), та одну конкретну проблему моніторингу, яку новий дизайн робить можливим, але яка була недоступна в старому.

Куди веде цей курс далі

Куди веде цей курс далі

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

У наступному уроці (cs_distsys_failure_modes_and_blast_radius) розширюється логіка ізоляції збоїв. Ви прочитаєте очищений звіт про причини збою DNS-SERVFAIL, визначите патерн каскадного збою та напишете безвинні дії, які спрямовані на системи, а не на людей.

Супутній урок: geometry_of_ingress_egress_separation переосмислює розділення як дводольний граф та досліджує розрізні вершини, мережеві розділення та те, що теорія графів говорить про межі мережі.

Чудова робота. Далі.