Нагрузочное тестирование YCSB: Sirin vs Apache Cassandra

Sirin — плагин для Picodata, реализующий протокол Apache Cassandra. Мы сравнили его производительность с Cassandra 5.0.6 с помощью стандартного бенчмарка YCSB на пяти профилях нагрузки: от интенсивной записи до только чтения. Оба стенда ограничены 6 ядрами CPU.

ТестSirin, rpsCassandra, rpsОтношение
Workload A (50% чтения, 50% обновлений)41 58531 888Sirin ×1.30
Workload B (95% чтения, 5% обновлений)37 61233 866Sirin ×1.11
Workload C (100% чтения)44 54040 919Sirin ×1.09
Workload D (95% чтения, 5% вставок)63 59153 396Sirin ×1.19
Workload F (50% чтения, 50% RMW)¹24 80519 930Sirin ×1.24

¹ Для workload F пропускная способность указана в tps (транзакций в секунду по YCSB): одна транзакция — это либо одиночное чтение (READ), либо полный RMW-цикл (READ + UPDATE). Прямое сравнение с rps остальных профилей некорректно.

Введение

Sirin — плагин для распределённой СУБД Picodata, реализующий протокол Apache Cassandra. Благодаря этому плагину приложения, использующие драйверы CQL, могут работать с Picodata без изменения кода.

Целью данного документа является оценка производительности Sirin 1.3.0 в сравнении с Cassandra 5.0.6 на нагрузке, генерируемой инструментом YCSB (Yahoo! Cloud Serving Benchmark). YCSB использует плоскую таблицу usertable: каждая запись содержит ключ и 10 текстовых полей по 100 байт (~1 КБ на строку), запросы обращаются к полному содержимому строки. Это позволяет оценить поведение систем на типовых OLTP-сценариях с разным соотношением операций чтения и записи.

YCSB предоставляет стандартный набор профилей нагрузки (workloads), широко используемых в индустрии для сравнительной оценки NoSQL-систем. Тестирование охватывает профили A, B, C, D и F: от смешанной нагрузки с равными долями чтения и обновления до полностью читающей нагрузки, сценария с вставкой свежих записей и нагрузки типа read-modify-write.

Измеряются пропускная способность, задержки выполнения запросов (p95, p99, min, max), потребление вычислительных ресурсов (CPU, RAM) и нагрузка на дисковую подсистему.

Условия

Стенд

Базы данных и генератор нагрузки запускались на отдельных виртуальных машинах и взаимодействовали через сеть, что исключало конкуренцию за ресурсы между тестируемой БД и инструментом нагрузки.

Конфигурация ВМ с базами данных:

РесурсЗначение
CPU8 ядер
RAM16 ГБ
Диск200 ГБ NVMe SSD

Конфигурация баз данных

Обе системы тестировались без репликации данных. Лимит CPU в 6 ядер задавался через cgroups одинаково для обеих систем, чтобы обеспечить сравнимые условия.

СистемаТопология
Cassandra 5.0.6Кластер из 3 узлов на одной машине
Sirin 1.3.0 на Picodata 26.1.4Кластер из 4 узлов на одной машине

Схема данных

YCSB использует стандартную схему с таблицей usertable. Каждая запись содержит ключ и 10 текстовых полей по 100 байт, итоговый размер строки — около 1 КБ:

CREATE TABLE usertable (
    y_id   varchar PRIMARY KEY,
    field0 varchar,
    field1 varchar,
    field2 varchar,
    field3 varchar,
    field4 varchar,
    field5 varchar,
    field6 varchar,
    field7 varchar,
    field8 varchar,
    field9 varchar
);

Инструмент нагрузки

Тесты проводились утилитой YCSB с биндингом cassandra-cql. Данные предварительно загружались командой ycsb.sh load, тесты запускались командой ycsb.sh run с параметром -p maxexecutiontime=3600 (1 час на каждый тест).

Набор тестов

YCSB задаёт профиль нагрузки через файл workload, определяющий соотношение операций и распределение ключей. Zipfian — популярные ключи запрашиваются значительно чаще (горячее пятно, характерно для OLTP). Latest — чаще запрашиваются недавно вставленные записи.

