
Сегодня VK — это технологическая компания с комплексом цифровых продуктов и сервисов, объединяющая десятки миллионов пользователей с разными интересами. Среди наших сервисов — ВКонтакте, VK Видео, VK Музыка, Одноклассники, Дзен, RuStore, Почта Mail, а также игровые, образовательные и облачные платформы. Каждый продукт генерирует огромные объёмы контента: видео, статьи, приложения, почтовый трафик, стримы и многое другое.
По мере роста компании и появления новых направлений для каждого крупного продукта мы создавали собственные решения по доставке контента. В итоге внутри VK возникла россыпь частных CDN, что осложняло развитие и сопровождение инфраструктуры. В 2024 году мы решили изменить подход и сделали первые шаги к созданию единой CDN для всей VK. Это инфраструктура, которая сможет эффективно обслуживать все наши сервисы и миллионы пользователей по всей стране.
Меня зовут Андрей Старченков, я руковожу командой разработки единой CDN в VK. В этой статье расскажу, как мы подошли к проектированию единой CDN-инфраструктуры, какие технологии и архитектурные решения используем и с какими вызовами сталкиваемся на этом пути.
Что такое CDN и зачем она нужна
CDN (Content Delivery Network) — распределённая сеть серверов, которая доставляет контент пользователям с минимальными задержками, выбирая оптимальный маршрут. Представьте, что у вас есть огромный склад товаров (origin-сервер, основное место хранения контента). Но потребителям неудобно ездить в него из разных точек города. Поэтому вы начинаете открывать магазины у дома (edge-серверы).
В России контент традиционно распространяют с запада на восток, так как основные дата-центры находятся в Москве и Санкт-Петербурге. Из-за этого пользователи в удалённых регионах нередко сталкиваются с задержками, потерями, долгими загрузками.

Идеальное решение этой проблемы — разместить кеширующие серверы в каждом городе. Но это сложно, дорого и не всегда рационально. Поэтому мы выбрали другой путь. Мы строим хабы, которые называем шилдами, в крупных региональных дата-центрах, где есть магистрали основных провайдеров. А уже от них раздаём контент на edge-серверы. Так мы балансируем между затратами и скоростью.
Но гарантировать, что текущие шилды и edge-серверы смогут покрыть все регионы — сложно. Поэтому нам было важно предусмотреть механизмы на случай, когда поблизости нет ни шилда, ни edge-сервера.
Методы балансировки
Ситуации, при которых ни шилда, ни edge-сервера рядом нет, возможны. Поэтому нам было важно определить, откуда в таких случаях забирать контент рациональнее: из ближайшего города или тянуть его из origin-сервера ресурса. Для этого мы решили применить комплексный подход — и используем технологии трёх уровней, от сетевого до прикладного.
Anycast (BGP-балансировка)
Anycast — это способ, при котором один и тот же IP-адрес назначается сразу нескольким серверам в разных географических точках. Когда пользователь отправляет запрос, маршрутизаторы интернета (через протокол BGP) выбирают ближайший сервер.

Плюсы:
Простота внедрения.
Быстрая реакция на изменения маршрутов.
Минусы:
Мы не управляем маршрутизацией — её определяет BGP, а он, в свою очередь, при выборе маршрута учитывает ряд атрибутов. В итоге этот подход не всегда гарантирует минимальную задержку, так как лучший маршрут с точки зрения протокола BGP не обязательно лучший по задержке.
Нет гибкого управления нагрузкой — можно только вывести перегруженный сервер, но не перераспределить трафик.
Из-за недостатков мы используем Anycast только в качестве резервного способа балансировки.
GSLB — балансировка через DNS
GSLB (Global Server Load Balancing) — это система, которая распределяет трафик между серверами, расположенными в разных географических точках. Она работает как умный навигатор для пользователей:
Определяет их местоположение и направляет запросы к ближайшему серверу, чтобы снизить задержки.
Проверяет работоспособность серверов: если один дата-центр перегружен или недоступен, трафик автоматически переключается на другие.
Оптимизирует нагрузку, чтобы ни один сервер не был перегружен.
Под капотом GSLB обычно скрывается технология DNS. Так, DNS отправляет запрос на рекурсивный сервер провайдера, и мы видим его IP, а не IP клиента. Но если провайдер поддерживает EDNS, можно получить реальный IP клиента прямо в DNS-запросе и точнее определить его местоположение. Если EDNS не работает, происходит группировка запросов в транзакции и система анализирует повторные обращения, чтобы всё же определить, откуда запрос. DNS возвращает IP ближайшего кеш-сервера.

