惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Stack Overflow Blog
Stack Overflow Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
H
Hacker News: Front Page
S
Security Affairs
Google Online Security Blog
Google Online Security Blog
Attack and Defense Labs
Attack and Defense Labs
H
Heimdal Security Blog
S
Securelist
S
Secure Thoughts
N
News and Events Feed by Topic
T
The Exploit Database - CXSecurity.com
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Last Week in AI
Last Week in AI
The Last Watchdog
The Last Watchdog
N
News | PayPal Newsroom
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
IT之家
IT之家
宝玉的分享
宝玉的分享
有赞技术团队
有赞技术团队
O
OpenAI News
V
Vulnerabilities – Threatpost
S
Schneier on Security
Cyberwarzone
Cyberwarzone
雷峰网
雷峰网
罗磊的独立博客
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
J
Java Code Geeks
Google DeepMind News
Google DeepMind News
The Cloudflare Blog
美团技术团队
人人都是产品经理
人人都是产品经理
T
The Blog of Author Tim Ferriss
T
Tor Project blog
P
Privacy International News Feed
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Google DeepMind News
Google DeepMind News
S
Security @ Cisco Blogs
Project Zero
Project Zero
Security Archives - TechRepublic
Security Archives - TechRepublic
Schneier on Security
Schneier on Security
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
P
Proofpoint News Feed
K
Kaspersky official blog
P
Privacy & Cybersecurity Law Blog
aimingoo的专栏
aimingoo的专栏
L
LINUX DO - 热门话题
V
V2EX
Blog — PlanetScale
Blog — PlanetScale
www.infosecurity-magazine.com
www.infosecurity-magazine.com
U
Unit 42

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Как виртуальные машины общаются в облаке MWS Cloud Platform: разбираем Data Plane
Ghostttty · 2026-06-26 · via Все публикации подряд на Хабре

В облачных сетях принято разделять два уровня: физический Underlay и виртуальный Overlay. Если Underlay — это фундамент здания (кабели, коммутаторы, базовая IP-связность), то Overlay — инженерные коммуникации: невидимые глазу, но без которых жизнь в доме остановится. От того, насколько эффективно и надёжно спроектирован Overlay, напрямую зависят скорость пользовательских приложений и стабильность всей платформы.

Привет! Меня зовут Валерий Симаков, я разработчик команды Network DPL в MWS Cloud Platform. Сегодня мы подробно поговорим о сетевой составляющей нашего облака, а именно об устройстве Data Plane (DPL) в Overlay-слое — том самом слое, который и отвечает за передачу пользовательского трафика. Мы разберём, как из разрозненных компонентов рождается единый, слаженный механизм передачи данных. Благодарю коллег из команды Network DPL за помощь в подготовке статьи.

Как соединить части и получить целое

На Хабре вышло уже немало материалов, посвящённых архитектуре облачной платформы MWS Cloud Platform: мы рассказывали об общем видении и выборе технологий, детально разбирали устройство физического Underlay-слоя и даже заглядывали внутрь самих виртуальных машин. Отдельного упоминания заслуживает и технология SRv6, которая лежит в основе нашей Overlay-сети. Однако до сих пор оставался без ответа важный вопрос: как все эти компоненты работают вместе, обеспечивая базовую связность виртуальных машин? 

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

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

Именно из этого стремления к простоте и родилась та связка QEMU, VPP и SRv6, о которой и пойдёт речь далее. Мы разберём, как этот механизм устроен и за счёт чего виртуальные машины в MWS Cloud общаются тихо, не спеша, без суеты, но в то же время быстро и с чётким пониманием, куда летит каждый пакет.

Монструм или терминоописание

Прежде чем продолжить, введу основные понятия, которые нам понадобятся в дальнейшем

QEMU — это эмулятор, с помощью которого мы создаём и запускаем виртуальные машины на наших физических серверах. В паре с аппаратным ускорителем KVM он позволяет добиться производительности, близкой к «голому железу».

DPDK (Data Plane Development Kit) — набор библиотек и драйверов для высокопроизводительной обработки сетевых пакетов в пространстве пользователя (user-space), минуя стандартный сетевой стек операционной системы. В нашем случае это отдельный плагин в VPP, выступающий мостиком между драйверами на хосте и самим VPP, позволяя напрямую взаимодействовать с сетевым оборудованием, забирая пакеты из кольцевых буферов сетевой карты без участия ядра и дорогостоящих системных вызовов.

