Темы



Обратный ход экспоненты: как мы сокращаем использование оборудования

Коротко сгенерировано ИИ по тексту статьи
  • В 2022 году разделение общей схемы данных снизило нагрузку на магистральную сеть на 35–40%.
  • В 2024 году переход с LZ4 на zstd сократил объём сжатого трафика почти на 40%.
  • В 2026 году новая репликация уменьшила межрегиональный трафик на 36 ГБ/с, а двойное семплирование сократило хранение 11,6 млн событий с 79 тыс. до 18 тыс. строк.

Почему это важно: В совокупности улучшения позволили отложить расширение аппаратной инфраструктуры на два с половиной года.

Более 20% интернета работает через сеть Cloudflare, а наша команда — команда данных — отвечает за конвейер данных, который доставляет эти данные (и многое другое) из нашей глобальной сети в соответствующие центральные центры обработки данных. Сеть Cloudflare — это глобально распределённая система, включающая десятки тысяч серверов. Данные, которые обеспечивают работу Cloudflare Logs, SQL API, наблюдаемости, внутренней аналитики и других сервисов, проходят через эту сеть и используют наш конвейер данных для обслуживания клиентов.

В мае этого года мы обеспечивали доставку примерно двух миллиардов событий в секунду. Сюда входят как клиентский трафик, так и данные, отправляемые внутренними командами. Из года в год мы решаем одну и ту же задачу — экспоненциальный рост трафика при линейном росте числа аппаратных ресурсов. Чтобы удерживать расходы на ресурсы под контролем, нам приходится реагировать на этот рост. За последние пять лет мы внесли ряд улучшений, компенсирующих увеличение объёма данных относительно выделенных аппаратных ресурсов: в совокупности они позволили отложить расширение аппаратной инфраструктуры на два с половиной года. В этой статье рассказывается об этих изменениях: разделении монолитной схемы данных в 2022 году, настройке сжатия в 2024 году, перестройке репликации конвейера весной 2026 года, децентрализации семплирования летом 2026 года и внедрении агрегирования в конвейер осенью 2026 года.

Предыстория

Наш конвейер начинается с внутреннего сервиса Logfwdr, который собирает данные из сильно распределённых источников (например, Workers, FL). Затем мы передаём эти данные набору централизованных приёмников, которые в конечном итоге отправляют их в нашу систему буферизации Buftee. Потребители получают данные из Buftee и доставляют их в конечные пункты назначения, например в ClickHouse, на который мы во многом полагаемся.

Упрощённая схема нашей архитектуры: Logfwdr получает события от производителей и перенаправляет их централизованным приёмникам. Затем приёмники помещают события в очередь системы буферизации, откуда их забирают нижестоящие потребители.

Разбираем монолит

В 2022 году мы отказались от единственной общей схемы данных. Раньше был один поток, в котором находились поля всех продуктов, поэтому внутренним потребителям Cloudflare приходилось получать всё подряд, а затем разделять записи по типам или отбрасывать их с помощью фильтров. Тогда большинство продуктов Cloudflare для работы с данными опирались на метаданные HTTP, безопасности и CDN. В 2021 году наша схема сообщений выглядела так:

Некоторые поля относились к одному продукту, но другие не имели друг к другу никакого отношения. Мы предположили, что ни одной из этих команд не нужны все 100% полей монолитной схемы. Иными словами, можно создать отдельные небольшие сообщения, содержащие только нужные каждому продукту поля. Хотя некоторые поля пришлось бы дублировать в каждом сообщении, замена этого широковещательного потока схемами для отдельных продуктов фактически сократила нагрузку на магистральную сеть на 35–40%, что компенсировало примерно годовой рост сжатого трафика.

3rdimage

На графике виден резкий спад пропускной способности в сжатых байтах в секунду: объём сжатых данных упал после перехода с большой монолитной схемы.

Сжатие

К 2024 году трафик продолжал стабильно расти, и нам ежедневно приходилось бороться с перегрузкой сети. В ответ мы заменили алгоритм сжатия LZ4 на zstd. Мы уже экспериментировали со сжатием zstd, но тогда заметили, что оно сильнее нагружает процессор. Поэтому мы тщательно отслеживали показатели, чтобы убедиться, что компромисс оправдан.