Как это работает:
Первый запрос приходит на DNS → определяем примерное местоположение по IP DNS-сервера → отправляем на ближайшую площадку.
Пользователь приходит на ближайший кеш-сервер → видим его реальный IP → решаем, оставить его здесь или перенаправить.
Минусы GSLB:
Провайдеры могут кешировать DNS-ответы дольше TTL, из-за чего пользователь попадает на сервер, который может быть уже неактуален.
Геолокация по IP может быть неточной.
Мы видим домен, но система не учитывает конкретное содержание запроса. Даже при равной загрузке серверов GSLB не может направить запрос к узлу, где нужный контент уже закеширован.
ALLB — балансировка на уровне приложений
ALLB (Application Layer) — это наша внутренняя формулировка. Суть подхода в том, что мы интегрируем CDN API с бэкендом ресурса, прячущегося за CDN. Благодаря этому, если пользователь авторизован, система знает его User ID, запрос (Content ID) и IP-адрес.

Это позволяет направлять пользователя к тому серверу, где нужный контент уже закеширован, или инициировать его загрузку на ближайший edge-сервер.
Плюсы:
Максимально точное распределение нагрузки.
Кешируется только популярный контент.
Можно строить динамическую карту контента благодаря анализу конкретных запросов и их содержимого на уровне приложений. Появляется возможность заранее определить, какой контент становится более популярным, и проактивно загружать его на нужные серверы.
Минусы:
Сложная интеграция с бэкендом ресурсов, которая может стоить дорого.
Высокие требования к отказоустойчивости API.
Проблемы с инерцией, если пользователь перемещается. Например, начал смотреть контент дома и там же получил ссылки, а продолжил уже в метро, то есть в другой локации.
Резюмируем:
Anycast мы используем только для маршрутизации запросов до DNS-серверов.
Опираемся преимущественно на GSLB-балансировку.
Реже используем ALLB.
Методы определения оптимального сервера
Для выбора оптимального сервера нам важно определить приблизительное расположение пользователя относительно наших дата-центров и оценить качество сетевых маршрутов. Это позволяет обеспечить максимально быструю и стабильную работу сервиса. Как это можно сделать:
GeoIP — это технология, которая определяет географическое местоположение устройства (страну, город, регион) по его IP-адресу. Работает быстро, но может ошибаться, особенно в случае CGNAT, VPN или прокси. В единой CDN мы не используем его из-за низкой точности.
Prefix-Based подход — метод, при котором решения принимаются на основе подсети, в которой находится пользователь (префикса). Этот подход предпочтителен для нас, поскольку на каждой площадке с кеш-серверами мы размещаем Route Collectors на базе Bird. Они собирают BGP-анонсы от провайдеров, один или несколько, и формируют карту маршрутов. А мы уже накладываем на неё метрики качества (задержка, потеря пакетов).
Казалось бы, мы собрали всё это — и видим карту нахождения пользователя: можно сопоставить IP-адрес с префиксом и отправить контент. Но путей много, и мы должны выбрать оптимальный подход.
Метрики отслеживания качества
BGP-метрики показывают, что у нас может быть несколько одноранговых площадок с одинаковыми показателями, и выбор может пасть на любую из них. Поэтому мы смотрим ещё и на Prefix Quality Metrics. Их мы делим на два типа:
серверные (Server Side);
клиентские (Client Side).

