Многие технологии Cloudflare хорошо задокументированы. Например, то, как мы обрабатываем трафик между «eyeballs» (клиентами) и нашими серверами, много раз обсуждалось в этом блоге: “Краткий справочный документ по Anycast (2011)”, "Балансировка нагрузки без инструментов балансировки нагрузки (2013)", "Открытие пути MTU на практике (2015)", "Периферийный инструмент балансировки нагрузки от Cloudflare (2020)", "Как мы исправили API сокетов BSD".
Однако мы редко говорили о второй части нашей сетевой настройки — о том, как наши серверы извлекают контент из Интернета. В этом блоге мы собираемся восполнить этот пробел. Мы обсудим подробности управления IP-адресами Cloudflare, используемыми для получения данных из Интернета, эволюцию структуры нашей выходной сети, а также то, как мы оптимизировали сеть для наилучшего использования доступного пространства IP-адресов.
Наберитесь терпения. Нам нужно обсудить множество аспектов.
Но вначале давайте определимся в терминологии.
Каждый сервер Cloudflare обрабатывает множество видов сетевого трафика, но при этом можно выделить две четкие категории:
Трафик, поступающий через Интернет – входящие подключения, инициированные «eyeball» к нашим серверам. В контексте этой публикации в блоге мы будем называть их «соединениями входящего трафика».
Трафик, поступающий через Cloudflare – исходящие подключения, инициированные нашими серверами к другим хостам в Интернете. Для краткости мы будем называть их «соединениями исходящего трафика».
Та часть, которая касается исходящего трафика, хотя и редко затрагивается в данном блоге, имеет решающее значение для наших операций. Наши серверы должны инициировать исходящие соединения, чтобы выполнять свою работу! Например:
В нашем продукте CDN контент, перед тем как подвергнуться кэшированию, извлекается с исходных серверов. См. "Pingora, прокси-сервер, который подключает Cloudflare к Интернету (2022)", Argo и многоуровневое кэширование.
Для продукта Spectrum каждое входящее TCP-соединение приводит к одному исходящему соединению.
Workers часто выполняет несколько подзапросов для создания HTTP-ответа. Некоторые из них могут запрашивать серверы в Интернете.
Мы также используем продукты на основе прямых прокси, ориентированных на клиента, такие как WARP и Cloudflare Gateway. Эти прокси-серверы обрабатывают соединения «eyeball», предназначенные для Интернета. Нашим серверам необходимо устанавливать соединения с Интернетом от имени наших пользователей.
И так далее.
Anycast для входящего трафика, Unicast для исходящего трафика
Архитектура нашей сети для входящего трафика значительно отличается от архитектуры для исходящего трафика. Для входящего трафика соединения из Интернета обрабатываются исключительно нашими диапазонами IP-адресов Anycast. Anycast (адресация любому устройству) — это технология, при которой каждый из наших центров обработки данных «объявляет» и может обрабатывать одни и те же диапазоны IP-адресов. При наличии многих возможных направлений, как Интернет «понимает», куда направлять пакеты? Дело в том, что пакеты «eyeball» направляются в ближайший центр обработки данных на основе показателей BGP Интернета, и часто это также географически ближайший центр. Как правило, маршруты BGP меняются незначительно, и можно ожидать, что каждый IP-адрес «eyeball» будет маршрутизироваться в единый центр обработки данных.
Однако, хотя Anycast хорошо работает в направлении входящего трафика, он не может обрабатывать исходящий трафик. Установление исходящего соединения через IP-адрес Anycast не сработает. Рассмотрим пакет отклика. Скорее всего, он будет маршрутизирован обратно в неправильное место — в центр обработки данных, географически ближайший к отправителю, при этом не обязательно в исходный центр обработки данных!
По этой причине до недавнего времени мы устанавливали исходящие соединения простым и традиционным способом: каждому серверу присваивался собственный IP-адрес одноадресной передачи (Unicast). "Unicast IP" означает, что в мире есть только один сервер, использующий этот адрес. Возвращаемые пакеты будут отлично обрабатываться и попадут обратно точно на нужный сервер, идентифицированный по IP Unicast.
Сегментация трафика основана на IP исходящего трафика.
Первоначально соединения, исходящие от Cloudflare, были в основном HTTP-выборками, отправляемыми на серверы-источники в Интернете. По мере расширения нашей продуктовой линейки росло и разнообразие трафика. Наиболее заметным примером является наше приложение WARP. Применительно к WARP, наши серверы используют прямой прокси и обрабатывают трафик, поступающий с устройств конечных пользователей. Это делается без такой же степени участия промежуточных путей, как в нашем продукте CDN. И это создает проблему. Сторонние серверы в Интернете, такие как серверы-источники, должны быть способны различать соединения, исходящие от сервисов Cloudflare, и наших пользователей WARP. Такая сегментация трафика традиционно выполняется с использованием разных диапазонов IP для различных типов трафика (хотя недавно мы внедрили более надежные методы, такие как запросы с сервера-источника с проверкой подлинности).
Чтобы обойти проблему разграничения доверенных и недоверенных пулов трафика, мы добавили недоверенный IP-адрес WARP на каждый из наших серверов:
IP-адреса исходящего трафика с тегом страны
Стало быстро очевидно, что тегов только для доверенного и недоверенного трафика недостаточно. Для сервиса WARP нам также необходимы теги по странам. Например, пользователи WARP из Великобритании полагают, что использование веб-сайта bbc.com является общедоступным. Однако BBC ограничивает множество своих сервисов, разрешая их только жителям Великобритании.
BBC реализует это с помощью геозонирования — используя базу данных, сопоставляющую общедоступные IP-адреса со странами и разрешающую только IP-адреса Великобритании. Геозонирование широко распространено в современном Интернете. Чтобы избежать проблем с геозонированием, следует выбирать конкретные адреса исходящего трафика, с меткой соответствующей страны, в зависимости от местоположения пользователя WARP. Как и многие другие стороны в Интернете, мы помечаем наше пространство IP-адресов исходящего трафика тегами кодов стран и публикуем его в виде геоинформации (geofeed) такой как эта). Обратите внимание, что опубликованная геоинформация — это просто данные. Тот факт, что IP-адрес помечен тегом (например, тегом "Великобритания"), не означает, что IP-адрес обслуживается из Великобритании. Это просто означает, что оператор хочет, чтобы у IP-адреса была геолокационная привязка к Великобритании. Как и многие другие аспекты в Интернете, этот механизм основан на доверии.
Примите к сведению, что на данный момент у нас есть три независимых географических тега:
тег страны пользователя WARP — «eyeball», соединяющий IP;
локация центра обработки данных, к которому подключен «eyeball»;
тег страны IP-адреса исходящего трафика.
Для обеспечения лучшего обслуживания мы хотим выбирать IP-адрес исходящего трафика таким образом, чтобы его тег страны соответствовал стране из IP-адреса «eyeball». Но обработка исходящего трафика через IP-адрес с тегом конкретной страны является сложной задачей: наши центры обработки данных обслуживают пользователей со всего мира, потенциально из многих стран! Помните о том, что из-за Anycast мы не можем напрямую контролировать маршрутизацию входящего трафика. География Интернета не всегда совпадает с физической географией. Например, наш центр обработки данных в Лондоне получает трафик не только от пользователей из Великобритании, но и из Ирландии и Саудовской Аравии. В результате нашим серверам в Лондоне требуется множество адресов исходящего трафика, проходящих через WARP, связанных со многими странами:
Теперь вы понимаете, к чему это приводит? Проблемное пространство просто «взрывается»! Вместо того чтобы иметь один или два IP-адреса исходящего трафика для каждого сервера, теперь нам нужны десятки IP-адресов, а адреса IPv4 недешевы. При такой структуре нам требуется множество адресов на один сервер, а мы работаем с тысячами серверов. Такая архитектура становится очень дорогой.
Является ли Anycast проблемой?
Позвольте напомнить: при использовании Anycast для входящего трафика мы не контролируем, в какой центр обработки данных маршрутизируется пользователь. Поэтому каждый из наших центров обработки данных должен иметь возможность маршрутизации исходящего трафика с адреса с любым возможным тегом. Внутри центра обработки данных мы также не контролируем, на какой сервер маршрутизируется соединение. Потенциально существует множество тегов, множество центров обработки данных и множество серверов внутри центра обработки данных.
Возможно, проблема заключается в архитектуре входящего трафика? Возможно, лучше использовать традиционный сетевую структуру, в которой конкретный «eyeball» направляется с помощью DNS в конкретный центр обработки данных или даже на сервер?
Это один из вариантов, но мы решили отказаться от него. Мы предпочитаем использование Anycast для входящего трафика. Это дает нам множество преимуществ:
Производительность: при использовании Anycast по определению «eyeball» маршрутизируется в ближайший (по показателям BGP) центр обработки данных. Как правило, это наиболее быстрый центр обработки данных для данного пользователя.
Автоматическое переключение: если один из наших центров обработки данных станет недоступным, трафик будет мгновенно автоматически перенаправлен в следующую лучшую локацию.
Устойчивость к DDoS: во время атаки типа «отказ в обслуживании» или пика трафика нагрузка автоматически распределяется по многим центрам обработки данных, что значительно снижает последствия атаки.
Единое программное обеспечение: функциональные возможности каждого центра обработки данных и каждого сервера внутри центра обработки данных идентичны. Мы используем один и тот же программный стек на всех серверах по всему миру. Каждая машина может выполнять любое действие, для любого продукта. Это обеспечивает простоту отладки и хорошую масштабируемость.
По этим причинам мы хотели бы сохранить Anycast для входящего трафика. Мы решили справиться с проблемой числа элементов множества для адресов исходящего трафика другим способом.
Решение проблемы на миллион долларов
Из тысяч серверов, с которыми мы работаем, каждый должен иметь возможность использовать IP-адреса исходящего трафика с любым из возможных тегов. Наше решение проще всего объяснить, продемонстрировав сначала два экстремальных варианта структуры.
Каждому серверу принадлежат все необходимые IP-адреса: каждый сервер имеет все специализированные IP-адреса исходящего трафика с необходимыми тегами.
Одному серверу принадлежит необходимый IP-адрес: специализированный IP-адрес исходящего трафика со специальным тегом находится в одном месте, и другие серверы перенаправляют трафик на него.
Специализированный IP-адрес на каждом сервере
Специализированный IP-адрес на одном сервере
Specialized IP on every server | Specialized IP on one server |
---|---|
Super expensive $$$, every server needs many IP addresses. | Cheap $, only one specialized IP needed for a tag. |
Egress always local - fast | Egress almost always forwarded - slow |
Excellent reliability - every server is independent | Poor reliability - introduced chokepoints |
Сверхвысокие затраты, каждому серверу требуется множество IP-адресов.
Низкие затраты, для тега требуется только один специально назначенный IP-адрес
Всегда локальный исходящий трафик – быстро
Почти всегда перенаправляемый исходящий трафик – медленно
Specialized IP on every server | Specialized IP per data center | Specialized IP on one server |
---|---|---|
Super expensive $$$ | Reasonably priced $$ | Cheap $ |
Egress always local - fast | Egress always local - fast | Egress almost always forwarded - slow |
Excellent reliability - every server is independent | Excellent reliability - every server is independent | Poor reliability - many choke points |
Превосходная надежность – каждый сервер является независимым
Низкая надежность – появляются узкие места
Но есть и третий способ
Мы долго думали над этой проблемой. Откровенно говоря, первый крайний вариант, при котором все необходимые IP-адреса доступны локально на каждом сервере Cloudflare, не является полностью неприемлемым. Это примерно то, что мы смогли реализовать для IPv6. С IPv6 доступ к обширному необходимому пространству IP-адресов не является проблемой.
Однако для IPv4 ни один из этих вариантов не является приемлемым. Первый вариант обеспечивает быстроту и надежность исходящего трафика, но требует высоких затрат, поскольку необходимые адреса IPv4 стоят дорого. Второй вариант позволяет использовать наименьшее возможное пространство IP-адресов, поэтому он дешев, но при этом снижает производительность и надежность.
Разработанное нами решение является компромиссом между крайностями. В целом, идея состоит в том, чтобы изменить элемент назначения. Вместо того чтобы назначать один адрес /32 IPv4 для каждого сервера, мы разработали метод назначения IP-адреса /32 для каждого центра обработки данных, а затем его совместного использования между физическими серверами.
Специализированный IP-адрес на каждом сервере
Специализированный IP-адрес на центр обработки данных
Специализированный IP-адрес на одном сервере
198.51.100.1 - forward to LHR
198.51.100.2 - forward to CDG
198.51.100.3 - forward to MAN
...
Сверхвысокие затраты
Разумные затраты
Низкие затраты
Всегда локальный исходящий трафик – быстро
Всегда локальный исходящий трафик – быстро
Почти всегда перенаправляемый исходящий трафик – медленно
Превосходная надежность – каждый сервер является независимым
Превосходная надежность – каждый сервер является независимым
Низкая надежность – множество узких мест
Совместное использование IP-адреса внутри центра обработки данных
Идея совместного использования IP-адреса между серверами не нова. Традиционно это может быть достигнуто с помощью Source-NAT на маршрутизаторе. К сожалению, огромное количество IP-адресов исходящего трафика, которые нам необходимы, а также размер наших операций не позволяют нам полагаться на межсетевой экран / NAT с отслеживанием состояния на уровне маршрутизатора. Нам также не нравится состояние с открытым доступом, поэтому мы не сторонники распределенных установок NAT.
Вместо этого мы выбрали разделение IP-адресов исходящего трафика между серверами по диапазону портов. Для заданного IP-адреса исходящего трафика каждому серверу принадлежит небольшая часть доступных исходных портов — фрагмент порта.
Когда возвращаемые пакеты поступают из Интернета, мы должны маршрутизировать их обратно на соответствующий компьютер. Для этой цели мы настроили "Unimog" — наш балансировщик нагрузки на основе L4 XDP ("Unimog, балансировщик нагрузки Cloudflare (2020)"), и он работает безупречно.
Имея фрагмент порта, например, для каждого из 2048 портов, мы можем совместно использовать один IP-адрес среди 31 сервера. Однако всегда существует вероятность того, что порты закончатся. Чтобы решить эту проблему, мы напряженно работали над тем, чтобы иметь возможность эффективно использовать порты исходящего трафика повторно. См. "Как остановить нехватку портов (2022)", "Как поделиться IPv4-адресами (2022)" и наш сегмент Cloudflare.TV.
Именно так это и выглядит. Каждому серверу известно, какие IP-адреса и фрагменты портов ему принадлежат. Для маршрутизации входящего трафика Unimog проверяет порты и направляет пакеты на соответствующие машины.
Совместное использование подсети между центрами обработки данных
Однако это еще не конец истории: мы не обсудили, как можно маршрутизировать единый адрес /32 в центр обработки данных. Традиционно в общедоступном Интернете возможно маршрутизировать подсети только с детализацией IP-адресов /24 или 256. В нашем случае это привело бы к большой трате пространства IP-адресов.
Чтобы решить эту проблему и улучшить использование нашего пространства IP-адресов, мы развернули наши диапазоны исходящего трафика как... Anycast! ! После этого мы настроили Unimog и научили его пересылать пакеты через нашу магистральную сеть в соответствующий центр обработки данных. Unimog поддерживает базу данных, аналогичную этой:
При такой структуре не имеет значения, в какой центр обработки данных доставляются обратные пакеты. Unimog всегда может исправить это и перенаправить данные в необходимое место. Практически, в то время как на уровне BGP мы используем Anycast в рамках нашей структуры, семантически IP-адрес идентифицирует центр обработки данных, а IP-адрес и диапазон портов идентифицируют конкретную машину. Принцип функционирования такого решения очень похож на Unicast.
Мы называем этот технологический комплекс «мягкий Unicast», и он представляется просто невероятным. Это похоже на реализацию нами Unicast в программном обеспечении через Anycast на уровне BGP.
Действие «мягкого Unicast» можно назвать просто волшебным.
Благодаря этой настройке мы можем достичь следующих преимуществ:
Мы можем совместно использовать IP-адрес исходящего трафика /32 между множеством серверов.
Мы можем распределять одну подсеть по нескольким центрам обработки данных и легко изменять эту настройку на лету. Это позволяет нам в полной мере использовать наши диапазоны IPv4 для исходящего трафика.
Мы можем группировать похожие IP-адреса вместе. Например, все IP-адреса, помеченные тегом "Великобритания", могут образовывать единый непрерывный диапазон. Это уменьшает размер публикуемой геоинформации.
Нам легко подключать новые диапазоны IP-адресов исходящего трафика, например IP-адреса клиентов. Это полезно для некоторых наших продуктов, таких как Cloudflare Zero Trust.
Все это реализуется по разумным ценам и без ущерба для производительности и надежности:
Как правило, пользователь может маршрутизировать исходящий трафик непосредственно из ближайшего центра обработки данных, обеспечивая максимально возможную производительность.
В зависимости от фактических потребностей мы можем выделять или освобождать IP-адреса. Это дает нам гибкость в управлении затратами на IP, и нам не нужно переплачивать авансом.
Поскольку мы используем несколько IP-адресов исходящего трафика в разных локациях, надежность не ставится под угрозу.
Истинное местоположение наших IP-адресов — облако.
Хотя «мягкий Unicast» позволяет нам добиться большей эффективности, мы столкнулись с некоторыми проблемами. Иногда нам задают вопрос: «Где физически находится этот IP-адрес?». Но на этот вопрос нет однозначного ответа! Наши IP-адреса исходящего трафика не имеют физической локации где-бы то ни было. С точки зрения BGP нашими диапазонами исходящего трафика является Anycast, поэтому они находятся везде. Логически каждый адрес используется в одном центре обработки данных одновременно, но мы можем перемещать его по требованию.
Сети доставки контента вводят пользователей в заблуждение
В качестве еще одного примера проблем можно привести еще одну проблему, с которой мы столкнулись со сторонними CDN. Как мы упоминали ранее, в нашем процессе присутствуют три тега страны:
Тег страны «eyeball» IP-адреса, через который выполняется подключение.
Локация нашего центра обработки данных.
Тег страны для IP-адресов, которые мы выбрали для соединений исходящего трафика.
Тот факт, что наш адрес исходящего трафика имеет тег "Великобритания", не всегда означает, что он действительно используется в Великобритании. У нас были случаи, когда пользователь WARP с тегом Великобритании вследствие технического обслуживания нашего центра обработки данных в Лондонском аэропорту Хитроу был направлен в Париж. Популярная CDN выполнила обратный поиск нашего IP-адреса исходящего трафика, обнаружила, что он помечен как "Великобритания", и перенаправила пользователя на лондонский сервер CDN. В целом это нормально... но фактически в тот момент мы столкнулись с отправкой исходящего трафика из Парижа. В итоге для этого пользователя имела место маршрутизация пакетов из его дома в Великобритании в Париж и обратно в Великобританию. Это плохо для производительности.
Мы решаем эту проблему, выполняя DNS-запросы в центре обработки данных для исходящего трафика. Для DNS мы используем IP-адреса, имеющие метку локации центра обработки данных, а не предполагаемой геолокации пользователя. Как правило, это решает проблему, но, к сожалению, все еще есть некоторые исключения.
Будущее уже здесь
Проведенные нами в 2021-му году эксперименты с гибкостью адресации продемонстрировали, что у нас есть множество возможностей для инноваций в отношении адресации входящего трафика. «Мягкий Unicast» показывает нам, что мы можем добиться большой гибкости и плотности на стороне исходящего трафика.
С каждым новым продуктом растет количество тегов, которые нам необходимы в связи с ростом объемов исходящего трафика — с учетом факторов от степени надежности трафика, категории продукта до геолокации. Поскольку пул пригодных для использования адресов IPv4 сокращается, мы можем быть уверены, что в этом пространстве будет появляться все больше инноваций. Наше решение — «мягкий Unicast», но без всякого сомнения, это не последняя наша разработка.
На данный момент, похоже, мы отходим от традиционной одноадресной передачи. Наши IP-адреса исходящего трафика фактически больше не существуют в фиксированном месте, а некоторые из наших серверов в настоящее время даже не имеют действительного IP-адреса Unicast.