VPP (Vector Packet Processing) — высокопроизводительный сетевой стек, работающий в пространстве пользователя. Его главное преимущество — векторная обработка сетевого трафика: вместо того чтобы обрабатывать каждый пакет по отдельности, VPP группирует их и применяет одни и те же операции сразу ко всей группе. В MWS Cloud Platform именно VPP является ядром Data Plane на каждом вычислительном узле.

Vhost-user — протокол, который связывает виртуальную машину (QEMU) и наше ядро (VPP). Он позволяет передавать сетевые пакеты напрямую через разделяемую память, минуя накладные расходы операционной системы. Благодаря vhost-user виртуальная машина общается с VPP через общую shared memory, избегая лишних копирований пакетов между процессами.

Underlay — физическая основа сети, её «скелет». Это коммутаторы, маршрутизаторы и оптоволоконные линии в дата-центрах, которые обеспечивают базовую IP-связность между всеми серверами. Underlay не знает ничего о виртуальных машинах — он лишь доставляет пакеты от одного физического хоста к другому.

SRv6 (Segment Routing over IPv6) — технология, которая позволяет гибко управлять маршрутами трафика в виртуальной сети Overlay. Идея проста: путь каждого пакета кодируется прямо в его IPv6-заголовке в виде цепочки сегментов. Это избавляет нас от необходимости держать сложные таблицы маршрутизации на промежуточных узлах и делает сеть более масштабируемой, то есть никакого состояния на underlay.

NUMA (Non-Uniform Memory Access) — архитектура памяти в мультипроцессорной системе, при которой время доступа к разным областям оперативной памяти неодинаково. Процессор обращается к своей локальной памяти быстро, а к памяти другого процессора — заметно медленнее. 

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

О чём говорят машины

В данной главе мы касаемся вопроса сетевого обмена и используем термины Compute- и Border-хостов, которые будут разобраны в следующей главе. На данный момент достаточно информации, что Compute-хост — это сервер, на котором располагаются VMs, а Border-хост — это пограничный сервер между облаком и глобальным интернетом, который выполняет в основном задачи маршрутизации.

Теперь важный момент, касающийся адресации. У виртуальной машины в MWS Cloud Platform может быть два IP-адреса. Чтобы лучше понять их суть, представьте, что наша виртуальная машина — это человек, у которого, подобно традиции некоторых культур, есть два имени:

1)   Внутренний IP-адрес — это как имя для близкого круга. Допустим, нашу виртуальную машину зовут Серёжа. Когда мы находимся в небольшой компании друзей (в рамках одной приватной облачной сети), достаточно просто окликнуть: «Серёжа!» — и нужный Серёжа отзовётся. Но попробуйте крикнуть «Серёжа!» в час пик на станции метро — вероятность, что к вам подойдёт именно тот Серёжа, о котором вы подумали, крайне мала. Внутренний IP-адрес уникален только в пределах вашей виртуальной сети в облаке и не виден из большого мира.

2)   Внешний IP-адрес — это уже аналог уникального номера паспорта, который позволяет однозначно идентифицировать человека в масштабах всей страны. По этому адресу к виртуальной машине можно обращаться из любой точки глобального интернета, и пакет гарантированно найдёт нужную VM, даже если в мире есть миллионы других Серёж. Внешний адрес — штука дефицитная (IPv4 давно кончились), и за его использование обычно выставляется отдельный счёт.

Когда мы говорим о пользовательском трафике, мы всегда имеем в виду IPv4

Несмотря на то что в статье часто упоминается IPv6, речь о нём идёт исключительно в контексте облачного Underlay-слоя. Причина проста: глобальное распространение IPv6 всё ещё оставляет желать лучшего — многие провайдеры до сих пор не предоставляют такую возможность конечному пользователю. Технически ничто не мешает упаковать пользовательский IPv6-пакет в IPv6-обёртку (так называемый IPv6-over‑IPv6) с SRv6-заголовком и точно так же успешно передать его по облаку, но пока реальность диктует нам работу с четвёртой версией протокола. Кто знает, может сразу придётся добавлять поддержку IPv8?

Возникает резонный вопрос: почему бы не использовать только внешние IP-адреса для всего? Ответ прост: их физически ограниченное количество и каждый такой адрес, закреплённый за виртуальной машиной, — это дополнительная строка в биллинге. Внутренние же адреса внутри облака бесплатны и не подвержены дефициту. На этом, пожалуй, оставим Серёжу в покое и вернёмся к сетевой связности.

На основе фактора сетевого общения можно выделить 2 принципиально разных сценария: 

Когда VM общается с другой VM в рамках одной облачной сети