ТестОперацииРаспределение запросовЗаписей в БД
Workload A50% чтение, 50% обновлениеZipfian30 000 000
Workload B95% чтение, 5% обновлениеZipfian30 000 000
Workload C100% чтениеZipfian30 000 000
Workload D95% чтение, 5% вставкаLatest30 000 000
Workload F50% чтение, 50% read-modify-writeZipfian30 000 000

Результаты

Workload A — update heavy (50% чтения, 50% обновлений)

Профиль моделирует системы с высокой долей мутаций, например, сессионные хранилища с частой записью последних действий пользователя.

Команда для запуска теста:

./bin/ycsb.sh run cassandra-cql \
    -P workloads/workloada \
    -p hosts=10.20.1.1 \
    -p recordcount=30000000 \
    -p operationcount=999999999 \
    -p maxexecutiontime=3600 \
    -p cassandra.readconsistencylevel=ONE \
    -p cassandra.writeconsistencylevel=ONE \
    -threads 96 \
    -p cassandra.maxconnections=10 \
    -p cassandra.coreconnections=10

Запросы (prepared statements):

-- Чтение
SELECT * FROM usertable WHERE y_id = ?

-- Обновление
UPDATE usertable SET field0=?,field1=?,field2=?,field3=?,field4=?,
    field5=?,field6=?,field7=?,field8=?,field9=? WHERE y_id = ?
ПараметрSirinCassandra
Пропускная способность, rps41 58531 888
Время выполнения на чтение p95, мс2.588.04
Время выполнения на чтение p99, мс3.7633.98
Время выполнения на чтение min, мс0.270.31
Время выполнения на чтение max, мс100.35500
Время выполнения на обновление p95, мс2.425.42
Время выполнения на обновление p99, мс3.5430.77
Время выполнения на обновление min, мс0.300.22
Время выполнения на обновление max, мс100.35407
Потребление CPU, %~80~80
Потребление RAM, ГБ3.6712
Макс. запись на диск, IOPS77.6217.76
Макс. чтение с диска, IOPS1576029 300
Макс. запись на диск, МБ/с7014
Макс. чтение с диска, МБ/с200.5519.4
Телеметрия

Телеметрия — Sirin

Пропускная способность Пропускная способность по типам операций (rps) в течение теста

CPU Загрузка CPU (%) по узлам кластера в течение теста

RAM Потребление оперативной памяти (ГБ) по узлам кластера в течение теста

Дисковая активность — IOPS Дисковая активность: IOPS на чтение и запись

Дисковая активность — пропускная способность Дисковая активность: пропускная способность (МБ/с) на запись и чтение

Телеметрия — Cassandra

Пропускная способность Пропускная способность по типам операций (rps) в течение теста

CPU Загрузка CPU (%) в течение теста

RAM Потребление оперативной памяти (ГБ) в течение теста

Дисковая активность — IOPS Дисковая активность: IOPS на чтение и запись

Дисковая активность — пропускная способность Дисковая активность: пропускная способность (МБ/с) на запись и чтение

Workload B — read mostly (95% чтения, 5% обновлений)

Профиль моделирует системы с преобладанием операций чтения и редкими мутациями, например, тегирование фотографий: большинство операций — чтение тегов, добавление тега — обновление.

Команда для запуска теста:

./bin/ycsb.sh run cassandra-cql \
    -P workloads/workloadb \
    -p hosts=10.20.1.1 \
    -p recordcount=30000000 \
    -p operationcount=999999999 \
    -p maxexecutiontime=3600 \
    -p cassandra.readconsistencylevel=ONE \
    -p cassandra.writeconsistencylevel=ONE \
    -threads 64 \
    -p cassandra.maxconnections=10 \
    -p cassandra.coreconnections=10

Запросы (prepared statements):

-- Чтение
SELECT * FROM usertable WHERE y_id = ?