Серверных метрик не всегда достаточно, так как они не учитывают последнюю милю. Поэтому важно собирать метрики и со стороны пользователя, которые позволяют понять:
когда загрузилась картинка;
когда появился первый кадр видео;
когда реально прилетел последний байт;
сколько времени это всё заняло.
Это позволяет нам сориентироваться в выборе одноранговых площадок. Работает это следующим образом:
Мы обращаемся к активности пользователя, начинаем пеленгацию.
Активное ПО на стороне пользователя позволяет реализовать опережающий сбор клиентских метрик. Для этого мы выполняем фоновые тестовые запросы к серверным площадкам, которые потенциально подходят пользователю на основе исторических данных. Это позволяет выбрать оптимальный путь с учётом реального пользовательского опыта (client-side).
Когда пользователю понадобится контент, мы уже будем знать, на какую площадку его отправить.
Как происходит балансировка
Балансировка в нашей инфраструктуре строится вокруг принципа приоритизации локаций для каждого пользователя на основе его сетевого префикса. Для разных типов контента могут быть критичны разные метрики, поэтому подход к распределению нагрузки гибко адаптируется под сценарий.
На практике это выглядит так:
Для каждого пользователя по его IP мы определяем префикс и формируем список локаций, ранжированных по приоритету.
Запросы пользователя по умолчанию отправляются на площадку с наивысшим приоритетом.
Как только эта площадка достигает определённого порога утилизации, часть новых запросов начинает перенаправляться на следующую локацию из списка.
Такой механизм позволяет плавно распределять нагрузку и избегать перегрузок.
Anycast для таких задач мы не используем, так как он не позволяет гибко перераспределять нагрузку между площадками. Если одна локация перегружена, он может только полностью отключить её. После этого весь трафик автоматически переходит на другую площадку, но заранее неизвестно, на какую именно. Это создаёт риск лавинообразной перегрузки всех площадок по цепочке.
В отличие от этого, подходы GSLB и ALLB позволяют управлять балансировкой более тонко. Мы можем дозированно переводить часть трафика на следующий приоритет, а при снижении нагрузки — возвращать его на площадку с наивысшим приоритетом. Такой механизм обеспечивает устойчивость и предсказуемость работы CDN даже при резких изменениях трафика.
Подводные камни балансировки
Безусловно, в работе мы сталкиваемся и с определёнными трудностями. Например, какие бы инструменты и алгоритмы мы ни применяли, чтобы управлять маршрутизацией, полностью исключить инерцию пользовательских запросов не удаётся. Эта проблема характерна для обоих подходов, но причины у неё разные.
GSLB-балансировка. В случае GSLB-балансировки основная сложность связана с кеширующими DNS-серверами. Несмотря на то что мы задаём TTL, большинство провайдеров игнорирует его или устанавливает свои значения. В результате первый пользователь получает корректный адрес и попадает на нужную площадку, но затем этот DNS-ответ кешируется у оператора (зачастую на сутки). После чего последующие пользователи с этим же DNS-сервером продолжают идти по тому же маршруту, вне зависимости от изменений в инфраструктуре или загрузке площадки.
ALLB-подход. В ALLB-подходе инерция проявляется иначе: пользователь может начать просмотр контента дома, а затем, например, перейти в метро и начать смотреть другое видео из ленты. При этом ссылка на контент остаётся прежней, и запросы по-прежнему идут на площадку, актуальную для домашней сети. Но пользователь уже физически находится в другом месте, и оптимальной стала бы другая точка входа. Это решаемый кейс, но требуется дополнительная логика на стороне клиента и сервера.
Современные балансировочные механизмы позволяют многое. Но инерция пользовательских потоков и особенности работы сетевой инфраструктуры остаются вызовами, требующими комплексного подхода и постоянного совершенствования решений.
Как устроены площадки?
Кеш-серверы далеко не всегда размещаются в наших собственных дата-центрах — зачастую они находятся непосредственно у операторов связи. Такой подход диктует свои правила и в эксплуатации, и в мониторинге.
Продолжим тему локаций и вернёмся к edge-серверам и шилдам. Как правило, шилдами становятся нейтральные локации, где присутствуют несколько операторов связи, а не один. Это полноценные дата-центры, рассчитанные на десятки, сотни, тысячи серверов и обеспечивающие хорошую связность.
Чем отличаются обычные локации от нейтральных?

В обычной локации сетевое оборудование принадлежит провайдеру, а из нашего — только серверы.
Для сбора BGP-анонсов и построения карты маршрутов мы используем Bird в роли Route Collector.
В качестве DNS-серверов — gdnsd. Мы допилили gdnsd, и он прекрасно работает с prefix-based подходом.
Вместо nginx мы используем форк Angie. Мы пропатчили его и написали несколько модулей.
Также работаем с агентами, которые отвечают за деплой, конфигурирование и мониторинг ПО на площадках.

В нейтральной локации может быть много провайдеров, и мы не можем использовать их сетевое оборудование — нам требуется собственное.
Единая CDN: клиентский портал и быстрая интеграция
Мы разрабатываем единую CDN как универсальное и коробочное решение, предназначенное для всех компаний в VK. Её применение позволит эффективно координировать использование вычислительных ресурсов и оптимизировать распределение нагрузки между различными площадками и сервисами.
Что включает в себя единая CDN:
Простой способ интеграции и управления функциональностью через удобный интерфейс, а не через сложные конфигурации nginx. Даже технический специалист с минимальным опытом сможет быстро начать работать с нашей CDN.
Сокращение времени доставки контента — всего 10 минут.
Возможность отслеживать статусы — функция, которой нет у большинства CDN. Можно наблюдать, как раскатывается ресурс, и при необходимости одним кликом откатить обновления благодаря истории изменений и функции rollback.
Поддержка внешних и внутренних S3.
Robot Friendly — API поддерживает работу не только с обычными пользовательскими аккаунтами, но и с техническими учётными записями, которые используются для автоматизации процессов и работы роботов.