Для полноты картины сразу отмечу, что, если бы обе VM располагались на одном хосте, весь маршрут упростился бы буквально на пару шагов, но в остальном принцип остался бы неизменным.

Итак, два виртуальных «Серёжи» — VM 1 с адресом 192.168.5.4 и VM 2 с адресом 192.168.5.5 — принадлежат одной приватной сети. Организационно это означает, что на каждом Compute-хосте этой сети выделен отдельный VRF. VRF — это, по сути, виртуальный маршрутизатор со своей собственной таблицей маршрутизации. 

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

А теперь ключевой трюк, который делает всю эту магию возможной. Для наглядности представим в виде диаграммы:

Благодаря тому что SDN-агент (в нашей терминологии CPL) непрерывно следит за состоянием облака, VPP на Хосте 1 точно знает: VM 2 с адресом 192.168.5.5 находится на Хосте 2, и даже знает сам адрес хоста 2 в формате IPv6. Когда VM 1 хочет отправить сообщение VM 2, она формирует обычный IPv4-пакет и передаёт его локальному VPP. VPP, заглянув в свою таблицу (заботливо заполненную Network-agent по конфигурации из CPL), видит целевой хост, на котором расположена VM 2.

VPP Хоста 1 инкапсулирует исходный IPv4-пакет в новый IPv6-заголовок с SRv6-секцией, в которой прописан нужный путь через Underlay до Хоста 2. Фактически этот заголовок говорит: «доставь меня на Хост 2, а как доставишь — действуй по зашитому на нём локальному правилу». Готовый пакет уходит в оптоволоконные недра физической Underlay-сети.

Когда посылка достигает Хоста 2, его встречает местный VPP. Первым делом он смотрит: «Так, пункт назначения — я. Значит, снимаю внешний заголовок». После декапсуляции остаётся исходный IPv4-пакет, адресованный 192.168.5.5. VPP сверяется с внутренней таблицей маршрутизации того VRF, которому принадлежит приватная сеть наших машин, и видит, что этот адрес привязан к виртуальному интерфейсу VM 2. Последний рывок — пакет попадает внутрь VM 2. Цель достигнута.

Обратный путь абсолютно симметричен: VM 2 отправляет ответный пакет, VPP Хоста 2 упаковывает его в SRv6 с маршрутом до Хоста 1 и весь процесс повторяется в зеркальном отражении. Так, шаг за шагом, две виртуальные машины в разных концах дата-центра общаются так, будто сидят в одном коммутаторе.

Когда VM общается напрямую с интернетом

Когда же VM 1 требуется дотянуться до ресурса за пределами облака, общая логика остаётся похожей, но появляется дополнительный участник — Border-хост. Сразу оговорюсь: вопросы работы BGP, DNS и прочей пограничной магии я умышленно оставляю за скобками, иначе мы рискуем никогда не закончить эту статью.

Итак, VM 1 формирует обычный IPv4-пакет, адресованный какому-нибудь внешнему серверу. VM 1 передаёт его в локальный VPP на Compute-хосте. VPP смотрит на адрес назначения и видит: это не сосед по приватной сети, не другая VM в облаке, а «внешний мир». Иными словами, l3-посылке пора отправляться в большое плавание за пределы нашего Underlay. Тогда сначала пакет проходит NAT’ирование, чтобы подменить приватный адрес на публичный. После чего, поскольку все дороги наружу лежат через пограничный узел, локальный VPP немедленно инкапсулирует IPv4-пакет в IPv6-обёртку с SRv6-заголовком, где в явном виде прописан маршрут до нужного Border-хоста, и передаёт его в физическую Underlay-сеть.

На Border-хосте работает такой же VPP. Получив датаграмму из Underlay, он снимает внешний IPv6-заголовок вместе с SRv6-секцией, извлекая исходный IPv4. Теперь ему нужно просто отправить пакет дальше — и он уходит в сторону интернет-провайдера уже в качестве классической IPv4-посылки.

Теперь обратный путь. Допустим, внешний сервер отвечает, и ответный пакет приходит на тот самый публичный IP-адрес, под которым скрывается VM 1. Он попадает на Border-хост. Здесь VPP по адресу назначения (публичному IP) мгновенно понимает, какой именно виртуальной машине он предназначался — эту информацию, как вы уже догадываетесь, заранее подготовил и раздал SDN-агент CPL. Дальше знакомый трюк: Border-хост упаковывает полученный IPv4-пакет в IPv6-заголовок с SRv6-маршрутом, ведущим точно на тот Compute-хост, где живёт VM 1. После он ныряет в Underlay, доезжает до нужного хоста, где локальный VPP снимает обёртку, проходит NAT (трансляцию сетевых адресов)  в приватный адрес и передаёт его прямиком внутрь виртуальной машины. Вуаля — круг замкнулся.