-- Обновление
UPDATE usertable SET field0=?,field1=?,field2=?,field3=?,field4=?,
    field5=?,field6=?,field7=?,field8=?,field9=? WHERE y_id = ?
ПараметрSirinCassandra
Пропускная способность, rps37 61233 866
Время выполнения на чтение p95, мс6.096.08
Время выполнения на чтение p99, мс8.2629.6
Время выполнения на чтение min, мс0.280.28
Время выполнения на чтение max, мс93.1276
Время выполнения на обновление p95, мс5.375.64
Время выполнения на обновление p99, мс7.4429.2
Время выполнения на обновление min, мс0.310.26
Время выполнения на обновление max, мс76.4238
Потребление CPU, %~82~80
Потребление RAM, ГБ3.812.12
Макс. запись на диск, IOPS5.486.22
Макс. чтение с диска, IOPS23 06022 050
Макс. запись на диск, МБ/с4.431.55
Макс. чтение с диска, МБ/с284.36476.16
Телеметрия

Телеметрия — Sirin

Пропускная способность Пропускная способность по типам операций (rps) в течение теста

CPU Загрузка CPU (%) по узлам кластера в течение теста

RAM Потребление оперативной памяти (ГБ) по узлам кластера в течение теста

Дисковая активность — IOPS Дисковая активность: IOPS на чтение и запись

Дисковая активность — пропускная способность Дисковая активность: пропускная способность (МБ/с) на запись и чтение

Телеметрия — Cassandra

Пропускная способность Пропускная способность по типам операций (rps) в течение теста

CPU Загрузка CPU (%) в течение теста

RAM Потребление оперативной памяти (ГБ) в течение теста

Дисковая активность — IOPS Дисковая активность: IOPS на чтение и запись

Дисковая активность — пропускная способность Дисковая активность: пропускная способность (МБ/с) на запись и чтение

Workload C — read only (100% чтения)

Профиль моделирует системы, в которых данные формируются внешним процессом (например, Hadoop-пайплайном), а сама БД обслуживает только операции чтения — например, кэш профилей пользователей.

Команда для запуска теста:

./bin/ycsb.sh run cassandra-cql \
    -P workloads/workloadc \
    -p hosts=10.20.1.1 \
    -p recordcount=30000000 \
    -p operationcount=999999999 \
    -p maxexecutiontime=3600 \
    -p cassandra.readconsistencylevel=ONE \
    -p cassandra.writeconsistencylevel=ONE \
    -threads 64 \
    -p cassandra.maxconnections=10 \
    -p cassandra.coreconnections=10

Запрос (prepared statement):

-- Чтение
SELECT * FROM usertable WHERE y_id = ?
ПараметрSirinCassandra
Пропускная способность, rps44 54040919
Время выполнения на чтение p95, мс4.314.31
Время выполнения на чтение p99, мс5.6025.02
Время выполнения на чтение min, мс0.250.26
Время выполнения на чтение max, мс118.1312.3
Потребление CPU, %~82~80
Потребление RAM, ГБ3.7511.7
Макс. запись на диск, IOPS1.587.22
Макс. чтение с диска, IOPS25 07023 970
Макс. запись на диск, МБ/с10.05
Макс. чтение с диска, МБ/с296.2516.5
Телеметрия

Телеметрия — Sirin

Пропускная способность Пропускная способность по типам операций (rps) в течение теста

CPU Загрузка CPU (%) по узлам кластера в течение теста

RAM Потребление оперативной памяти (ГБ) по узлам кластера в течение теста

Дисковая активность — IOPS Дисковая активность: IOPS на чтение

Дисковая активность — пропускная способность Дисковая активность: пропускная способность (МБ/с) на чтение

Телеметрия — Cassandra

Пропускная способность Пропускная способность по типам операций (rps) в течение теста

CPU Загрузка CPU (%) в течение теста

RAM Потребление оперативной памяти (ГБ) в течение теста

Дисковая активность — IOPS Дисковая активность: IOPS на чтение

Дисковая активность — пропускная способность Дисковая активность: пропускная способность (МБ/с) на чтение

Workload D — read latest (95% чтения, 5% вставок)