Сначала мы развернули это изменение на нескольких серверах. К нашему облегчению, заметной разницы в загрузке процессоров не обнаружилось.

4th image.png

Версия 2024.6.2 предшествовала переходу на сжатие zstd, а версия 2024.7.1 включала это изменение.

Убедившись в результатах, мы постепенно развернули изменение на всём парке серверов — и там оно также почти не повлияло на загрузку процессоров. В итоге пропускная способность по сжатому трафику снизилась почти на 40%. Объём несжатых данных продолжил расти прежними темпами, то есть теперь мы могли поддерживать более чем в 1,5 раза больший трафик через канал прежней пропускной способности. Иначе говоря, с учётом сокращения, эквивалентного росту, мы отодвинулись примерно на 10 месяцев назад.

5th image.png

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

В 2026 году мы опробовали три стратегии сокращения объёма несжатых данных (а значит, и сжатых).

Балансировка нагрузки

Чтобы аналитика оставалась доступной при региональных авариях, наши системы должны хранить резервные копии данных в нескольких центральных регионах (данные, подпадающие под действие границ локализации метаданных клиентов, хранятся строго в назначенном регионе). Исторически самым простым способом обеспечить устойчивость к авариям была двойная запись: Logfwdr передавал по полной копии каждого аналитического события, не привязанного к региону, в каждый из двух центральных регионов. Затем каждый регион независимо обрабатывал свою полную копию вплоть до ClickHouse. Кроме того, в каждом регионе мы применяем семплирование — чрезвычайно масштабируемый метод, подходящий для любых объёмов данных и условий трафика. Мы уменьшаем выборку для высокообъёмного трафика, сохраняя редкие события.

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

Ранее мы уже решали похожую задачу для Logpush. В случае Logpush Logfwdr рассматривает центральные центры обработки данных как единый общий пул приёмников: каждое сообщение отправляется только в один регион, а при недоступности машины или площадки перенаправляется в другое место. Эта модель уже доказала свою эффективность во время крупных инцидентов: трафик беспрепятственно переключался из одного местоположения в другое без участия людей. Автоматическое переключение стало возможным благодаря тому, что доставка Logpush не зависит от состояния системы: клиентам не важно, какой центральный центр обработки данных отправляет им журналы.

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

1. Общий пул приёма данных: Мы применили модель Logpush к аналитическим потокам. Logfwdr отправляет каждое событие ровно один раз через каналы связи между регионами — тому централизованному приёмнику, который доступен.

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

3. Устойчивость к сбоям: Если центральный регион выходит из строя, Logfwdr немедленно направляет весь трафик, не привязанный к региону, в сохранивший работоспособность регион. Если связь между центрами обработки данных прерывается, каждый кластер продолжает принимать свою локальную долю данных без обратного давления; после восстановления магистральной сети удалённые вставщики наверстывают отставание, используя буфер хранения Buftee.

6thimage.png

Раньше Logfwdr отправлял каждое событие, не привязанное к региону, в центры обработки данных обоих регионов. Теперь он отправляет событие один раз. После Buftee удалённый вставщик создаёт вторую копию для ClickHouse.

Для перенесённых наборов данных переключение сократило сжатый трафик между регионами примерно на 43 ГБ/с, добавив к конвейеру лишь около 7 ГБ/с репликации между центрами обработки данных. Эту разницу объясняют два архитектурных фактора:

1. Репликация выполняется после семплирования: в старой модели Logfwdr передавал по каналам связи между регионами две копии необработанных событий, не прошедших семплирование. В новой модели Logfwdr отправляет централизованным приёмникам одну копию, после чего они сразу применяют семплирование перед буферизацией в Buftee. Таким образом, передаётся только уже сокращённый поток.

2. Более эффективное сжатие благодаря равномерному разбиению на части: на источнике данные распределены по тысячам отдельных серверов. После централизации потоки объединяются и разбиваются на равномерные пакеты с более широкими временными интервалами. Благодаря такой структурной однородности алгоритмы сжатия достигают намного более высоких коэффициентов, чем это было возможно для пакетов, передаваемых Logfwdr.