Внутреннее устройство системы
Теперь подробнее о том, как работает система:
Все запросы пользователей клиентского портала сначала отправляются на балансировщик. Прежде чем попасть на REST-сервисы, мы отдаём статику, затем обрабатываем динамический контент, а уже после этого обращаемся к базе данных.
Можно авторизоваться через корпоративный IDM и RADIUS.
В архитектуре есть Task Manager — компонент, который управляет всеми процессами внутри CDN: от прогрева кеша до доставки конфигураций и координации работы агентов.

Мы ориентируемся на горизонтальное масштабирование. Сейчас у нас развёрнуто около 600 агентов, расположенных в дата-центрах и на площадках провайдеров. Поскольку трафик проходит через незащищённые сети, мы используем собственный VPN-туннель и шифрованный gRPC.
В центре системы находится Agent Controller — он выступает в роли шины для gRPC-сессий с агентами, что позволяет отделить бизнес-логику. Agent Controller также взаимодействует с Task Manager через gRPC. В системе лежит база данных, где хранится вся необходимая информация.

Сам агент отвечает за управление конфигурациями nginx и gdnsd. Он может:
создавать на базе настроек клиентского портала конфиги под nginx и перезапустить его, контролируя успешность операции;
откатить всё к предыдущей конфигурации;
прогревать или очищать кеш по запросу с портала.
Поскольку балансировка нагрузки в GSLB реализуется через DNS, агент управляет конфигурациями для gdnsd, направляя пользователей на оптимальные площадки с учётом текущих условий и настроек.
Как устроена балансировка
Мы собираем:
данные с наших роут-коллекторов, которые есть на каждой площадке (используем Bird);
метрики сетевого оборудования;
метрики серверов и Prefix Quality Metrics (со стороны сервера и пользователя).
На основе этих данных формируем правила балансировки, которые содержатся в KV-хранилище. Далее мы генерируем конфигурации для gdnsd, если речь идёт о GSLB-балансировке, и с помощью слоя доставки конфигураций (Task Manager + Agent Controller + Agent) доставляем их на серверы.
Благодаря этому gdnsd всегда отвечает согласно актуальным правилам — и пользователи получают контент без задержек.
С ALLB всё проще. В момент запроса площадок для пользователя ALLB-модуль обращается к KV-хранилищу, в котором уже находятся сформированные правила балансировки, и сразу возвращает список серверов, на которые можно направить пользователя, без дополнительных обработок.
Цифровой двойник CDN: решаем проблемы до их появления
Мы часто задаёмся вопросом: «А что, если…?» Например, что произойдёт с сетью в целом, если снять нагрузку с одной площадки и отправить на следующую?
Чтобы узнать ответ на этот (и не только) вопрос, в этом году мы начали моделировать и создавать цифрового двойника нашей сети. Так мы получили эмулятор, с помощью которого можем решать несколько задач.
Тестирование новых алгоритмов балансировки. Мы можем смотреть, как распространяется нагрузка по сети в реалтайме, или как бы она распространялась, если бы мы задеплоили новый алгоритм.
Поиск узких мест до выявления проблем пользователями. Мы можем не ждать нагрузки, а генерировать её самостоятельно, нагоняя виртуально.
Более точное планирование расширения площадок и развития сети.
Будущее CDN: прогнозирование и автоматизация
Создание единой CDN в VK — стратегический шаг, направленный на преодоление фрагментации инфраструктуры и оптимизацию доставки контента для миллионов пользователей.
Это сложный инженерный процесс, где нужно учитывать географию, особенности сетей, нагрузку и поведение пользователей. Но благодаря консолидации разных методов балансировки, подходов и технологий мы смогли сократить задержки даже для удалённых регионов. А с внедрением цифрового двойника получим возможность превентивно развивать CDN с учётом реальной нагрузки.
Безусловно, текущая версия единой CDN — не окончательная, ведь мы постоянно совершенствуем систему и внедряем автоматизацию, чтобы идти в ногу с ростом нагрузки и ожиданиями пользователей.
О том, как будет продвигаться развитие нашего решения и что получится в итоге, обязательно расскажем в одной из следующих статей.