Профиль моделирует системы, где пользователи в основном читают свежие данные — например, ленту статусов: новые записи добавляются непрерывно, и они же чаще всего читаются. В отличие от workload B, запросы используют распределение latest: недавно вставленные ключи запрашиваются с большей вероятностью.

Команда для запуска теста:

./bin/ycsb.sh run cassandra-cql \
    -P workloads/workloadd \
    -p hosts=10.20.1.1 \
    -p recordcount=30000000 \
    -p operationcount=999999999 \
    -p maxexecutiontime=3600 \
    -p cassandra.readconsistencylevel=ONE \
    -p cassandra.writeconsistencylevel=ONE \
    -threads 64 \
    -p cassandra.maxconnections=10 \
    -p cassandra.coreconnections=10

Запросы (prepared statements):

-- Чтение
SELECT * FROM usertable WHERE y_id = ?

-- Вставка
INSERT INTO usertable (y_id,field0,field1,field2,field3,field4,
    field5,field6,field7,field8,field9) VALUES (?,?,?,?,?,?,?,?,?,?,?)
ПараметрSirinCassandra
Пропускная способность, rps63 59153 396
Время выполнения на чтение p95, мс3.052.92
Время выполнения на чтение p99, мс4.6414.6
Время выполнения на чтение min, мс0.240.24
Время выполнения на чтение max, мс120198
Время выполнения на вставку p95, мс3.113.11
Время выполнения на вставку p99, мс4.6916.1
Время выполнения на вставку min, мс0.330.29
Время выполнения на вставку max, мс118148
Потребление CPU, %~79~82
Потребление RAM, ГБ3.9511.97
Макс. запись на диск, IOPS8036
Макс. чтение с диска, IOPS15 48015 330
Макс. запись на диск, МБ/с7233
Макс. чтение с диска, МБ/с188306
Телеметрия

Телеметрия — Sirin

Пропускная способность Пропускная способность по типам операций (rps) в течение теста

CPU Загрузка CPU (%) по узлам кластера в течение теста

RAM Потребление оперативной памяти (ГБ) по узлам кластера в течение теста

Дисковая активность — IOPS Дисковая активность: IOPS на чтение и запись

Дисковая активность — пропускная способность Дисковая активность: пропускная способность (МБ/с) на запись и чтение

Телеметрия — Cassandra

Пропускная способность Пропускная способность по типам операций (rps) в течение теста

CPU Загрузка CPU (%) в течение теста

RAM Потребление оперативной памяти (ГБ) в течение теста

Дисковая активность — IOPS Дисковая активность: IOPS на чтение и запись

Дисковая активность — пропускная способность Дисковая активность: пропускная способность (МБ/с) на запись и чтение

Workload F — read-modify-write (50% чтения, 50% RMW)

Профиль моделирует системы, где записи читаются и тут же модифицируются пользователем или для фиксации его активности — например, пользовательские базы данных с накопительными счётчиками. В отличие от слепого обновления (workload A), операция RMW всегда предваряется чтением той же строки, что удваивает количество обращений к хранилищу на одну логическую операцию. Пропускная способность для этого профиля измеряется в tps: YCSB считает одной транзакцией либо чистый READ, либо полный RMW-цикл — вне зависимости от числа фактических запросов к БД.

Команда для запуска теста:

./bin/ycsb.sh run cassandra-cql \
    -P workloads/workloadf \
    -p hosts=10.20.1.1 \
    -p recordcount=— \
    -p operationcount=999999999 \
    -p maxexecutiontime=3600 \
    -p cassandra.readconsistencylevel=ONE \
    -p cassandra.writeconsistencylevel=ONE \
    -threads — \
    -p cassandra.maxconnections=10 \
    -p cassandra.coreconnections=10

Запросы (prepared statements):

-- Чтение (в т.ч. первый шаг RMW)
SELECT * FROM usertable WHERE y_id = ?

-- Запись (второй шаг RMW)
UPDATE usertable SET field0=?,field1=?,field2=?,field3=?,field4=?,
    field5=?,field6=?,field7=?,field8=?,field9=? WHERE y_id = ?