Аналогичным образом обрабатывается и входящее соединение, инициированное из интернета, например, когда кто-то снаружи хочет достучаться до нашего веб-сервера. Разница лишь в том, что первый шаг делает не VM, а внешний отправитель. Пакет приходит на Border-хост, тот находит нужную VM, упаковывает пакет в SRv6 и отправляет по Underlay. Ответный же трафик пойдёт по исходящему сценарию, который мы только что разобрали. Так два мира: облачный Underlay и глобальный интернет — обмениваются данными, а Border-хост служит бесшумным и стремительным переводчиком между ними.

Теперь пора поговорить про устройство самих хостов, разобрав чёрный ящик отвёрткой. 

Откуда растут хосты

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

Border-хост 

Специализированный физический сервер, выполняющий роль пограничного маршрутизатора между публичным интернетом и внутренней облачной инфраструктурой MWS Cloud Platform. Для простоты можно сказать, что Border-хост — это парадный подъезд с охраной и почтовым отделением в рамках облачной инфраструктуры: именно через него проходят все «посылки», адресованные облачным виртуальным машинам из внешнего мира, и через него же отправляются наружу все ответные и исходящие отправления.

На Border-хосте нет виртуальных машин — он целиком занят обработкой и маршрутизацией трафика. Программно его основу составляет VPP, работающий в связке с DPDK. При этом Border-хост видит одновременно две реальности: с одной стороны — интернет с его классическими IPv4-маршрутами, с другой — внутренний Underlay на базе IPv6.

Схематично это можно представить так:

Где RX-hardware — это аппаратная часть сетевого интерфейса (сетевой карты), отвечающая за приём пакетов, а TX-hardware — за передачу.

Основная задача Border-хоста — быть «переводчиком» на стыке двух миров: внешнего (интернет) и внутреннего (облачный Underlay MWS Cloud). Для каждого направления эта трансляция выглядит по-своему. Рассмотрим два ключевых сценария. 

Сценарий 1: входящий трафик из интернета

Когда пакет поступает на Border-хост из внешней сети, никакого SRv6-заголовка у него, разумеется, нет. Это обычный IPv4-пакет, адресованный публичному IP-адресу, закреплённому за одной из виртуальных машин в нашем облаке.

Первым делом VPP на Border-хосте анализирует адрес назначения пакета. Здесь в игру вступает CPL — наш централизованный SDN-агент, который в режиме реального времени отслеживает состояние всей облачной инфраструктуры. Именно CPL заранее «рассказал» Border-хосту, за каким публичным IP-адресом скрывается конкретная виртуальная машина и какой путь к ней нужно построить. Фактически Border-хост располагает полной картой соответствия для дальнейшего построения SRv6-цепочки. 

Дополнительно на Border-хосте расположен внешний Load Balancer, поэтому если пришедший пакет пришел на Virtual IP внешнего балансировщика, то далее сетевой пакет отправляется туда.

После этого путь сетевого трафика, прошедшего балансировщик и изначально не предназначенного ему, схож: когда становится ясно, для какой именно виртуальной машины предназначен трафик, VPP выполняет инкапсуляцию: вложенный IPv4-пакет упаковывается в новый IPv6-заголовок с SRv6-секцией, где прописан точный маршрут через Underlay-сеть до нужного compute-хоста. После этого пакет отправляется вглубь облака, где его дальнейшей судьбы мы коснёмся при изучении самого compute-хоста.

Сценарий 2: исходящий трафик в интернет

Во всех случаях, когда пакет приходит к Border-хосту из облачной Underlay-сети, это означает, что виртуальная машина отправляет данные во «внешний мир». Такой пакет приходит в SRv6-обёртке. Задача Border-хоста — выполнить декапсуляцию: снять внешний IPv6-заголовок и SRv6-секцию, освободив исходный IPv4-пакет. Затем чистый IPv4-пакет отправляется в сторону провайдера по стандартным правилам IP-маршрутизации.

Border-хост не подключён напрямую к интернет-провайдеру

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

Compute-хост

Физический сервер, на котором работают виртуальные машины. Если продолжить аналогию с многоквартирным домом, то compute-хост — это само здание с общей инфраструктурой: фундаментом (процессорные ядра), водопроводом и электричеством (оперативная память, сетевые интерфейсы). Каждая квартира в этом доме — отдельная виртуальная машина, изолированная от соседей, но пользующаяся общими ресурсами здания. Роль управляющей компании, которая следит за порядком и распределяет ресурсы, выполняет гипервизор QEMU/KVM. А чтобы жильцы могли быстро отправлять и получать «посылки» (сетевые пакеты), в доме работает высокоскоростной почтовый сервис — VPP, связанный с каждой квартирой через отдельный протокол vhost-user. 

