Sirin — плагин для Picodata, реализующий протокол Apache Cassandra. Мы сравнили его производительность с Cassandra 5.0.6 на timeseries-нагрузке: запись строк двух размеров, точечное и пакетное чтение. Оба стенда ограничены 6 ядрами CPU, используется конфигурация СУБД по умолчанию.
| Тест | Sirin, RPS | Cassandra, RPS | Отношение |
|---|---|---|---|
| Запись 30 байт | 190 198 | 197 165 | Cassandra ×1.04 |
| Запись 150 байт | 147 416 | 186 739 | Cassandra ×1.27 |
| Пакетное чтение (5 000 строк) | 468 | 603 | Cassandra ×1.29 |
| Точечное чтение | 166 143 | 18 750 | Sirin ×8.9 |
Введение
Sirin — плагин для распределённой СУБД Picodata, реализующий протокол Apache Cassandra. Благодаря этому плагину приложения, использующие драйверы CQL, могут работать с Picodata без изменения кода.
Целью данного документа является оценка производительности Sirin в сравнении с Cassandra 5.0.6 — эталонной реализацией протокола. Сравнение позволяет определить, насколько Sirin пригоден для замены Cassandra в типовых сценариях нагрузки, а также выявить области, требующие дальнейшей оптимизации.
Тестирование охватывает операции записи и чтения на схеме данных, характерной для timeseries workload. Измеряются пропускная способность, время выполнения запросов, потребление вычислительных ресурсов (CPU, RAM) и нагрузка на дисковую подсистему.
Условия
Стенд
Базы данных и генератор нагрузки запускались на отдельных виртуальных машинах и взаимодействовали через сеть, что исключало конкуренцию за ресурсы между тестируемой БД и инструментом нагрузки.
Конфигурация ВМ с базами данных:
| Ресурс | Значение |
|---|---|
| CPU | 8 ядер |
| RAM | 16 ГБ |
| Диск | 200 ГБ NVMe SSD |
Конфигурация баз данных
Обе системы тестировались без репликации данных. Лимит CPU в 6 ядер задавался через cgroups одинаково для обеих систем, чтобы обеспечить сравнимые условия.
| Система | Топология |
|---|---|
| Cassandra 5.0.6 | Один процесс, обслуживающий все запросы |
| Sirin 1.0.2 на Picodata 26.1.1 | Кластер из 5 узлов на одной машине |
Схема данных
Использовалась типовая схема данных для timeseries-нагрузки:
CREATE TABLE ${KEYSPACE}.${TABLE}(
partition_key text,
clustering_key timeuuid,
data blob,
PRIMARY KEY ((partition_key), clustering_key)
)
Входные данные
Исходный размер одной строки «сырых» данных, используемых в тестах:
Запись полезной нагрузки в 30 байт в 10 000 партиций:
| Поле | Тип | Размер |
|---|---|---|
partition_key |
text |
18 байт |
clustering_key |
timeuuid |
16 байт |
data |
blob |
30 байт |
| Итого | 64 байта |
Запись полезной нагрузки в 150 байт в 10 000 партиций:
| Поле | Тип | Размер |
|---|---|---|
partition_key |
text |
18 байт |
clustering_key |
timeuuid |
16 байт |
data |
blob |
150 байт |
| Итого | 184 байта |
Используемый инструмент
Тесты проводились утилитой latte.
Набор тестов
| Тест | Описание |
|---|---|
| Запись полезной нагрузки в 30 байт в 10 000 партиций | Запись одной строки (64 байта) в случайную из 10 000 партиций |
| Запись полезной нагрузки в 150 байт в 10 000 партиций | Запись одной строки (184 байта) в случайную из 10 000 партиций |
| Точечное чтение | Чтение одного объекта из 10 000 партиций |
| Пакетное чтение | Чтение 5 000 объектов из 10 000 партиций |
Объём тестовых данных
Тесты чтения проводились на данных, накопленных в ходе теста «Запись 30 байт». Тест «Запись 150 байт» генерировал собственный независимый набор данных.
| Тест | Система | Число строк | Объём сырых данных |
|---|---|---|---|
| Запись полезной нагрузки в 30 байт в 10 000 партиций | Sirin | 684 715 985 | 40.8 ГБ |
| Запись полезной нагрузки в 30 байт в 10 000 партиций | Cassandra | 709 796 028 | 42.3 ГБ |
| Запись полезной нагрузки в 150 байт в 10 000 партиций | Sirin | 530 700 061 | 90.9 ГБ |
| Запись полезной нагрузки в 150 байт в 10 000 партиций | Cassandra | 672 261 629 | 115.2 ГБ |
Объём сырых данных рассчитан как произведение числа строк на размер одной строки (64 и 184 байта соответственно).
Измеряемые параметры
| Категория | Параметры |
|---|---|
| Пропускная способность | Запросов в секунду (RPS) |
| Время выполнения запросов | Медиана, p90, p95 времени выполнения запроса |
| CPU | Суммарное потребление по всем процессам БД |
| RAM | Суммарное потребление по всем процессам БД |
| Диск | IOPS и пропускная способность (МБ/с) на чтение и запись |
| Write amplification | Множитель суммарной записи на диск относительно объёма сырых данных |
Результаты
Запись полезной нагрузки в 30 байт в 10000 партиций
Команда для запуска теста:
latte run write.rn 192.168.1.103:9042 --duration 60m -p 60 --threads 16 --connections 100
Запрос (prepared statement):
INSERT INTO latte.basic (partition_key, clustering_key, data)
VALUES (:pk, :ck, :data)
Значение partition_key выбирается равномерно из 10 000 партиций, clustering_key — timeuuid, data — blob фиксированного размера.
| Параметр | Sirin | Cassandra |
|---|---|---|
| Пропускная способность, RPS | 190 198 | 197 165 |
| Время выполнения p90, мс | 10.617 | 12.05 |
| Время выполнения p95, мс | 14.672 | 18.02 |
| Время выполнения медиана, мс | 3.432 | 2.55 |
| Потребление CPU, % | ~80 | 86 |
| Потребление RAM, ГБ | 4.0 | 5.7 |
| Макс. запись на диск, IOPS | 450 | 75 |
| Макс. чтение с диска, IOPS | 103 | 162 |
| Макс. запись на диск, МБ/с | 92.61 | 65.02 |
| Макс. чтение с диска, МБ/с | 61.13 | 26.35 |
| Write amplification | 3.75 | 4.42 |
| Записано объектов | 684 715 985 | 709 796 028 |
| Объём сырых данных, ГБ | 40.8 | 42.3 |
Телеметрия — Sirin
Пропускная способность (RPS) в течение теста — график latte
Время выполнения запроса: p50, p90, p95 (мс) — график latte
Загрузка CPU (%) по узлам кластера в течение теста
Потребление оперативной памяти (ГБ) по узлам кластера в течение теста
Дисковая активность: IOPS на запись и чтение
Дисковая активность: пропускная способность (МБ/с) на запись и чтение
Суммарный объём данных, записанных и прочитанных с диска за время теста (байт)
Утилизация сетевого канала: входящий и исходящий трафик (МБ/с)
Телеметрия — Cassandra
Пропускная способность (RPS) в течение теста — график latte
Время выполнения запроса: p50, p90, p95 (мс) — график latte
Загрузка CPU (%) в течение теста
Потребление оперативной памяти (ГБ) в течение теста
Дисковая активность: IOPS на запись и чтение
Дисковая активность: пропускная способность (МБ/с) на запись и чтение
Суммарный объём данных, записанных и прочитанных с диска за время теста (байт)
Утилизация сетевого канала: входящий и исходящий трафик (МБ/с)
Запись полезной нагрузки в 150 байт в 10 000 партиций
Команда для запуска теста:
latte run write.rn 192.168.1.103:9042 --duration 60m -p 60 --threads 16 --connections 100
Запрос (prepared statement):
INSERT INTO latte.basic (partition_key, clustering_key, data)
VALUES (:pk, :ck, :data)
Значение partition_key выбирается равномерно из 10 000 партиций, clustering_key — timeuuid, data — blob фиксированного размера.
| Параметр | Sirin | Cassandra |
|---|---|---|
| Пропускная способность, RPS | 147416 | 186739 |
| Время выполнения p90, мс | 16.07 | 12.89 |
| Время выполнения p95, мс | 22.64 | 18.55 |
| Время выполнения медиана, мс | 3.53 | 2.71 |
| Потребление CPU, % | 87 | 88 |
| Потребление RAM, ГБ | 5.1 | 6.08 |
| Макс. запись на диск, IOPS | 251 | 162.2 |
| Макс. чтение с диска, IOPS | 1230 | 395 |
| Макс. запись на диск, МБ/с | 220.5 | 149.7 |
| Макс. чтение с диска, МБ/с | 160.2 | 68.1 |
| Write amplification | 4.63 | 5.09 |
| Записано объектов | 530 700 061 | 672 261 629 |
| Объём сырых данных, ГБ | 90.9 | 115.2 |
Телеметрия — Sirin
Пропускная способность (RPS) в течение теста — график latte
Время выполнения запроса: p50, p90, p95 (мс) — график latte
Загрузка CPU (%) по узлам кластера в течение теста
Потребление оперативной памяти (ГБ) по узлам кластера в течение теста
Дисковая активность: IOPS на запись и чтение
Дисковая активность: пропускная способность (МБ/с) на запись и чтение
Суммарный объём данных, записанных и прочитанных с диска за время теста (байт)
Утилизация сетевого канала: входящий и исходящий трафик (МБ/с)
Телеметрия — Cassandra
Пропускная способность (RPS) в течение теста — график latte
Время выполнения запроса: p50, p90, p95 (мс) — график latte
Загрузка CPU (%) в течение теста
Потребление оперативной памяти (ГБ) в течение теста
Дисковая активность: IOPS на запись и чтение
Дисковая активность: пропускная способность (МБ/с) на запись и чтение
Суммарный объём данных, записанных и прочитанных с диска за время теста (байт)
Утилизация сетевого канала: входящий и исходящий трафик (МБ/с)
Пакетное чтение по 5000 объектов из 10 000 партиций
Команда для запуска теста:
latte run read_batch.rn 192.168.1.103:9042 --duration 60m -p 10 --threads 3 --connections 20
Запрос (prepared statement):
SELECT * FROM latte.basic
WHERE partition_key = :pk AND clustering_key > :ck
LIMIT 5000
Читается до 5 000 строк из случайной партиции начиная со случайного clustering_key.
| Параметр | Sirin | Cassandra |
|---|---|---|
| Пропускная способность, RPS | 494 | 603 |
| Время выполнения p90, мс | 119 | 87.6 |
| Время выполнения p95, мс | 155 | 100 |
| Время выполнения медиана, мс | 47.2 | 44.8 |
| Потребление CPU, % | 67 | 78 |
| Потребление RAM, ГБ | 2.5 | 5.85 |
| Макс. чтение с диска, KIOPS | 3.31 | 11.10 |
| Макс. чтение с диска, МБ/с | 148.11 | 279.8 |
| Read amplification | 1.07 | 1.3 |
Телеметрия — Sirin
Пропускная способность (RPS) в течение теста — график latte
Время выполнения запроса: p50, p90, p95 (мс) — график latte
Загрузка CPU (%) по узлам кластера в течение теста
Потребление оперативной памяти (ГБ) по узлам кластера в течение теста
Дисковая активность: IOPS на чтение
Дисковая активность: пропускная способность (МБ/с) на чтение
Суммарный объём данных, прочитанных с диска за время теста (байт)
Утилизация сетевого канала: входящий и исходящий трафик (МБ/с)
Телеметрия — Cassandra
Пропускная способность (RPS) в течение теста — график latte
Время выполнения запроса: p50, p90, p95 (мс) — график latte
Загрузка CPU (%) в течение теста
Потребление оперативной памяти (ГБ) в течение теста
Дисковая активность: IOPS на чтение
Дисковая активность: пропускная способность (МБ/с) на чтение
Суммарный объём данных, прочитанных с диска за время теста (байт)
Утилизация сетевого канала: входящий и исходящий трафик (МБ/с)
Точечное чтение из 10 000 партиций
Команда для запуска теста:
latte run read_single.rn 192.168.1.103:9042 --duration 60m -p 60 --threads 16 --connections 100
Запрос (prepared statement):
SELECT * FROM latte.basic
WHERE partition_key = :pk AND clustering_key = :ck
Читается ровно одна строка по точному значению partition_key и clustering_key.
| Параметр | Sirin | Cassandra |
|---|---|---|
| Пропускная способность, RPS | 166 143 | 18 750 |
| Время выполнения p90, мс | 14.13 | 59.28 |
| Время выполнения p95, мс | 20.61 | 61.51 |
| Время выполнения медиана, мс | 2.88 | 51.71 |
| Потребление CPU, % | ~93 | 89 |
| Потребление RAM, ГБ | 4.0 | 5.77 |
| Макс. чтение с диска, KIOPS | 5.7 | 71.7 |
| Макс. чтение с диска, МБ/с | 155.41 | 1 530 |
| Read amplification | 15.21 | 1 356 |
Телеметрия — Sirin
Пропускная способность (RPS) в течение теста — график latte
Время выполнения запроса: p50, p90, p95 (мс) — график latte
Загрузка CPU (%) по узлам кластера в течение теста
Потребление оперативной памяти (ГБ) по узлам кластера в течение теста
Дисковая активность: IOPS на чтение
Дисковая активность: пропускная способность (МБ/с) на чтение
Суммарный объём данных, прочитанных с диска за время теста (байт)
Утилизация сетевого канала: входящий и исходящий трафик (МБ/с)
Телеметрия — Cassandra
Пропускная способность (RPS) в течение теста — график latte
Время выполнения запроса: p50, p90, p95 (мс) — график latte
Загрузка CPU (%) в течение теста
Потребление оперативной памяти (ГБ) в течение теста
Дисковая активность: IOPS на чтение
Дисковая активность: пропускная способность (МБ/с) на чтение
Суммарный объём данных, прочитанных с диска за время теста (байт)
Утилизация сетевого канала: входящий и исходящий трафик (МБ/с)
Выводы
Архитектурный контекст
Picodata обрабатывает запросы в одном вычислительном потоке на узел (event loop), отдельно от IO-потоков движка Vinyl. При конфигурации в 5 узлов на 6 ядрах это даёт архитектурный потолок по compute-нагрузке в 5/6 ≈ 83% суммарного CPU. Cassandra, напротив, использует пул потоков и задействует все доступные ядра.
Для корректного сравнения ниже приведена нормализованная эффективность — RPS на 1% потреблённого CPU:
| Тест | Sirin, RPS/% | Cassandra, RPS/% | Отношение |
|---|---|---|---|
| Запись полезной нагрузки в 30 байт в 10 000 партиций | 2 377 | 2 293 | Sirin ×1.04 |
| Запись полезной нагрузки в 150 байт в 10 000 партиций | 1 694 | 2 122 | Cassandra ×1.25 |
| Пакетное чтение по 5000 объектов из 10 000 партиций | 7.2 | 7.7 | Cassandra ×1.07 |
| Точечное чтение из 10 000 партиций | 1 786 | 211 | Sirin ×8.5 |
Запись полезной нагрузки в 30 байт
Пропускная способность сопоставима: различие Sirin Cassandra в скорости (190 198 против 197 165 RPS), сопоставимо со снижением затрат по CPU (80% против 86%). По нормализованной эффективности Sirin незначительно превосходит Cassandra (+3.7%).
Хвостовые задержки (tail latency) у Sirin лучше (p90: 10.6 мс против 12.1 мс, p95: 14.7 мс против 18.0 мс), медиана выше (3.4 мс против 2.6 мс). Sirin потребляет меньше RAM (4.0 против 5.7 ГБ) и демонстрирует меньший write amplification (3.75 против 4.42).
Запись полезной нагрузки в 150 байт
При увеличении полезной нагрузки с 30 до 150 байт Sirin выдаёт 147 416 RPS при CPU ~87% — столько же, что у Cassandra. Cassandra при аналогичном CPU достигает 186 739 RPS.
Дисковая активность при 150-байтной нагрузке выше, чем в 30-байтном тесте: пиковое чтение с диска достигает 1 230 IOPS и 160 МБ/с против 103 IOPS и 61 МБ/с, что отражает активное слияние уровней LSM-дерева Vinyl во время теста.
Write amplification у Sirin несколько выше, чем в 30-байтном тесте (4.63 против 3.75); у Cassandra аналогичная динамика (5.09 против 4.42). Следует учитывать, что процесс компакции у Cassandra продолжается в фоне как во время теста, так и после его окончания.
Пакетное чтение
В абсолютных числах Sirin выдаёт 468 RPS против 603 у Cassandra. При нормализации по CPU разрыв сокращается до 7%: Sirin работает при 65% CPU, тогда как Cassandra — при 78%. Запас по CPU у Sirin объясняется ограничением на число одновременно обрабатываемых запросов, обусловленным однопоточной моделью Picodata.
Read amplification у Sirin ниже (1.07 против 1.3), нагрузка на диск меньше.
Точечное чтение
Наиболее показательный сценарий. Sirin опережает Cassandra в 8.9 раза по абсолютной пропускной способности (166 143 против 18 750 RPS) и в 8.5 раза по CPU-нормализованной эффективности. При этом Sirin работает на 93% CPU, превышая compute-потолок — разница покрывается IO-потоками Vinyl, которые обслуживают операции чтения параллельно.
Главная причина отрыва — разница в read amplification: 15.21 у Sirin против 1 356 у Cassandra. При точечных запросах Cassandra вынуждена читать с диска в 90 раз больше данных, что упирает её производительность в пропускную способность дисковой подсистемы.
Разница объясняется различиями в стратегии слияний LSM-дерева и коррелирует с различиями в производительности записи: стратегия Vinyl в поиске баланса скорости чтения и скорости записи, поэтому объём выполняемой работы во время записи выше. Cassandra испольует свою стратегию слияний по умолчанию (STCS).
Потребление ресурсов
Потребление RAM у Sirin стабильно во всех тестах — ~4.0–5.1 ГБ в зависимости от размера строк, тогда как у Cassandra 5.7–6.1 ГБ.
Итог
По CPU-нормализованной эффективности Sirin сопоставим с Cassandra на записи малых строк и кратно превосходит на точечном чтении. На записи 150-байтных строк Cassandra опережает Sirin по эффективности в 1.25 раза: более крупные строки усиливают конкуренцию между компакцией Vinyl и обработкой запросов. На пакетном чтении обе системы практически равны с небольшим преимуществом Cassandra