ПараметрSirinCassandra
Пропускная способность, tps24 80519 930
Время выполнения на чтение p95, мс7.0810.1
Время выполнения на чтение p99, мс10.1936.38
Время выполнения на чтение min, мс0.250.3
Время выполнения на чтение max, мс126.7443
Время выполнения на RMW p95, мс11.9421.34
Время выполнения на RMW p99, мс16.7741.63
Время выполнения на RMW min, мс0.650.61
Время выполнения на RMW max, мс137448
Потребление CPU, %~81~80
Потребление RAM, ГБ3.9611.9
Макс. запись на диск, IOPS63.615.5
Макс. чтение с диска, IOPS19 34027 590
Макс. запись на диск, МБ/с58.712.6
Макс. чтение с диска, МБ/с247.3446.1
Телеметрия

Телеметрия — Sirin

Пропускная способность Пропускная способность по типам операций (tps) в течение теста

CPU Загрузка CPU (%) по узлам кластера в течение теста

RAM Потребление оперативной памяти (ГБ) по узлам кластера в течение теста

Дисковая активность — IOPS Дисковая активность: IOPS на чтение и запись

Дисковая активность — пропускная способность Дисковая активность: пропускная способность (МБ/с) на запись и чтение

Телеметрия — Cassandra

Пропускная способность Пропускная способность по типам операций (tps) в течение теста

CPU Загрузка CPU (%) в течение теста

RAM Потребление оперативной памяти (ГБ) в течение теста

Дисковая активность — IOPS Дисковая активность: IOPS на чтение и запись

Дисковая активность — пропускная способность Дисковая активность: пропускная способность (МБ/с) на запись и чтение

Выводы

Архитектурный контекст

В тестах использовалось 30 миллионов записей (~30 ГБ сырых данных при ~1 КБ на строку). Этот объём не помещается как в memtable систем, так и в дисковый кеш linux. В результате чтения обоих систем частично уходят на диск. Однако использование Zipfian подразумевает горячее пятно в данных, к которому обращается большая часть запросов, и, следовательно, эти данные всегда находятся в page cache.

Workload A

Оба стенда показывают постепенное снижение пропускной способности на протяжении всего часа: по графикам RPS Sirin падает с ~52 000 до ~35 000 rps, Cassandra — с ~45 000 до ~25 000 rps. Причина видна на графиках IOPS: по мере накопления обновлений новые LSM-уровни вытесняют горячие данные из буфера, и чтение всё чаще уходит на диск. У Cassandra дисковые чтения монотонно растут с ~12 000 до 29 000 IOPS к концу теста — именно это обеспечивает более резкое падение производительности. У Sirin рост IOPS сдержаннее (~12 000–15 000), а деградация мягче: ~33% против ~44% у Cassandra.

Средний результат за час — Sirin 41 585 против 31 888 rps (+30%). По хвостовым задержкам (tail latency) Sirin значительно лучше: p99 на чтение 3.76 мс против 33.98 мс, p99 на обновление 3.54 мс против 30.77 мс. Максимальная задержка у Cassandra достигает 500 мс против 100 мс у Sirin.

Workload B

При снижении доли обновлений с 50% до 5% картина меняется. По графикам IOPS у обеих систем дисковые чтения не растут, а постепенно снижаются к концу теста (Sirin: ~23 000→17 000 IOPS, Cassandra: ~22 000→18 000 IOPS) — кэш OS постепенно прогревается на читающей нагрузке. Несмотря на это, RPS обеих систем незначительно снижается к концу теста, что указывает на CPU как на основное ограничение в данном профиле.

Преимущество Sirin сокращается до 11% (37 612 против 33 866 rps). Хвостовые задержки (tail latency) остаются значительно лучше: p99 на чтение 8.26 мс против 29.6 мс, p99 на обновление 7.44 против 29.2 мс.

Workload C