Важно, что дом разбит на несколько подъездов (NUMA-узлов) и для максимальной эффективности каждый жилец привязан к определённому подъезду, чтобы не бегать через весь дом за своими посылками, но об этом мы поговорим позднее.

Схематично это можно представить так:

На первый взгляд схема может показаться запутанной, но давайте разбираться по порядку. Как уже рассказывалось в предыдущих материалах, Underlay-сеть MWS Cloud Platform целиком построена на IPv6 и активно использует технологию SRv6 (Segment Routing over IPv6). Соответственно, каждый физический хост в такой сети имеет уникальный IPv6-адрес.

Когда закодированный в SRv6 пакет поступает на входной сетевой интерфейс хоста, VPP первым делом анализирует его SRv6-заголовок. Он проверяет, не является ли данный хост конечной точкой (EndPoint) для этого конкретного сегмента маршрута. Если нет — значит, посылка предназначена другому хосту, и VPP, строго следуя правилам SRv6, обновляет заголовок и отправляет пакет дальше по цепочке сегментов.

Если же хост действительно конечная точка, начинается самое интересное: внешний IPv6-заголовок (вместе с SRv6-обёрткой) снимается и на свет появляется исходный внутренний IPv4-пакет. Но просто «освободить» его недостаточно — нужно понять, что с ним делать внутри хоста. Для этого в SRv6 используется Local SID — специальный сегмент, который описывает поведение непосредственно на этом узле. 

В наш Local SID заранее зашита вся необходимая информация: к какой виртуальной машине или группе машин направляется пакет, требуется ли ему предварительно пройти через NAT, попасть на внутренний Load Balancer, в каком изолированном домене маршрутизации VRF он должен перемещаться и даже на каком именно NUMA-узле его следует обрабатывать, чтобы соблюсти NUMA locality.

Итак, пакет попадает в назначенный ему VRF и дальше его судьба зависит от конкретного сценария:

NAT: если виртуальная машина общается с внешним миром, пакет сначала проходит трансляцию адресов, подменяя приватный адрес на публичный (или наоборот).

Load Balancer: если запрос адресован не конкретной VM, а сервису, балансировщик выбирает один из здоровых бэкендов и отправляет пакет к нему.

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

В любом случае после всех этих шагов мы оказываемся на финишной прямой: IPv4-адрес назначения нашего пакета совпадает с адресом, который носит виртуальный Ethernet-интерфейс внутри целевой VM (этот адрес, разумеется, равен внутреннему IP-адресу виртуальной машины).

Здесь нас и поджидает тот самый «мост» — протокол vhost-user, который связывает процесс VPP с конкретной виртуальной машиной. Дополнительно лишь укажу, что с точки зрения vhost-user терминологии, QEMU выступает в качестве сервера, а VPP подключается к нему как клиент (справедливости ради, в терминологии vhost-user протокола существует не только клиент-сервер, но и frontend-backend, правда этот аспект уже сильно выходит за рамки данной статьи). После согласования параметров соединения они начинают общаться через общую область памяти (shared memory).

VPP, обработав пакет, помещает его в разделяемую память и уведомляет «соседа». Гостевой агент (virtio-драйвер внутри QEMU/KVM) забирает его из общей памяти и передаёт его операционной системе виртуальной машины. Цель достигнута: сообщение доставлено из одного облачного уголка в другой, преодолев цепочку из физических и виртуальных устройств. На этом мы оставим наш пакет — ему ведь ещё лететь обратно, но это уже совсем другая история.

Итак, NUMA

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

·  NUMA (Non-Uniform Memory Access) — архитектура памяти в мультипроцессорной системе, при которой время доступа к разным областям оперативной памяти неодинаково. Процессор обращается к своей локальной памяти быстро, а к памяти, висящей на другом процессоре, — заметно медленнее. В облачном контексте этим «тормозом» пренебрегать нельзя, потому что он напрямую сказывается на скорости передачи данных.

·  NUMA Node — аппаратная группировка процессорных ядер, памяти и устройств ввода-вывода. Ядра, работающие в пределах одной ноды, имеют быстрый доступ к своей локальной памяти. Память соседних нод для них — удалённая, и каждый поход за данными туда обходится дороже.

