Привет, Хабр! Меня зовут Денис Пашков, я – ведущий архитектор данных в группе компаний GlowByte. В этой публикации я бы хотел поделиться опытом работы с MPP-решением StarRocks, набирающим популярность на российском рынке. Все, кто интересуется данной темой, уже, наверное, не сомневаются, что StarRocks очень хорошо себя показывает в аналитической нагрузке. Мои коллеги из Data Sapience регулярно делятся результатами нагрузочных испытаний платформы данных Data Ocean Nova (ознакомиться можно: 1, 2 и 3). Сегодня же речь пойдет о неочевидном сценарии использования – OLTP-нагрузке.

Сразу оговорюсь, что под OLTP тут будет пониматься не классическая транзакционная нагрузка в десятки тысяч TPS, характерная для операционных систем, а субсекундный отклик на чтение и, что важно, на запись по ключу в условиях смешанной аналитической работы. Ведь именно это и декларирует StarRocks:
Deliver sub-second latency at scale with an engine purpose-built for modern CPUs and complex SQL.
Предыстория
У одного из наших клиентов эксплуатируется система на базе СУБД Oracle. Характер нагрузки предполагает OLAP от ELT-процессов, транзакционную нагрузку от аналитических приложений и вдобавок доступ к подготовленным данным (отчетам).
Все то, за что мы так любим Oracle, – один калибр на все случаи жизни! Но, к сожалению, у текущего решения есть две большие проблемы:
-
Система немасштабируемая;
-
Необходимо провести импортозамещение.
Очевидным, казалось бы, решением является гетерогенная система. Например, связка Greenplum + Postgres + опционально ClickHouse, которая обычно предлагается на российском рынке.
Вариант рабочий, но есть очевидные минусы:
|
Минусы |
Влияние |
|
Дублирование данных по разным СУБД |
Повышение стоимости владения, дополнительные решения по синхронизации ключей, дублирование логики и т. д. |
|
Синхронизация данных между СУБД |
Снижение SLA за счет доставки (задержка данных) и тиражирования данных, увеличение накладных расходов |
|
Различные диалекты SQL |
Повышение требований к команде, адаптация приложений для работы с каждой СУБД |
|
Усложнение архитектуры |
Несколько команд администрирования, три вида оборудования и, как следствие, очень высокая стоимость владения |
Нам с заказчиком хотелось оставаться в парадигме одной универсальной платформы, но с возможностями масштабирования. Так и начиналась история проверки StarRocks для такой боевой и нетривиальной задачи.
Критерии успеха были следующие:
-
Конкурентная обработка десятков Read/Write SQL-запросов OLAP-профиля;
-
Конкурентная обработка сотен Read/Write SQL-запросов OLTP-профиля с откликом менее 1 с;
-
Конкурентная обработка запросов смешанного профиля нагрузки (OLAP+OLTP) c откликом менее 1 с.
Конкурентная обработка в данном случае – одновременные операции чтения, записи, обновления, удаления над одними и теми же таблицами ETL-ем, приложениями, и BI (т.е. OLTP/OLAP-профиль нагрузки).
Условия проведения тестирования
1) Сборка Data Ocean Nova StaRter Pack c Nova StarRocks 3.5.9 в архитектуре shared-nothing;
2) Модель данных из 25 таблиц, максимально повторяющих DDL Oracle:
-
Primary Key таблицы (PK такой же, как в Oracle);
-
Фактор репликации 3;
-
Колоночный формат хранения;
-
Сжатие zstd(3);
3) Данные анонимизированы, максимально приближены к промышленным. Соответствуют:
-
кардинальности;
-
распределению по партициям;
-
ссылочной целостности оригинальной модели Oracle.
4) SQL-запросы:
-
Несколько десятков реальных запросов OLTP/OLAP-профилей, адаптированных под синтаксис StarRocks и параметризованных случайными значениями;
-
Результирующий набор сопоставим по кардинальности с оригинальной моделью;
5) Сценарии тестирования:
-
OLTP-профиль нагрузки: одновременные read/write только OLTP-запросами;
-
Смешанный профиль: одновременные read/write всеми типами запросов (OLTP+OLAP);
6) Выключен полностью кэш и в БД, и на уровне операционной системы;
7) Запрещены оптимизации под конкретный запрос (использование matview, материализаций, различных заранее выполненных сортировок и так далее);
8) Конфигурация кластера, DDL, SQL настраивается единожды и не меняется в ходе тестирования;
9) Сценарии запускаются из JMeter и автоматически протоколируются;
10) Результаты повторно проверяются дважды: клиентом и независимым аудитором.
Характеристики кластера
Инфраструктура – Яндекс.Облако, виртуализация – K8S.
|
Среда тестирования |
|||||
|
Хост |
CPU |
RAM |
Диски |
Сеть |
|
|
1xFE (front end) |
16 |
32 GB |
2 × SSD 838 ГБ |
10 Гбит/с |
|
|
4xBE (backend) |
40 |
200 GB |
4 × SSD 3576 ГБ |
10 Гбит/с |
|
Важно заметить, что конфигурация по дисковой подсистеме (в первую очередь, количество) далека от оптимальной для MPP-платформ, да и в целом облачное окружение с сетью 10 Гбит/с всегда загоняет в определенные рамки. Однако, забегая немного вперед, могу сказать, что результаты все же впечатляют.
Описание сценариев в JMeter
-
Поднимается заданное число сессий, каждая из которых выбирает случайным образом один из запросов нужного типа (OLTP/OLAP, чтение/запись);
-
Каждому запросу присваивается один или несколько случайных параметров (идентификатор, дата и другие), которые обеспечивают работу с произвольным блоком таблицы;
-
Запрос выполняется;
-
Цикл повторяется в течение 120 минут.
Результаты нагрузочных тестов
1. Классический OLTP-профиль
Для начала было интересно узнать, какой максимальный QPS (query per second) у запросов, относящихся к сценарию «классический операционный OLTP». Другими словами, запросы с доступом по ключу вида:
select * from TABLE where id=<pk>insert into TABLE values(...)update TABLE set atr=<> where id =<pk>delete from TABLE where id=<pk>
Отдельно – чтение, и отдельно – запись 100 сессий:
|
Конкуренция |
Запись/Чтение |
Среднее время выполнения одного запроса, c |
QPS |
|
100 сессий |
Чтение |
0,025 |
3 036 |
|
100 сессий |
Запись |
0,332 |
573 |
Одновременное чтение и запись в одну таблицу 100 сессий:
|
Конкуренция |
Запись/Чтение |
Среднее время выполнения одного запроса, c |
QPS |
|
100 сессий |
Чтение 50 сессий |
0,152 |
302 |
|
Запись 50 сессий |
0,587 |
85 |
Напомню, «100 сессий» на практике означают, что в StarRocks открыто 100 соединений, которые запускают произвольные запросы по шаблону с произвольными параметрами, «поднимая» новые запросы на исполнение вновь и вновь по мере завершения предыдущих непрерывно в течение 120 минут. Все это происходит при отключенном кэшировании.
-
Максимальная нагрузка приходится на координатор FE(FrontEnd-узел), который упирается в доступные ему 16 vCPU;
-
Нагрузка на BE-узлы незначительная по всем ресурсам (CPU,RAM, I/O).
В данном эксперименте мы уперлись в текущую конфигурацию координатора.
Важный момент: координатор в StarRocks масштабируется горизонтально. Поэтому при желании этот bottleneck обходится штатными средствами.
Дополнительно отмечу подготовленные выражения (prepared statements).
Скрытый текст
Prepared Statement — это предварительно скомпилированный SQL-запрос, который хранится на сервере и может выполняться многократно с разными параметрами.
При выполнении подготовленного выражения пропускаются стадии парсинга SQL-запроса и подготовки CBO плана запроса, за счет чего производительность на 30% выше, чем у этого же запроса, но с различными параметрами.
В StarRocks Prepared Statements реализованы через MySQL Binary Protocol. Это позволяет разделить жизненный цикл запроса на три этапа:
-
Prepare
Клиент отправляет шаблон SQL-запроса (например, SELECT * FROM users WHERE id = ?). Frontend (FE) парсит запрос, выполняет базовую валидацию и сохраняет структуру во внутреннем кэше; -
Execute
Клиент отправляет только значения параметров. FE подставляет их в готовый план и отправляет на выполнение; -
Close (Deallocate)
Удаление подготовленного выражения из памяти FE.
Server-side vs. Client-side
Важно различать эти подходы. Многие драйверы (особенно JDBC) по умолчанию эмулируют prepared statements на стороне клиента (просто подставляя строки). Для получения реального профита в StarRocks необходимо включить Server-side Prepared Statements (например, в JDBC через useServerPrepStmts=true).
Преимущества Prepared Statements
Использование подготовленных выражений снижает нагрузку на FE за счет:
-
Пропуска этапа парсинга и планирования
Для простых запросов (Point Lookups) эти этапы могут занимать до 30–50% общего времени обработки; -
Binary Protocol
Передача данных в бинарном формате эффективнее, чем парсинг текста, особенно для больших наборов параметров или специфических типов данных (Date, Decimal).
Подготовленные выражения – хороший метод защиты от SQL-инъекций, так как параметры передаются отдельно от логики запроса и никогда не интерпретируются как часть SQL-кода.
В последних версиях StarRocks, начиная с 3, внедрена специальная оптимизация для Prepared Statements, нацеленная на Point Select (выборку по ключу).
Когда запрос соответствует условиям (простая выборка по Primary Key из таблицы с Primary Key моделью), StarRocks задействует «короткий путь»:
-
Запрос минует стандартный тяжелый оптимизатор;
-
FE напрямую связывается с нужным Backend-узлом (BE), где находятся данные;
Это позволяет достигать производительности в десятки тысяч QPS на одну ноду, приближая StarRocks к возможностям KV-хранилищ.
Хотя чаще всего используются API-драйверы, на уровне SQL это выглядит так:
PREPARE select_orders FROM 'SELECT order_id, customer_id, amount, status FROM orders WHERE customer_id = ? AND order_date >= ? AND status = ?';-- 2. Установить параметрыSET @customer_id = 12345;SET @order_date = '2024-01-01';SET @status = 'completed';-- 3. ВыполнитьEXECUTE select_orders USING @customer_id, @order_date, @status;
При внедрении стоит учитывать следующие нюансы:
-
Наибольший профит заметен на Primary Key таблицах. На Duplicate- или Aggregate-моделях выигрыш будет только в экономии CPU на парсинге;
-
В отличие от классических OLTP (PostgreSQL/Oracle), StarRocks кэширует план только в рамках сессии. Если соединение разорвано, PREPARE нужно выполнять заново;
-
Для сложных аналитических запросов с множеством соединений и агрегаций экономия 1–2 мс на парсинге будет незаметна на фоне секунд выполнения самого запроса.
В тестируемой версии StarRocks поддерживались подготовленные выражения только для select-запросов.
2. OLTP-профиль, реальный кейс
Ключевое отличие от предыдущего сценария в том, что, помимо запросов классического операционного OLTP по ключу, он дополнительно включает запросы, «похожие» на OLTP, – высокоселективные OLAP-запросы.
Например, такие:
select * from TABLEwhere region_id = 6and object_id = 12345and timestamp('2025-06-30') between date_from and date_to
Ни один из атрибутов не является первичным ключом, при этом запрос возвращает одну строку. В промышленной системе Oracle этот запрос работает десятки/сотни миллисекунд, и то за счет составного индекса.
Подводим итоги после 2 часов непрерывной работы.
Результаты:
|
Число конкурентных сессий |
Запись/Чтение |
Среднее время выполнения одного запроса, c |
QPS |
|
25 сессий |
Чтение (70%) Запись (30%) |
0,039 |
556 |
|
50 сессий |
0,049 |
903 |
|
|
75 сессий |
0,064 |
1 060 |
|
|
100 сессий |
0,083 |
1 129 |
Детализация по типу DML:
|
Конкуренция |
Запись/Чтение |
Среднее время выполнения одного запроса, c |
Ср. время 95% лучших, с |
QPS |
|
100 сессий |
Чтение |
0,061 |
0,037 |
1 085 |
|
Обновление |
0,636 |
0,290 |
6 |
|
|
Вставка |
0,592 |
0,250 |
33 |
|
|
Удаление |
0,789 |
0,420 |
5 |
В данном сценарии картина нагрузки на кластер изменилась: координатор (FE) загружен примерно на ⅓, а вот BE утилизирует 100% CPU.
Т.е. вопрос ресурсов BE – BE масштабируется.
Комментарий: OLAP-запросы, «похожие» на OLTP (не по ключу), не используют PK индекс и работают дольше, за счет чего запрос дольше задерживается на CPU и снижается общая пропускная способность.
Насколько отличается производительность запросов по ключу от OLAP-запросов, «похожих» на OLTP (не по ключу)?
В таблице ниже представлено среднее время выполнения запросов из того же теста для 2 типов запросов: select по ключу, select не по ключу к одной и той же таблице.
|
Пример |
Тип запроса |
Среднее время выполнения 1 запроса, миллисекунды |
|
Таблица 1 |
Чтение по ключу |
30,15 |
|
Не по ключу |
84,16 |
|
|
Таблица 2 |
Чтение по ключу |
29,81 |
|
Не по ключу |
138,26 |
|
|
Таблица 3 |
Чтение по ключу |
30,57 |
|
Не по ключу |
96,77 |
Как вы можете видеть, время работы драматически (конечно, нет) падает. Много ли вы знаете систем, способных на поиск по полю, не входящему в ключ, не отсортированному предварительно, с таким временем отклика?
Такую производительность обеспечивают ZoneMap-индексы. В StarRocks ZoneMap-индексы двухуровневые и очень эффективные. Они позволяют кардинально снизить объемы сканирования настолько, что миллисекундный отклик сохраняется даже в таких сценариях.
Справочно: Индекс ZoneMap хранит статистику для каждого блока данных (chunk), которая включает информацию о Min (минимальном значении), Max (максимальном значении), HasNull (наличии значений null) и HasNotNull (наличии ненулевых значений). При выполнении запросов StarRocks может быстро определить, какие блоки читать априори не требуется
Скрытый текст
Индекс ZoneMap хранит статистику для каждого блока данных (chunk), которая включает информацию о Min (минимальном значении), Max (максимальном значении), HasNull (наличии значений null) и HasNotNull (наличии ненулевых значений). При выполнении запросов StarRocks может быстро определить, можно ли исключить блоки данных на основе их статистики, что сокращает объем сканируемых данных и повышает скорость выполнения запроса. Каждый блок данных может представлять собой сегмент или страницу данных столбца. Соответственно, существует два типа индексов ZoneMap: один хранит статистику для каждого сегмента, а другой — для каждой страницы столбца. Разработчики изначально повторили лучшие практики, известные нам более 10 лет, реализованные в файловом формате parquet. И точно так же, как и в parquet, индекс ZoneMap создается автоматически при операции записи в таблицу. Никакого создания, ручного обслуживания, как у BRIN (Block Range Index) в Greenplum, не требуется, а эффективность на порядок выше!
3. Смешанный профиль
В данном сценарии проверяется, как поведут себя различные группы запросов в условиях смешанной нагрузки, максимально приближенной к реальной. Для этого мы запускаем одновременно 3 группы запросов: ETL, OLAP, OLTP. Сохранится ли время отклика?
Суть теста не меняется: всеми типами запросов одновременно пишем в одни и те же таблицы и читаем их. Разбавляем тест ETL-запросами, которые предполагают массивные операции записи/обновления целевых таблиц с аналитическими Join-операциями в выборке:
insert into TARGETselect ……… from T1join T2join T3
Для смешанной конкурентной нагрузки хорошая практика проектирования – применение настроек ресурсных групп.
Применяемые настройки ресурсных групп:
OLAP+ETL
ALTER RESOURCE GROUP olap_etl WITH ( 'concurrency_limit' = '24', 'cpu_weight' = '40', 'mem_limit' = '0.9', 'spill_mem_limit_threshold' = '0.9');
OLTP
ALTER RESOURCE GROUP oltp WITH ( 'cpu_weight' = '10', 'exclusive_cpu_cores' = '0', 'mem_limit' = '0.1');
|
Число конкурентных сессий |
Тип SQL-запроса |
Ср. время 1 запроса, c |
QPS |
|
100 сессий |
OLTP |
0,122 |
150,92 |
|
OLAP |
39,520 |
1,26 |
|
|
ETL |
43,800 |
0,68 |
|
|
TOTAL |
0,643 |
152,87 |
Конфигурацию ресурсных групп можно изменять динамически:
ALTER RESOURCE GROUP olap_etl WITH ( 'concurrency_limit' = '24', 'cpu_weight' = '20', -- <--- уменьшили с 40 до 20 'mem_limit' = '0.9', 'spill_mem_limit_threshold' = '0.9');
Уменьшили cpu_weight у группы olap_etl за счет чего ресурс CPU распределился в пропорции 1/3 (oltp) и 2/3 (olap+etl).
Результаты:
|
Число конкурентных сессий |
Тип SQL-запроса |
Среднее время выполнения 1 запроса, c |
QPS |
|
100 сессий |
OLTP |
0,070 |
291,56 |
|
OLAP |
44,120 |
0,91 |
|
|
ETL |
47,520 |
0,69 |
|
|
TOTAL |
0,320 |
293,17 |
Утилизация ресурсов на BE-узлах: за счет применения ресурсных групп «касаемся» планки по CPU.
Время работы всех типов запросов оценивается как стабильное и предсказуемое.
Нагрузкой можно управлять в динамике с помощью ресурсных групп, например, применять ту или иную конфигурацию в зависимости от профиля нагрузки в разные временные окна. Субсекундный отклик для OLTP сохраняется, объем выделенного ресурса OLTP-группе влияет на QPS.
4. Влияние Compaction
Не может же быть все идеально!
Во время длительной непрерывной работы StarRocks в нашем нагрузочном тесте возникают разовые периодические всплески времени работы одних и тех же OLTP-запросов, иногда до нескольких секунд, когда обычное время <100 мс.
На OLAP-нагрузке такое поведение незаметно.
|
Compaction |
QPS |
OLTP |
OLAP, c |
|||
|
Чтение, с |
Модиф-и, с |
P95, с |
Max, с |
|||
|
Выкл. |
152 |
0,093 |
0,414 |
0,055 |
9,110 |
39,520 |
|
Раз в 5 минут |
219 |
0,061 |
0,342 |
0,049 |
5,440 |
47,050 |
|
Раз в 15 минут |
201 |
0,069 |
0,364 |
0,053 |
7,990 |
40,810 |
|
Default (1 минута) |
86 |
0,140 |
4,538 |
0,098 |
20,220 |
55,100 |
Всплески обусловлены процессом Compaction (обслуживания формата хранения StarRocks), который блокирует на чтение/запись метаданные tablet на время своей работы. Пока процесс обслуживания не завершится, запрос заблокирован!
Производительность процесса обслуживания зависит от производительности дисковой подсистемы и аллокации ресурсов, выделяемых для Compaction.
Выключать Compaction на спорадически меняющихся данных плохо для производительности, поскольку копится большое число версий, что влияет на отклик запросов. Слишком частый Compaction – тоже плохо, ведет к частым блокировкам.
Обращайте внимание на default-настройки. Они совершенно не подходят для промышленной эксплуатации.
Для промышленной среды необходимо выбирать оптимальную стратегию обслуживания с учетом имеющегося оборудования и ресурсов выделенных на операцию обслуживания.
Вывод
-
Производительность OLTP-запросов – более 1000 запросов/с. Время отклика – <100 мс в среднем;
-
StarRocks справляется со смешанным профилем нагрузки, при этом обеспечивая выполнение OLTP менее чем за 1 с (122 мс в среднем);
-
В целевой промышленной конфигурации производительность ожидается кратно лучше.
Давайте резюмируем все наши эксперименты в виде заключения.
Технические аспекты
-
StarRocks – решение, которое способно обрабатывать смешанную нагрузку с «короткими запросами» на чтение и изменение, с OLAP-запросами, характерными для ETL-трансформаций и аналитических задач;
-
Для интенсивной OLTP-нагрузки с минимальным временем отклика требуется использовать тип таблиц Primary Key;
-
Узким горлышком при высокой конкуренции запросов может быть координатор FE. В промышленном использовании в сайзинг необходимо закладывать несколько FE не только для отказоустойчивости, но и для балансировки нагрузки;
-
Подготовленные выражения (prepared statements) увеличивают производительность OLTP-запросов на 30% за счет «soft parse» однотипных запросов. Помните, что «мягкий парсинг» работает только в пределах одной сессии (в тестируемой версии StarRocks подготовленные выражения поддерживаются только для select);
-
Необходимо обеспечить своевременный Compaction версий под планируемую OLTP-нагрузку. Своевременность определяется оптимальным балансом допустимого перцентиля отклонения от целевого SLA и выделенных процессу обслуживания ресурсов;
-
В смешанных сценариях нагрузки необходимо обязательно применять настройки ресурсных групп;
-
Кластер StarRocks может быть динамически сконфигурирован под требуемую производительность с учетом нагрузки и объемов данных: параметры кластера, управляющие вычислительными ресурсами и конкуренцией, а также ресурсными группами, не требуют перезагрузки кластера (graceful shutdown). Необходимы реализация сценария или использование полноценной платформы, такой как Data Ocean, с уже готовой функцией динамического масштабирования.
Методологические аспекты миграции
Обычное желание заказчика сложной аналитической системы – мигрировать на новые технологические рельсы с минимальными изменениями в логике приложений и сервисов. Заказчик всегда хочет сохранить экспертизу и устоявшиеся подходы в разработке, снизить риски принятия системы в эксплуатацию, переиспользовать интеграции с существующим функционалом автотестов и системой контроля качества данных и так далее.
Вот тут и наступает главный вызов! StarRocks показал себя отлично в нашем тестировании на конкретных практических сценариях работы, но для покрытия всех кейсов «хотим, как в Oracle» все еще есть, над чем работать.
Команда Data Sapience, развивающая платформу данных Data Ocean Nova, разработала недостающий StarRocks-функционал, который включает:
-
Поддержку процедурного кода, максимально близкого к нотации Oracle PL/SQL;
-
Материализацию на локальный диск compute-дедупликации вычислений CTE;
-
Создание механизма сбора и сохранения расширенной информации о завершившихся запросах Nova StarRocks в единую систему логирования и аудита для работы с историей запросов и визуализации графических планов для AI-агентов;
-
Специализированные коннекторы быстрого прямого импорта и экспорта данных для расширения федеративных возможностей Nova StarRocks.
С учетом этих изменений у нас выработалась следующая формула успешной миграции:
-
Миграция модели данных как есть с учетом трансформации типов, но без потери качества;
-
Предварительное приведение на стороне Oracle процедурного кода, связанного с обработкой курсоров (в аналитической системе это не совсем удачный паттерн разработки, и, к счастью, таких изменений придется сделать очень мало);
-
Исключение логики обработки, основанной на триггерах (временное быстрое решение прижилось в паре мест);
-
И только потом – выполнение миграции процедурного кода PL/SQL Oracle в LPSQL Nova StarRocks с минимальными изменениями в процедурной логике.
Команда разработки Data Sapience уже проводит исследования эффективности нового функционала StarRocks, разработанного ими для поддержки нескольких покрывающих btree-индексов с включением в PK дополнительных полей и подготовленных выражений для insert-, update-, delete-операций.
ссылка на оригинал статьи https://habr.com/ru/articles/1029814/