В целом это позволило сократить трафик в сетях между регионами на 36 ГБ/с. Сначала мы внедрили изменение для двух наборов данных: аналитики HTTP и Ready-Analytics — нашего собственного аналитического продукта с запуском в один клик.

overall-net-reduction-1stimage.png

Сначала мы переключили данные HTTP-аналитики: объём трафика сократился примерно на 20 ГБ/с (более чем на 50%).

first cutover-logfwdr-2nd image.png

В наборах данных вроде Ready-Analytics объём трафика сразу упал на 43% — примерно с 28 до 16 ГБ/с.

С весны мы активно переносим на эту архитектуру с балансировкой нагрузки и другие наборы данных.

Семплирование с самого начала

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

Решение заключалось в том, чтобы применять семплирование непосредственно в Logfwdr, сохранив его и на централизованных приёмниках. Кратко алгоритм работает так: у каждого набора данных есть ключ, который команды-производители выбрали для индексации и семплирования данных. При семплировании мы сначала перемешиваем записи с одинаковым ключом, чтобы исключить смещение. Затем для каждой группы записей выбираем выборку размером, равным квадратному корню из общего количества записей. В результате получается репрезентативная выборка — независимо от того, применялось семплирование один или два раза. Для получения оценок мы корректируем расчёты с учётом доли выборки. Например, если мы отбираем 10 записей из 100, доля выборки составляет 10/100, а несмещённая оценка исходного количества равна 10 × 10 = 100.

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

image8.png

Синим показаны данные, прошедшие семплирование один раз, и исходные данные; красным — данные, прошедшие двойное семплирование. Оценка остаётся той же, даже когда количество строк в базе данных сокращается.

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

Если рассмотреть это подробнее с помощью степенных зависимостей, мы увидим, что объём данных после двойного семплирования (красная линия) растёт примерно как x0.319, тогда как после однократного семплирования или без него (синяя линия) — как x0.485. Иными словами, если в одном ключе в 100 раз больше данных, чем в другом, при однократном семплировании в базе хранилось бы примерно в 10 раз больше строк. Теперь будет храниться лишь примерно в 4 раза больше строк. Например, 11,6 миллиона событий представлены в ClickHouse 18 тысячами строк вместо 79 тысяч. Двойное семплирование сокращает объём хранения для ключей, которые встречаются чаще всего, сохраняя при этом столько же подробностей о каждом событии для ключей, которые встречаются реже всего.

image20.png

На графике показана степенная зависимость, отражающая выравнивание соотношения между расчётным объёмом и количеством хранимых строк. Обратите внимание: зависимость x^0.25 не наблюдалась, поскольку двойное семплирование выполняется отдельно на разных машинах и пакетах, тогда как централизованные приёмники семплируют оставшиеся данные после объединения некоторых пакетов.

Сначала мы внедрили эту стратегию для трёх крупнейших наборов данных. В каждом случае объём сжатых данных, изначально отправлявшихся по сети централизованным приёмникам, сократился как минимум вдвое. В сумме это 25 ГБ/с, или более 2 ПБ в сутки.

image19.png

Во всех наборах данных, для которых мы применили двойное семплирование, объём сжатых данных в секунду резко сократился.

Агрегирование

Cloudflare предлагает несколько аналитических наборов данных, основанных на сводках: агрегатах исходных событий, вычисляемых в момент приёма данных. Это противоположный компромисс по сравнению с семплированием: вместо приблизительного ответа на любой вопрос мы точно отвечаем на фиксированный набор вопросов, если заранее выбрали измерения и метрики.

Например, в наборе данных HTTP мы измеряем количество уникальных появлений IP-адресов за определённую минуту, а не сами IP-адреса. Другой пример — подсчёт общего количества запросов GET, POST, PUT и так далее к определённому домену за эту минуту с группировкой по методу HTTP. Ни для одного из этих вычислений не требуется ждать, пока данные дойдут до самого конца конвейера.

Раньше агрегирование выполнялось ближе к концу конвейера — во вставщиках, которые считывают данные из Buftee и записывают их в ClickHouse. Децентрализация этого этапа позволила распределить нагрузку и сократить объём данных, проходящих через центральные узлы.