·  Cross-NUMA — ситуация, когда ядро процессора из одной NUMA-ноды обращается к памяти, физически подключённой к другой ноде. Это как если бы жилец из одного подъезда многоквартирного дома каждый раз бегал за водой на другой этаж через всё здание — технически возможно, но крайне неэффективно.

·  NUMA Penalty — тот самый «штраф» за cross-NUMA взаимодействие, выражающийся в дополнительных тактах процессорного времени и возросших задержках. Для Data Plane, где счёт идёт на микросекунды, такие штрафы быстро складываются в неприемлемые потери производительности.

·  NUMA Locality — принцип организации работы, при котором каждый процесс или поток использует исключительно ту память, которая находится в его локальной NUMA-ноде. Цель — свести cross-NUMA взаимодействие к минимуму, а в идеале исключить его вовсе. Именно этот принцип мы строго соблюдаем при размещении VPP и QEMU на наших Compute-хостах.

К счастью, когда мы говорим о проекте VPP, стоит признать, что текущая реализация, находящаяся в open source, уже «с коробки» следует принципам NUMA Locality, насколько это возможно, и не нуждается в дополнительных доработках, например: VPP умеет в NUMA-осведомлённую агрегацию интерфейсов (bonding) с приоритетом локальных, NUMA-осведомлённое векторное выделение памяти и в целом выделение памяти с помощью готовых внутренних библиотек на необходимой NUMA-ноде — так называемый pmalloc. А это значит, что с нашей стороны была только необходимость использовать готовую базу, чтобы минимизировать penalty настолько, насколько это возможно, ведь полностью исключить невозможно, и далее мы разберём почему.

По степени внедрения NUMA locality можно выстроить следующую градацию:

«Полное» NUMA locality — это идеальный случай, при котором penalty равен нулю: процессор работает исключительно со своей локальной памятью и никаких перекрёстных обращений не происходит. «Частичное» — ситуация, когда penalty положительный, но мы сознательно идём на компромисс, стараясь удержать штраф в разумных пределах. «Отсутствует» — наихудший сценарий, когда cross-NUMA доступы происходят хаотично и бесконтрольно, порождая максимальный штраф; таких ситуаций в высоконагруженной сетевой подсистеме нужно избегать любой ценой.

О том, что NUMA penalty может быть весьма ощутимым, дополнительных исследований можно не проводить — их существует достаточно, причём на любой вкус, вот лишь один пример — статья на Academia.edu.

Казалось бы, вывод очевиден: всегда стремись к полному NUMA locality. Но есть нюанс, и его лучше представить графически:

Варианты прохождения сетевого трафика с точки зрения NUMA locality

Варианты прохождения сетевого трафика с точки зрения NUMA locality

Эта иллюстрация подтверждает предыдущую таблицу, и всё хорошо, но теперь несколько поменяем сценарий:

Пример частного случая обработки трафика

Пример частного случая обработки трафика

Здесь мы попадаем в ситуацию, когда полностью избежать NUMA penalty уже невозможно. Да, в идеале мы размещаем виртуальные машины в пределах одной NUMA-ноды, но бывают случаи, когда ресурсов этой ноды физически не хватает — и тогда приходится мириться с частичным NUMA locality. К счастью, архитектура MWS Cloud спроектирована так, чтобы даже в этом компромиссном варианте штраф оставался минимальным.

Выше, в главе про путь пакета, мы упоминали, что в Local SID SRv6 зашита информация о том, на каком именно NUMA-узле следует продолжать обработку трафика. Именно этот механизм позволяет принимать пакет сразу на DPDK-интерфейсе, локальном для нужной ноды, а не гонять его через межпроцессорные шины к соседнему узлу. Вдобавок наш SDN-агент CPL при создании виртуальной машины заранее знает, к какой NUMA-ноде её ресурсы будут привязаны, и инструктирует систему размещать ресурсы строго локально по отношению к этой VM.

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

Крякнем, плюнем и надёжно склеим скотчем

Наверное, самый короткий пункт в нашем рассказе — доработки проекта VPP. Здесь можно выделить два абсолютно важных направления.

