Более 20% веб-трафика проходит через сеть Cloudflare, и наша команда (Data team) отвечает за конвейер данных, который перекачивает эту информацию (и не только) из нашей глобальной сети в соответствующие центральные дата-центры. Сеть Cloudflare — это глобально распределенная система, поддерживающая десятки тысяч серверов. Данные, обеспечивающие работу Cloudflare Logs, SQL API, систем наблюдаемости, внутренней аналитики и многого другого, проходят через эту сеть и используют наш конвейер данных для обслуживания клиентов.
В мае этого года мы обеспечивали доставку данных со скоростью примерно два миллиарда событий в секунду. Сюда входит как трафик клиентов, так и данные, отправляемые внутренними командами. Из года в год мы сталкиваемся с одной и той же проблемой: экспоненциальный рост трафика при линейном росте аппаратных мощностей. Мы вынуждены реагировать на этот рост, чтобы держать расходы на ресурсы под контролем. За последние пять лет мы внедрили различные улучшения, чтобы компенсировать увеличение объема данных по сравнению с выделенным оборудованием, что эквивалентно отсрочке расширения парка оборудования на два с половиной года. В этой статье подробно описаны данные изменения: разделение монолитной схемы данных в 2022 году, настройка сжатия в 2024 году, перепроектирование репликации конвейера весной 2026 года, децентрализация сэмплирования летом 2026 года и внедрение агрегации в конвейер осенью 2026 года.
Предыстория
Наш конвейер начинается с внутренней службы под названием Logfwdr, где мы собираем данные из высокораспределенных источников (например, Workers, FL). Затем мы передаем эти данные на набор централизованных приемников, которые в конечном итоге отправляют их в нашу систему буферизации Buftee. Потребители забирают данные из Buftee и распределяют их по конечным пунктам назначения, таким как ClickHouse, на который мы сильно полагаемся.
Разбор монолита
В 2022 году мы демонтировали нашу единственную схему. Раньше существовал единый поток, содержащий поля всех продуктов, что заставляло внутренних потребителей Cloudflare принимать всё подряд и выполнять демультиплексирование или отбрасывать записи с помощью фильтров. В то время большинство продуктов Cloudflare, работающих с данными, строились на метаданных HTTP, Security и CDN. В 2021 году наша схема сообщений выглядела так:
Некоторые поля здесь относились к одному продукту, но некоторые были совершенно не связаны друг с другом. Гипотеза заключалась в том, что ни одной из этих команд не требуются 100% полей из монолитной схемы. Другими словами, мы можем создавать небольшие сообщения для полей, необходимых каждому продукту. Хотя нам пришлось дублировать некоторые поля в каждом сообщении, замена этого «пожарного шланга» на специфичные для продуктов схемы фактически снизила использование пропускной способности магистрали на 35-40%, что позволило «отыграть» примерно год роста сжатого трафика.
Сжатие
К 2024 году, по мере стабильного роста трафика, мы ежедневно сталкивались с проблемами перегрузки сети. Чтобы отреагировать на это, мы сменили алгоритм сжатия с LZ4 на zstd. Мы уже экспериментировали со сжатием zstd раньше, но тогда заметили более высокое потребление ресурсов процессора. Поэтому мы тщательно отслеживали метрики, чтобы убедиться, что этот компромисс оправдан.
Изначально мы развернули это изменение на нескольких серверах. К нашему облегчению, мы не заметили заметной разницы в нагрузке на CPU.
С большей уверенностью мы постепенно развернули обновление на весь наш парк серверов, что также практически не повлияло на процессоры. В итоге мы получили почти 40% снижение пропускной способности сжатого трафика. Объем несжатых байтов продолжал расти прежними темпами, а это означало, что мы могли поддерживать более чем в 1,5 раза больше трафика при том же размере канала. Или, говоря иначе, расчетное сокращение эквивалента роста отбросило нас примерно на 10 месяцев назад.
Теперь, в 2026 году, мы опробовали три стратегии по сокращению объема несжатых байтов (а следовательно, и сжатых).
Балансировка нагрузки
Чтобы сделать аналитику устойчивой к региональным сбоям, наши системы требуют хранения избыточных данных в нескольких централизованных регионах (данные, подпадающие под действие Customer Metadata Boundaries, хранятся строго в пределах назначенного региона). Исторически самым простым способом обеспечения устойчивости к сбоям была двойная запись: Logfwdr передавал две полные копии каждого нерегионального аналитического события — по одной в каждый централизованный регион. Затем каждый регион независимо обрабатывал полную копию для записи в ClickHouse. Мы также применяем sampling в каждом регионе — невероятно масштабируемую технику, которая работает при любых объемах данных и любых условиях трафика. Мы выполняем даунсэмплинг высокообъемного трафика, в то время как редкие события сохраняются.
Эта инфраструктура была управляемой, когда лишь несколько потоков использовали вторичные регионы. Однако по мере того, как мы расширяли устойчивость к сбоям на почти все аналитические потоки, трафик Logfwdr удвоился по всем направлениям. Отправка каждого события дважды через глобальную сеть стала неустойчивой при нашем экспоненциальном росте трафика.
Мы уже решали похожую задачу для Logpush. Для Logpush сервис Logfwdr рассматривает централизованные дата-центры как единый общий пул приемников: каждое сообщение отправляется только в один регион, с переключением на другой пункт назначения, если машина или объект недоступны. Эта модель уже доказала свою эффективность во время крупных инцидентов, позволяя плавно переключать трафик из одного места в другое без вмешательства человека. Это автоматическое переключение стало возможным, поскольку доставка Logpush не имеет состояния (stateless), так как клиентам не важно, какой именно централизованный дата-центр отправляет логи.
С аналитикой всё было сложнее. В отличие от логов без состояния, кластеры ClickHouse в обоих регионах по-прежнему нуждаются в полной копии нерегиональных данных, чтобы обеспечить мгновенное и независимое переключение при сбоях запросов. Прорыв заключался в отделении транзита конвейера от избыточности базы данных:
1. Общий пул приема: Мы адаптировали модель Logpush для аналитических потоков. Logfwdr отправляет каждое событие ровно один раз через глобальную сеть на любой доступный централизованный приемник.
2. Отложенная репликация из централизованных регионов: Вместо репликации трафика у источника репликация происходит как можно позже в конвейере. Данные попадают в наш распределенный уровень буферизации Buftee, а удаленные инсертеры передают копии между дата-центрами дальше по цепочке.
3. Устойчивая обработка сбоев: Если централизованный регион выходит из строя, Logfwdr немедленно направляет весь нерегиональный трафик в оставшийся регион. Если соединение между дата-центрами прерывается, каждый кластер продолжает принимать свою локальную долю без обратного давления (backpressure); удаленные инсертеры догоняют очередь из буфера хранения Buftee, как только магистраль восстанавливается.
Для мигрированных наборов данных этот переход позволил исключить примерно 43 ГБ/с сжатого транзитного трафика, добавив лишь около 7 ГБ/с репликации между дата-центрами в нашем конвейере. Два архитектурных фактора объясняют эту асимметрию:
1. Репликация происходит после сэмплирования: В старой модели Logfwdr передавал две копии необработанных, несэмплированных событий через глобальную сеть. В новой модели Logfwdr отправляет одну копию на централизованные приемники, которые немедленно применяют сэмплирование перед буферизацией в Buftee, передавая дальше только этот уже сжатый поток.
2. Улучшенное сжатие за счет равномерного секционирования: данные в источнике фрагментированы по тысячам отдельных серверов. После централизации потоки агрегируются и разбиваются на равномерные пакеты в течение более широких временных интервалов. Такая структурная однородность позволяет алгоритмам сжатия достигать значительно более высоких коэффициентов сжатия, чем это когда-либо было возможно для транзитных пакетов Logfwdr.
В целом это привело к чистому сокращению трафика на 36 ГБ/с в глобальных сетях. Мы внедрили это решение сначала для двух наборов данных: HTTP analytics и Ready-Analytics, нашего собственного продукта для аналитики в один клик.
Начиная с весны мы активно переносим другие наборы данных на эту архитектуру с балансировкой нагрузки.
Выборка с самого начала
Еще одна стратегия, которую мы применили, заключалась в дальнейшем расширении нашего механизма выборки, чтобы перенести критически важную обработку на более ранние этапы конвейера. Выборка уже использовалась в наших централизованных сервисах, особенно в приемниках, что снижало нагрузку на последующие системы. Мы можем более эффективно использовать ресурсы, если будем отправлять меньше данных дальше по конвейеру (без ущерба для качества данных).
Решение заключалось в том, чтобы просто выполнять выборку в Logfwdr в дополнение к сохранению выборки в централизованных приемниках. Если вкратце, алгоритм выборки работает так: для каждого набора данных есть ключ, который команды разработчиков выбирают для индексации и выборки данных. При выполнении выборки мы сначала перемешиваем записи для каждого ключа, чтобы исключить предвзятость. Затем для каждой группы записей мы выбираем размер выборки, равный квадратному корню из общего количества записей. Результатом является репрезентативная выборка, независимо от того, проводилась ли она один или два раза. Чтобы получить оценки, мы масштабируем вычисления в соответствии с коэффициентом выборки. Например, если мы выбираем 10 из 100 записей, коэффициент выборки составит 10/100, а несмещенная оценка исходного количества будет равна 10*10 = 100.
Чтобы убедиться, что этот подход работает хорошо, мы сравнили количество строк, записанных в ClickHouse, с оценочной суммой общего количества, используя различные ключи для разных типов трафика, чтобы охватить весь спектр — от «наименее встречающихся» до «наиболее встречающихся» ключей.
Результат заключается в том, что для ключей с большим объемом данных коэффициент выборки уменьшается. Однако ключи с меньшим объемом данных подвергались выборке сопоставимо. Таким образом, мы сохранили репрезентативную выборку, доставляя и храня меньше событий. Мы не идем на компромисс в отношении качества доставляемых данных, даже если доставляем их в меньшем количестве.
Если рассмотреть это более внимательно с использованием степенных законов, можно заметить, что объем данных при двойной выборке (красный график) растет примерно как x, по сравнению с x для однократной выборки/контрольной группы (синий график). Другими словами, ключ, содержащий в 100 раз больше данных, чем другой, при однократной выборке занимал бы примерно в 10 раз больше строк. Теперь он будет занимать лишь примерно в 4 раза больше строк. Конкретно: 11,6 миллиона событий представлены 18 тыс. строк в ClickHouse вместо 79 тыс. Двойная выборка снижает объем хранения для «наиболее встречающихся» ключей, сохраняя при этом ту же детализацию для каждого события для «наименее встречающихся» ключей.
Изначально мы внедрили эту стратегию для трех наших основных наборов данных. В каждом из них объем сжатых данных, которые мы изначально отправляли по сети на централизованные приемники, сократился как минимум вдвое. Это 25 ГБ/с в сумме, или более 2 ПБ в день.
Агрегирование
Cloudflare предлагает несколько аналитических наборов данных, построенных на основе сверток: агрегатов необработанных событий, вычисленных во время приема. Это создает противоположный выборке компромисс: вместо того чтобы отвечать на любой вопрос приблизительно, мы отвечаем на фиксированный набор вопросов точно, при условии, что мы заранее выбираем измерения и метрики.
Например, в наборе данных HTTP мы измеряем количество уникальных вхождений IP-адресов в течение данной минуты, а не сами отдельные IP-адреса. Другой пример: мы суммируем общее количество запросов GET, POST, PUT и т. д. для данного домена за эту минуту, сгруппированных по методу HTTP. Ни одно из этих вычислений на самом деле не требует ожидания конца конвейера для начала расчетов.
Исторически эта агрегация происходила ближе к концу конвейера, внутри модулей вставки (inserters), которые считывали данные из Buftee и вставляли их в ClickHouse. Децентрализация этой агрегации дала возможность распределить нагрузку и уменьшить объем данных, которые мы централизуем.
Поэтому мы создали функционал агрегации, который используется на каждом этапе, создавая повторяющиеся возможности для объединения соответствующих частичных агрегатов по мере схождения данных. Как и в случае с выборкой, записи группируются по ключу, который определяет, какие записи можно объединить. Мы выполняем агрегацию на каждом экземпляре Logfwdr. Мы снова агрегируем данные после того, как частично агрегированные события достигают централизованных приемников, которые отправляют эти повторно агрегированные события в выделенные секционированные буферы. Поскольку эти буферы объединяют записи от нескольких приемников, мы выполняем агрегацию еще раз после того, как они считываются пакетами модулями вставки ClickHouse. Наконец, мы агрегируем данные в ClickHouse с помощью агрегирующих табличных движков.
Первым набором данных, для которого мы это внедрили, был HTTP-трафик. Только в этом одном наборе данных мы снизили объем трафика сжатых байтов с более чем 9 ГБ/с до менее чем 2 ГБ/с. Несмотря на то, что это набор данных с самой высокой кардинальностью, агрегация на нем все равно дала нам примерно 80% сокращения трафика в сети.
Эта функция агрегации эффективна для наборов данных, которые легко сворачиваются, особенно для таких случаев использования, как метрики использования, где точность сумм и подсчетов имеет первостепенное значение. Это также означает, что мы можем предложить командам разработчиков еще один вариант снижения использования ресурсов помимо выборки, что мы и сделали. По аналогии с Ready-Analytics мы создали универсальный внутренний продукт для агрегирующей аналитики в один клик под названием Ready-Aggregates. Поскольку мы продолжаем совершенствовать эту новую функцию в конвейере, мы ожидаем, что экономия будет продолжать расти.
Влияние
Самым ярким доказательством этого экспоненциального роста является то, как быстро рост трафика поглощает запас мощности.
Возьмем, к примеру, Ready-Analytics, где были применены два из трех механизмов: балансировка нагрузки и методы выборки. В середине мая балансировка нагрузки снизила трафик на 50%, с ~26 ГБ/с до ~13 ГБ/с. Два месяца спустя трафик уже начал расти обратно до ~20 ГБ/с. Это примерно половина от достигнутого сокращения, нивелированная органическим ростом трафика. Затем мы создали еще больший запас мощности, снизив скорость пропускной способности этого набора данных до однозначных чисел, ~8 ГБ/с, когда была внедрена выборка.
Без обоих вмешательств только Ready-Analytics превысил бы 60 ГБ/с к сентябрю. Обрабатывая меньше данных в централизованных центрах обработки данных, мы также экономим значительное количество ресурсов процессоров и памяти. Следующие графики показывают влияние балансировки нагрузки и выборки в Logfwdr на использование процессора и памяти только приемниками Ready-Analytics: сокращение примерно на 50%, что позволило высвободить около 750 ядер процессоров и 3,5 ТБ оперативной памяти.
В целом по всему конвейеру, с весны по осень, балансировка нагрузки (сэкономлено ~38 ГБ/с), выборка (сэкономлено ~25 ГБ/с для основных наборов данных) и агрегирование (на данный момент сэкономлено ~7+ ГБ/с) позволили исключить около 70 ГБ/с сжатого трафика из нашей магистральной сети. Эти резкие падения обеспечивают немедленное облегчение.
Если мы посмотрим на перспективу пяти лет, то изменения, внесенные только в этом году, имеют такое же большое значение, как и краткосрочные выгоды. Мы сократили вдвое объем данных, который обрабатывали бы через пять лет. Структурные и алгоритмические оптимизации, которые мы уже внедрили и будем продолжать внедрять, необходимы для поддержания устойчивых требований к аппаратному обеспечению.
Если вам интересно помочь нам в решении этих задач в масштабе, мы нанимаем сотрудников!











