Redpanda никогда не боялась заново изобретать велосипед, когда меняются условия и мы можем сделать что-то в 10 раз лучше. В прошлый раз, когда мы сделали это с API Apache Kafka®, в итоге на нем стали работать основные банковские системы в США, лаборатории искусственного интеллекта, ведущие ритейлеры, производство чипов и беспилотные автомобили. Для инженера во мне это было воплощением мечты.
Сегодня мы представляем R2: новый «движок движков» и основу, на которой отныне будет работать каждый продукт Redpanda для работы с данными.
Начиная с грядущей версии 26.3.1, Redpanda Streaming, Redpanda SQL и будущие продукты будут использовать R2 в качестве основного ядра. В результате Redpanda Streaming/Operator перестанет быть доступной по исходному коду (source available) начиная с версии 26.3.1. Мы продолжим поддерживать Redpanda Community Edition, бесплатную для использования на срок до 50 ядер для компаний любого размера.
Обсуждения в сообществе переместились в github.com/redpanda-data/community.
R2: движок движков
R2 — это новый движок, который приводит в движение нативные продукты Redpanda. Каждое конструктивное решение основано на опыте эксплуатации, который мы получили за семь лет работы Redpanda в масштабных средах с самыми требовательными нагрузками в мире: от освоения космоса и низколатентных платежей до встраиваемых сред и высокопроизводительной сквозной записи в объектное хранилище.
R2 также представляет собой новую модель программирования для нас, созданную для эпохи агентного кодирования. Генерация кода теперь обходится дешево, но создание сверхнадежного продукта по-прежнему остается сложной задачей. Многие наши пользователи доверяют Redpanda свой бизнес, поскольку мы часто являемся главной системой записи. Сбой означает потерю данных и удар по их финансовым результатам. Задача состоит в том, чтобы использовать достижения ИИ для ускорения инноваций, одновременно повышая корректность, безопасность и надежность, от которых зависит бизнес наших клиентов.
R2 опирается на четыре уровня:
- Создан с нуля с использованием полноценного детерминированного имитационного тестирования (DST), включая виртуальные часы и регулирование шага потоков при планировании сопрограмм для многоядерных систем.
- Эволюция кода на основе формальных доказательств для основных библиотек: TLA+проверки на все виды параллелизма и доказательства Lean для всей арифметики. В сочетании с DST это предотвратило попадание примерно 40 нетривиальных ошибок в основную ветку разработки.
- Явная алгебра ошибок (std::expected<T, E>), благодаря которой все вызывающие стороны либо аварийно завершают работу, либо обрабатывают 100% ошибок. Весь код компилируется с ключом -fno-exceptions, поэтому необработанное исключение не может затеряться.
- Аппаратное ускорение первого уровня для графических процессоров (CUDA и ROCm) и Apple Metal.
Самое главное — это объединяет нас на единой общей платформе после сотен лет совокупных инженерных усилий, затраченных на создание продуктов Redpanda. Это фундамент, на котором мы строим компанию.
R2 создан с нуля с использованием сопрограмм C++23. Он предоставляет нам единую асинхронную абстракцию для операций ввода-вывода, графических процессоров/ускорителей и файлов. Функционально в нем реализован один локальный цикл обработки событий разработки для Mac и Linux, что значительно улучшает опыт разработчика. Теперь все продукты используют единую кодовую базу.
Основы: DST, TLA+ и Lean
Каждое ядро задействует 1 реактор на 1 поток ОС плюс N чужеродных потоков (N = 1 по умолчанию). Каждый такт реактора состоит из четырех фаз: сбор завершенных задач в очереди рабочих классов, их выполнение с использованием алгоритма взвешенного кругового обслуживания с дефицитом (DWRR, до 64 возобновлений за такт), сброс подготовленных операций и ожидание следующего завершения.
Источник завершения может подключаться модульно. В Linux это io_uring, в macOS — kqueue. Для тестирования R2 использует источник симуляции: виртуальные часы, генератор псевдослучайных чисел с фиксированным зерном (PRNG), виртуализированный ввод-вывод и упорядочивание с фиксированным зерном, что позволяет воспроизводить ошибки на основе исходного зерна.
- Детерминированная симуляция. Ускоряет время тестирования с лет до минут.
- Спецификации TLA+ для межядерного взаимодействия, передачи сообщений, блокировок, планирования DWRR, контроллера допуска GPU, противодавления и т. д.
- Доказательства Lean для обеспечения алгоритмической полноты. Например, доказательство того, что встроенные битовые поля правильно упаковывают INT64, или что оператор Deadline ведет себя детерминировано при переполнении времени.
Некоторые из важнейших ошибок были обнаружены в новом коде, который еще не прошел закалку в рабочей среде, поскольку пространство состояний можно исследовать во время генерации кода на CI, а не на реальных производственных системах. Мы впервые сделали формальные доказательства частью каждой проверки основного кода, и совокупный эффект заключается в том, что весь перенесенный нами код в основном «просто заработал» и в нескольких случаях даже выявил скрытые ошибки в исходной реализации.
R2 использует планировщик DWRR, поэтому, когда мы внедрили управление квотами для графических процессоров и выделения памяти ускорителю, проверки TLA+ и Lean обнаружили сложнейшую тупиковую ситуацию (дедлок) в краевом случае, вызванную инверсией приоритетов во время выполнения с переподписанной емкостью, хотя сам планировщик работал корректно. Потребовались годы закалки, чтобы найти подобные ошибки внутри R1, текущего движка Redpanda Streaming, и этот фундамент изменил то, как мы разрабатываем лучшее программное обеспечение для всех будущих продуктов.
Циклы тестирования от лет до минут
Точки приостановки сопрограмм явно заданы, поэтому в источнике симуляции каждое чередование перечислимо и воспроизводимо из исходного зерна. В сочетании со спецификациями TLA+ и детерминированными часами ошибка синхронизации, на обнаружение которой в производственном трафике ушли бы годы, проявляется за минуты симулированного времени.
Небольшие компьютеры: память и потоки
Одной из самых сложных частей архитектуры «поток на ядро» для новых программистов является нехватка памяти. На первый взгляд большая машина выглядит как набор более мелких компьютеров с относительно ограниченным объемом памяти.
Наш предыдущий планировщик futures равномерно распределял память между ядрами при загрузке и предоставлял каждому срезу (shard) / логическому ядру собственный распределитель, причем каждое межядерное освобождение памяти отправлялось обратно ее владельцу. Быстрый путь обходился дешево, но он делал проблему малого компьютера буквальной. Когда в срезе заканчивается память и он не может позаимствовать ее у простаивающего соседа, это заставляет инженера создавать сложнейшие механизмы для противодавления (backpressure), высвобождения памяти, динамического перемещения рабочей нагрузки между ядрами и т. д.
С тех пор mimalloc, TCMalloc и другие универсальные распределители памяти догнали их и при гораздо меньшем совмещении проектирования стали хорошо работать в широком спектре сценариев нагрузки, включая запросы с медленной подачей, сверхнизкую задержку и медленную запись в объектное хранилище с большими аренами.
R2 сохраняет архитектуру «поток на ядро» для выполнения, но прекращает ручную нарезку памяти. Мы по-прежнему выполняем передачу сообщений от источника к назначению, чтобы обеспечить выполнение на уровне ядра, а также единую модель параллелизма и многопоточности во всей кодовой базе. Каждый исполняемый файл R2 компонуется с mimalloc: каждый поток выделяет память из собственной кучи без блокировки, блок, освобожденный на другом ядре, попадает в список свободных страниц и возвращается при следующем сборе у владельца, а освобожденные страницы возвращаются ядру после короткой задержки очистки. Мы также запускали TCMalloc в режиме для каждого процессора (per-CPU). Это хороший распределитель, но mimalloc превзошел его на наших нагрузках, поэтому мы удалили TCMalloc.
Фоновые чужеродные потоки для таких задач, как компакция или блокирующие системные вызовы, не привязаны к ядру, поэтому планировщик Linux CFS может их перемещать. Они используют более простые механизмы рекуперации и выделение памяти больше логического ядра, чтобы упростить перемещение рабочих нагрузок между процессорами и переложить эту логику на планировщик Linux CFS, снижая задержки для проблемных нагрузок, где большая часть работы переносится на одно ядро, и увеличивая общую пропускную способность системы.
Что R2 означает для Redpanda Streaming
Насколько мне известно, R1 — это первый распределенный лог с Kafka API, который динамически обрабатывал постоянно меняющуюся форму рабочей нагрузки на едином кластере без изолированного консенсуса (без ZooKeeper, без KRaft), причем каждая подтвержденная запись по умолчанию сохранялась на диск. Безопасность, задержка, пропускная способность, согласованность, доступность и сетевые расходы — все это можно настраивать на уровне топика. Вложенные контуры управления переносят «узкое место» на следующий компонент оборудования в зависимости от рабочей нагрузки. Это лучшая инженерная работа из всех, что выпускала любая команда, в которой я состоял, и скорость и масштаб у наших клиентов проверяют ее на прочность каждый день.
R1 остается на GitHub в прежнем виде. R2 переносит все эти возможности, начиная с версии 26.3.1, и с этой же версии начинают действовать новые лимиты использования редакции Redpanda Community Edition.
Что R2 означает для Redpanda SQL
Redpanda SQL (ранее Oxla) — это наша аналитическая база данных, совместимая с Postgres. Мы приобрели ее, чтобы предоставить единую абстракцию для потоков и таблиц, основанную на дуальности потоков и таблиц, которую технический директор Redpanda Тайлер Акидау (Tyler Akidau) помог формализовать в работе One SQL to Rule Them All (SIGMOD 2019). Никаких отдельных ETL-пайплайнов — только SQL для потребления, преобразования и доставки данных туда, куда это необходимо.
С 2010 года количество ядер на сокет выросло в 32 раза (с 8 до 256), в то время как пропускная способность памяти на ядро выросла всего в 2,5 раза и упала до 3,2 ГБ/с на самых плотных процессорах 2024 года. Для аналитического SQL эта пропускная способность теперь является главным фактором стоимости, и мы построили Redpanda SQL с учетом этого.
Потоки против короутин
При блокирующем проектировании поток выполняет две функции одновременно: служит единицей параллелизма ввода-вывода и единицей выполнения на ядре. Для этих функций требуются противоположные параметры. Мы пересоздали кэш файловой системы S3 для Redpanda SQL на базе среды выполнения R2 с архитектурой «один реактор на ядро», а затем перенесли весь движок запросов (бенчмарки приведены ниже).
Мы перенесли весь движок запросов на R2 и запустили его для Redpanda SQL сегодня (Oxla 1.4.0, конфигурация по умолчанию) в S3: те же данные, те же узлы EC2 m7a.8xlarge, по одному движку за раз, на бенчмарках Star Schema Benchmark и ClickBench, причем каждый результат проверялся по контрольной сумме с оригиналом.
При 64 клиентах многопоточная версия разрасталась до 20 000–23 000 потоков на узел. Порт на R2 использовал 35 потоков на узел на любом уровне — по 1 на физическое ядро. Холодные сканирования выигрывают больше всего, так как каждое ядро удерживает множество приостановленных чтений в полете по сравнению с примерно 1 на ядро ранее.
Пока не все приносит выигрыш: теплый ClickBench показывает сопоставимые результаты (1,02х без учета одного запроса с регулярным выражением GROUP BY), а портированная версия использует на 20–30% больше пиковой памяти. И то, и другое находится в приоритете для профилировщика.
R2 объединяет все наши нативные продукты: Redpanda Streaming, Redpanda SQL и предстоящие релизы. Для нас это также новая система, разработанная для эпохи агентного кодирования, и она уже предотвратила попадание примерно 40 нетривиальных ошибок в основную ветку.
.alex