Поэтому мы создали функцию агрегирования, применяемую на каждом этапе конвейера: по мере поступления данных появляется несколько возможностей объединить совпадающие частичные агрегаты. Как и при семплировании, записи группируются по ключу, который определяет, какие из них можно объединить. Агрегирование выполняется на каждом экземпляре Logfwdr. Затем мы агрегируем данные повторно после того, как частично обработанные события поступают на централизованные приёмники, которые отправляют их в выделенные буферы с секционированием. Поскольку эти буферы объединяют записи из нескольких приёмников, после считывания данных пакетами вставщиками ClickHouse агрегирование проводится ещё раз. Наконец, агрегирование выполняется в ClickHouse с помощью агрегирующих табличных движков.

image15.png

На схеме показан пример прохождения событий через конвейер и их агрегирования на каждом этапе.

Первым набором данных, для которого мы внедрили эту функцию, стал HTTP-трафик. Только в этом наборе данных объём сжатого трафика сократился с более чем 9 ГБ/с до менее чем 2 ГБ/с. Хотя сейчас это набор данных с наибольшим числом уникальных значений, агрегирование всё равно позволило сократить сетевой трафик примерно на 80%.

image4.png

Объём сжатых данных в секунду с течением времени для сводного набора данных HTTP. Оранжевым показана скорость при агрегировании только после поступления данных к вставщикам; зелёным — после переноса агрегирования на более ранний этап конвейера.

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

Результаты

Нагляднее всего экспоненциальный рост проявляется в том, как быстро увеличение трафика съедает запас пропускной способности.

Возьмём Ready-Analytics: для этого продукта применили два из трёх методов — балансировку нагрузки и семплирование. В середине мая балансировка нагрузки сократила трафик на 50% — примерно с 26 до 13 ГБ/с. Два месяца спустя трафик уже снова вырос примерно до 20 ГБ/с. Органический рост трафика свёл на нет около половины достигнутого сокращения. Затем мы создали ещё больший запас, снизив пропускную способность этого набора данных до однозначных значений — примерно 8 ГБ/с — после внедрения семплирования.

image9.png

Общая скорость передачи Ready-Analytics после обоих переключений. Зелёным показан фактический трафик; жёлтые «призрачные» кривые показывают, каким был бы трафик без балансировки нагрузки (май) и семплирования (июль).

Без обоих этих изменений трафик Ready-Analytics уже к сентябрю превысил бы 60 ГБ/с. Обрабатывая меньше данных в центральных центрах обработки данных, мы также существенно экономим процессорные ресурсы и память. На следующих графиках показано, как балансировка нагрузки и семплирование в Logfwdr повлияли на использование процессоров и памяти только приёмниками Ready-Analytics: снижение примерно на 50%, высвободившее около 750 процессорных ядер и 3,5 ТиБ памяти.

image22.png
image11.png

В сумме по всему конвейеру с весны до осени балансировка нагрузки (экономия около 38 ГБ/с), семплирование (экономия около 25 ГБ/с на крупнейших наборах данных) и агрегирование (пока более 7 ГБ/с) позволили убрать из магистральной сети около 70 ГБ/с сжатого трафика. Эти резкие спады сразу снимают нагрузку.

image16.png

Благодаря этим мерам пропускная способность сейчас примерно на восемь месяцев отстаёт от ранее прогнозировавшейся траектории роста.

Если посмотреть на перспективу пяти лет, изменения, внесённые только за этот год, окажутся столь же значимыми, как и краткосрочные результаты. Через пять лет объём обрабатываемых нами данных будет вдвое меньше, чем был бы без этих изменений. Структурные и алгоритмические оптимизации, которые мы уже внедрили и продолжим внедрять, необходимы для того, чтобы потребность в аппаратных ресурсах оставалась на устойчивом уровне.

image12.png

Долгосрочный эффект проделанной в этом году работы: прогнозируемый объём данных в 2031 году сократился вдвое.

Если вы хотите помочь нам решать эти задачи в масштабах всей системы, мы набираем сотрудников!

© Cloudflare Blog