Единственный профиль, на котором обе системы выходят на стабильный режим с первых минут и удерживают его без деградации до конца теста. Отсутствие записи исключает рост LSM-уровней и давление компакции, поэтому тест демонстрирует «чистую» читающую производительность при установившемся кэше. На графике RPS у Sirin кривая практически горизонтальна на протяжении всего часа.

Sirin опережает Cassandra на 9% (44 540 против 40 919 rps). P99 на чтение: 5.60 мс против 25.02 мс.

Workload D

Обе системы работают при сопоставимой дисковой нагрузке на чтение (~15 480 и ~15 330 IOPS соответственно), однако Sirin опережает Cassandra: 63 591 против 53 396 rps (+19%) при меньшем потреблении CPU (79% против 82%). Cassandra при этом читает с диска значительно больше байт — 306 МБ/с против 188 МБ/с у Sirin — при практически одинаковом числе операций: это означает, что Cassandra читает более крупными блоками и «подтягивает» больше лишних данных за один IOPS.

На стороне записи картина обратная: Sirin активнее пишет на диск (80 против 36 write IOPS, 72 против 33 МБ/с) — следствие более частых фоновых компакций Vinyl при поступлении новых вставок. Несмотря на это, на графике RPS Sirin держит стабильный уровень ~62–65 000 с характерными кратковременными просадками от компакций, а у Cassandra RPS ровный, но на ~19% ниже.

P99 на чтение: 4.64 мс против 14.6 мс; p99 на вставку: 4.69 мс против 16.1 мс.

Workload F

Sirin опережает Cassandra на 24%: 24 805 против 19 930 tps. Это наименьший абсолютный показатель пропускной способности среди всех профилей — закономерный результат: RMW-цикл требует двух последовательных обращений к БД (SELECT, затем UPDATE), и пока не завершится чтение, поток не может начать запись. Это увеличивает эффективную задержку на транзакцию по сравнению со слепым обновлением в workload A.

Хвостовые задержки (tail latency) отражают двухфазную природу RMW: p99 на RMW у Sirin составляет 16.77 мс против 41.63 мс у Cassandra (разрыв ×2.5). P99 на чистое чтение — 10.19 мс против 36.38 мс. Максимальные задержки у Cassandra достигают 443–448 мс против 127–137 мс у Sirin.

Картина дисковых операций близка к workload D: Cassandra читает с диска больше байт при большем числе IOPS — 446 МБ/с при 27 590 IOPS против 247 МБ/с при 19 340 IOPS у Sirin. Та же закономерность — Cassandra считывает более крупные блоки и «подтягивает» лишние данные, тогда как Sirin читает эффективнее. На стороне записи Sirin активнее пишет на диск (63.6 IOPS / 58.7 МБ/с против 15.5 IOPS / 12.6 МБ/с), что характерно для фоновых компакций Vinyl.

Потребление ресурсов

Sirin стабильно потребляет 3.6–4.0 ГБ оперативной памяти во всех тестах. Cassandra — 11.7–12.1 ГБ, то есть втрое больше. Разница принципиальна: при совместном размещении узлов или сервисов на одной машине это существенно влияет на допустимую плотность. По CPU обе системы в смешанных тестах выходят на ~80%, то есть вычислительное ядро нагружено сопоставимо.

Итог

Sirin опережает Cassandra по пропускной способности во всех пяти протестированных профилях: ×1.30 (A), ×1.11 (B), ×1.09 (C), ×1.19 (D), ×1.24 (F). На нагрузках со значительной долей записи (A, B) основным ограничивающим фактором для обеих систем является рост дисковых чтений при накоплении LSM-уровней; Sirin деградирует медленнее. На чисто читающей нагрузке (C), при вставках с latest-распределением (D) и при RMW-нагрузке (F) Sirin показывает более высокую эффективность при аналогичном числе дисковых операций: Cassandra читает с диска заметно больше байт за тот же IOPS, что снижает итоговую пропускную способность.

По задержкам Sirin стабильно лучше: p99 в 2.5–9 раз ниже, максимальные задержки у Cassandra достигают 198–500 мс против 93–137 мс у Sirin. Потребление RAM у Sirin втрое ниже при сопоставимой загрузке CPU.