Первое — Upstream VPP. VPP — это огромный проект с живым и весьма дружелюбным сообществом, в котором рады доработкам и исправлениям независимо от региона и корпоративной принадлежности (Linux, привет!). Поэтому запереться в комнате с собственным форком — путь заранее провальный. Мы по нему и не пошли. Разумеется, у нас есть форк на корпоративном GitLab — так работает любой инженерный процесс. Если в процессе работы обнаруживается неисправность в оригинальном коде, её исправление подразумевает работу с upstream, то есть, например, создание pull request в оригинальный проект (в качестве домашнего задания можно проверить этот факт на https://gerrit.fd.io/r/, поискав почты в домене mts.ru). К сожалению, мы пока только формируем процесс работы с upstream, поэтому пушим не очень часто, но мы прикладываем усилия, чтобы это изменилось в ближайшее время.

Помимо этого, раз в определённое время происходит синхронизация между нашим форком и оригинальным VPP, — мы забираем свежие изменения, а свои правки возвращаем обратно. Это позволяет нам всегда оставаться на гребне волны и не копить технический долг.

Второе — персональные плагины. У VPP есть одна особенность, известная каждому, кто погружался в этот чудесный мир: часть плагинов реализована, скажем так, «для галочки». Да-да, load balancer и nat, речь про вас. Несложно догадаться, что в том состоянии, в котором оба этих плагина пребывают в upstream, использовать их в реальном облаке решительно невозможно. Load balancer нам пришлось серьёзно допиливать, хотя нет-нет да и проскальзывают мысли переписать всё с нуля. NAT же был реализован полностью с нуля и с оригинальным плагином имеет общее разве что название. 

Внимательный читатель тут же задастся вопросом: в предыдущем пункте вы говорили про развитие upstream, а теперь внезапно переписали и не поделились. Всё так. Эти плагины слишком сильно разошлись с оригинальным проектом, и в open source им, откровенно говоря, делать нечего — да и незачем: их архитектура завязана на наши внутренние механизмы, а для внешнего мира они просто неактуальны.

Естественно, на этих двух направлениях различия не заканчиваются. Есть ещё отдельные доработки для диагностики, отладки и анализа состояния сети, реализованные в виде самостоятельных решений вокруг VPP. Но это уже совсем другая история, балансирующая между выходом за рамки данной статьи и NDA.

Сколько жмёшь

К сожалению, эта глава наступила. Почему, «к сожалению»? Потому что замер производительности — самая неблагодарная задача. Результаты зависят от методики, от ресурсов тестовых стендов, от версий инструментов, от положения Венеры в Меркурии, от фазы луны и, конечно, от того, с какой ноги сегодня встал тестировщик (ещё немного — и я проведу исследование на тему корреляции между результатами бенчмарков и временем в пути на работу). А ещё есть неприятный нюанс: продукт постоянно развивается, а значит, цифры, полученные вчера, сегодня уже могут потерять актуальность — из-за новой оптимизации, изменения количества worker-потоков VPP или состояния железа. Поэтому все числа, приведённые ниже, носят скорее ознакомительный характер и с высокой долей вероятности могут не совпадать с тем, что вы увидите на момент чтения этой главы. Но общее представление они дают, и это главное.

Compute-хост

Замеры проводились на реальной боевой ноде с процессором Intel Xeon Gold 6448H: два NUMA-узла, по 32 физических ядра на каждый плюс Hyper-Threading. Мы ничего не приукрашивали — использовали стандартные инструменты: iperf3 и netperf в режиме TCP_STREAM, а для тонких экспериментов привлекали сам VPP и dpdk-testpmd. В качестве внешнего референса взяли открытый отчёт DPDK.

Первый эксперимент — самый честный. Один worker VPP, привязанный к конкретному ядру, и от одной до четырёх пар виртуальных машин. Каждая VM сидит на своём ядре, все интерфейсы VirtualEthernet направлены к единственному worker-у. Никакой магии, просто «в лоб».

Пик — 36,4 Гбит/с на трёх парах VM. Четвёртая пара уже даёт насыщение: скорость чуть падает, потери растут. Вывод: один worker-поток VPP спокойно «кормит» три-четыре мощные виртуальные машины суммарным трафиком под 40 гигабит. Этого с запасом хватает для подавляющего большинства клиентских сценариев.

Чтобы было на что опираться, мы сравнили результаты с чистым L2-форвардингом на dpdk-testpmd. На мелких посылках, 64 байта, наблюдается полный паритет — 15,2 миллиона пакетов в секунду в обоих случаях. На крупных, 1500 байт, VPP ожидаемо отстаёт: 32,6 Гбит/с против 52,8 Гбит/с у testpmd. Ничего удивительного — testpmd просто перекладывает пакеты из порта в порт, а VPP вдобавок маршрутизирует, заглядывает в VRF и обслуживает vhost-user. Он не является узким местом, он просто делает гораздо больше полезной работы.

BBR вместо Cubic: приятный бонус

Гоняя тесты в пределах одного хоста, где физических потерь нет по определению, мы заметили странные всплески ретрансмитов. Оказалось, дело в алгоритме управления перегрузкой. По умолчанию на виртуальных машинах стоял Cubic. Мы переключились на BBR — и картина резко изменилась.

VPP + BBR даёт те же 36,4 Гбит/с, но ретрансмитов становится в восемь раз меньше, чем у Cubic. Testpmd с BBR и вовсе обнуляет потери. Мораль простая: включайте BBR на всех виртуальных машинах, которые активно работают с сетью. Это бесплатно и очень эффективно.

NUMA и изоляция ядер: когда физика важнее софта

Наши compute-хосты — это два NUMA-узла. Если клиентская и серверная виртуальные машины оказываются на разных узлах, по нашим замерам мы платим штраф около 10% пропускной способности. Именно поэтому мы и стараемся сводить NUMA penalty к нулю всеми доступными средствами — о чём, собственно, и говорили в предыдущей главе.

Но самое драматичное влияние на производительность оказывает изоляция процессорных ядер. Мы сравнили работу четырёх worker-ов VPP на одном хосте в двух конфигурациях. Без isolcpus, когда ядра остаются доступны операционной системе для любых фоновых задач, результат составил около 62 Гбит/с. С isolcpus, когда все ядра, кроме нулевого, полностью вычищены от посторонней нагрузки, — 88 Гбит/с. При этом дисперсия результатов падает в разы. Вывод однозначный: isolcpus — не администраторская прихоть, а суровая необходимость для максимальной производительности Data Plane.

Border-хост: встреча с большим интернетом

Теперь переходим к самому, пожалуй, интересному — border-хостам. На них нет виртуальных машин, только VPP с DPDK, который гоняет пакеты между внешними физическими интерфейсами и облачным Underlay. Мы прогнали через генератор TRex два типа нагрузки: мелкие 64-байтовые пакеты, чтобы проверить пиковую производительность в пакетах в секунду, и крупные 1472-байтовые, чтобы выжать максимум битрейта. Тестировали в двух режимах: single port, где трафик идёт с одного физического порта на другой, и both ports в полном дуплексе.

Для 64-байтовых пакетов в режиме single port картина такая:

До 12 миллионов пакетов в секунду потери держатся в пределах сотых долей процента. На 14 Mpps начинается заметная просадка.

Режим both ports, полный дуплекс:

На 7 Mpps на порт, что даёт суммарно 14 миллионов пакетов в секунду и 12,32 Гбит/с, потери пока ещё микроскопические — тысячные доли процента. На 8 Mpps происходит резкий рост до 4,4%. Вывод: Border-хост на мелких посылках уверенно держит 12–14 миллионов пакетов в секунду на порт без значимых потерь.

Для крупных пакетов в 1472 байта в режиме single port:

91 гигабит в секунду с потерями в одну десятитысячную процента. Дальше упираемся в физические ограничения порта и шины, но и без того видно, что Border-хост способен переварить под сотню гигабит на одном порту.

Наконец, полный дуплекс для крупных пакетов:

При 6 Mpps на порт, или суммарно около 146 Гбит/с полнодуплексного трафика, потери остаются ниже тысячной доли процента. На 7 Mpps наступает обвал. Но даже 146 Гбит/с с микроскопическими потерями — это очень солидный запас для любых реальных нагрузок, с которыми сталкивается пограничный узел облака.

Что-то кончается, что-то начинается

Простой вопрос о том, как работает «простая и элегантная» базовая связность виртуальных машин в облаке MWS Cloud Platform, незаметно перерос в обзорную экскурсию по ключевым составляющим. Мы разобрались с видами хостов, заглянули в их внутреннее устройство, коснулись обработки сетевого трафика и постарались проследить путь маленького сетевого пакетика от глобального интернета до конкретной виртуальной машины. Затронули и производительность — скажем честно: скорее, «потрогали пальцем ноги температуру воды», но и этого оказалось достаточно, чтобы составить представление о масштабах.

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

Эта статья носит прежде всего ознакомительный характер: многие темы остались без должного внимания, поскольку каждая заслуживает отдельного разговора. Тем не менее первая часть работы подошла к концу. Да, всё верно: это именно первая, теоретическая часть. Если она вызовет у читателей положительную реакцию, мы обязательно подготовим вторую, где на практике развернём упрощённую модель Overlay MWS Cloud Platform и покажем всё своими руками.

Приходите в сообщество MWS Cloud Platform, чтобы поделиться обратной связью об облаке или задать вопрос — в чате на вопросы пользователей отвечает команда разработки платформы.