Привет! Меня зовут Денис Макаров, я бэкенд-тимлид в KTS.
В прошлый раз мы сравнили Tarantool с Redis, а в этой статье решили провести тесты с Hazelcast. Исследование проводили с коллегой, нашим бэкенд-разработчиком и автором блога Линой Костян.
Денис Макаров
Бэкенд-тимлид
Лина Костян
Бэкенд-разработчик
Так же, как в прошлой статье, мы рассматриваем вариант Tarantool как замены: берём типичные кейсы работы с Hazelcast и реализуем такие же механики на Tarantool.
Для тестирования использовали Grafana K6 — инструмент для нагрузочного тестирования, который позволяет создавать и запускать тестовые сценарии на JavaScript и анализировать результаты тестирования. Он имеет широкий набор функций для создания тестовых сценариев и может работать с различными протоколами, такими как HTTP, WebSocket, gRPC и т.д.
Grafana K6 можно использовать как в командной строке, так и в интерфейсе Grafana. Удобной особенностью K6 является возможность подключать сторонние расширения для работы с протоколами, которые изначально не поддерживаются К6. Так, из коробки К6 не умеет работать с Tarantool, поэтому мы использовали расширение xk6-tarantool.
Для работы с Hazelcast нам пришлось написать собственный плагин xk6-hazelcast.Для подключения необходимо пересобрать исполняемый файл К6 с использованием исходного кода нужных дополнений.
Примечание: все тесты были проведены на виртуалках, и это могло немного повлиять на производительность и результаты измерений
Tarantool:Создаём спейс kv с полями (key string, element string). Для тестов меняем параметр wal_mode (none, write, fsync)
???? Hazelcast
Результаты выполнения сценариев persistence: true, fsync: true
Время выполнения запросов
Avg
Min
Med
Max
p(90)
p(95)
Set_keys
5.22ms
110.18µs
3.62ms
142.03ms
11.88ms
15.45ms
Get_keys
3.8ms
77.36µs
2.71ms
67.69ms
8.45ms
10.9ms
Del_keys
3.81ms
83.14µs
2.71ms
114.89ms
8.51ms
10.99ms
Среднее RPS
Set_keys
19051
Get_keys
26160
Del_keys
26042
persistence: true, fsync: false
Время выполнения запросов
Avg
Min
Med
Max
p(90)
p(95)
Set_keys
4.91ms
103.5µs
3.46ms
109.04ms
11.07ms
14.39ms
Get_keys
3.72ms
78.58µs
2.65ms
103.97ms
8.26ms
10.69ms
Del_keys
3.68ms
80.38µs
2.63ms
77.61ms
8.19ms
10.56ms
Среднее RPS
Set_keys
20233
Get_keys
26702
Del_keys
26947
persistence: false, fsync: false
Время выполнения запросов
Avg
Min
Med
Max
p(90)
p(95)
Set_keys
5.1ms
105.61µs
3.55ms
85.24ms
11.59ms
11.15ms
Get_keys
3.86ms
81.02µs
2.75ms
206.83ms
8.63ms
11.15ms
Del_keys
3.79ms
80.64µs
2.72ms
74.16ms
8.43ms
10.87ms
Среднее RPS
Set_keys
19509
Get_keys
25736
Del_keys
26170
???? Tarantool, результаты выполнения сценариев
wal_mode Write
Время выполнения запросов
avg
min
med
max
p(90)
p(95)
Set_keys
3.78ms
117.33µs
2.94ms
53.07ms
7.51ms
9.93ms
Get_keys
2.7ms
86.38µs
2.18ms
45.22ms
4.72ms
6.7ms
Del_keys
2.93ms
108.13µs
2.32ms
70.4ms
5.29ms
7.35ms
Среднее RPS
Set_keys
26813
Get_keys
33250
Del_keys
30873
wal_mode: None
Время выполнения запросов
avg
min
med
max
p(90)
p(95)
Set_keys
3.82ms
76.2µs
2.2ms
41.77ms
7.85ms
10.36ms
Get_keys
3.28ms
95.29µs
2.66ms
57.78ms
5.9ms
8.23ms
Del_keys
2.9ms
87.79µs
2.32ms
56.83ms
5.17ms
7.25ms
Среднее RPS
Set_keys
26335
Get_keys
33017
Del_keys
34273
wal_mode: Fsync
Время выполнения запросов
avg
min
med
max
p(90)
p(95)
Set_keys
4.14ms
122.3µs
3.21ms
60.34ms
8.31ms
10.85ms
Get_keys
3.17ms
89.51µs
2.58ms
71.09ms
5.69ms
7.85ms
Del_keys
3.46ms
114.76µs
2.74ms
61.46ms
6.38ms
8.84ms
Среднее RPS
Set_keys
25055
Get_keys
31342
Del_keys
28758
Сравнительная таблица по RPS
Hazelcast
Tarantool
persistence: true, fsync: false
wal_mode Write
Set_keys
20233
26813
Get_keys
26702
33250
Del_keys
26947
30873
persistence: false, fsync: false
wal_mode: None
Set_keys
21509
26335
Get_keys
26736
33017
Del_keys
26870
34273
persistence: true, fsync: true
wal_mode: Fsync
Set_keys
19051
25055
Get_keys
26160
31342
Del_keys
26042
28758
Сравнительная таблица по медиане и перцентилям времени выполнения запросов
Hazelcast
Tarantool
persistence: true, fsync: false
wal_mode: write
med
p(90)
p(95)
med
p(90)
p(95)
Set_keys
3.46ms
11.07ms
14.39ms
2.94ms
7.51ms
9.93ms
Get_keys
2.65ms
8.26ms
10.69ms
2.18ms
4.72ms
6.7ms
Del_keys
2.63ms
8.19ms
10.56ms
2.32ms
5.29ms
7.35ms
persistence: false, fsync: false
wal_mode: None
Set_keys
3.55ms
11.59ms
11.15ms
3.28ms
7.85ms
10.36ms
Get_keys
2.75ms
8.63ms
11.15ms
2.66ms
5.9ms
8.23ms
Del_keys
2.72ms
8.43ms
10.87ms
2.32ms
5.17ms
7.25ms
persistence: true, fsync: true
wal_mode: fsync
Set_keys
3.62ms
11.88ms
15.45ms
3.21ms
8.31ms
10.85ms
Get_keys
2.71ms
8.45ms
10.9ms
2.58ms
5.69ms
7.85ms
Del_keys
2.71ms
8.51ms
10.99ms
2.74ms
6.38ms
8.84ms
Вывод
При любых конфигурациях использования диска Tarantool производительнее. В частности, даже в режиме полной персистентности Tarantool быстрее Hazelcast, работающего в режиме выключенного логирования (persistance: false).
Сценарий 5. Вторичные индексы
Kv в tarantool (id, value) со вторичным индексом на value.
В hazelcast со вторичным hash индексом на “this” .
Сравнительная таблица по медиане и перцентилям времени выполнения запросов
Hazelcast
Tarantool
med
p(90)
p(95)
med
p(90)
p(95)
Set_keys
3.52ms
11.62ms
15.36ms
2.26ms
8.27ms
12.15ms
Get_keys
2.71ms
8.48ms
10.95ms
1.86ms
6.32ms
9.41ms
Вывод
Оба приложения умеют работать со вторичными индексами «из коробки», однако Tarantool производительнее на несколько тысяч rps.
Сценарий 6. Влияние репликации на производительность
Тестируем сценарий 1, меняя конфигурацию репликации. Цель теста — определить влияние репликации на производительность БД.
Проводим 2 теста:
Сценарий 6.1 Hazelcast с master-master репликацией на 1 узел
Сценарий 6.2 Tarantool с master-slave репликацией на 1 узел
???? Сценарий 6.1 Hazelcast master-master
Результаты выполнения сценариев
Время выполнения запросов
avg
min
med
max
p(90)
p(95)
Set_keys
3.78ms
643.85µs
2.91ms
74.92ms
6.81ms
9.33ms
Get_keys
2.62ms
247.85µs
2ms
67.59ms
5.01ms
6.74ms
Del_keys
2.6ms
236.8µs
1.98ms
115.51ms
4.92ms
6.63ms
Среднее RPS
Set_keys
26322
Get_keys
37863
Del_keys
38155
???? Сценарий 6.2 Tnt-master-slave
Результаты выполнения сценариев
Время выполнения запросов
avg
min
med
max
p(90)
p(95)
Set_keys
4.35ms
129.16µs
3.32ms
72.58ms
8.83ms
11.61ms
Get_keys
3.27ms
84.55µs
2.66ms
41ms
5.95ms
8.15ms
Del_keys
3.45ms
99.55µs
2.78ms
89.36ms
6.21ms
8.53ms
Среднее RPS
Set_keys
22883
Get_keys
30452
Del_keys
28830
Сравнительная таблица по RPS
Hazelcast
Tarantool
Репликация на 1 узел (master-master)
Репликация на 1 узел (master-slave)
Set_keys
26322
22883
Get_keys
37863
30452
Del_keys
38155
28830
Сравнительная таблица по медиане и перцентилям времени выполнения запросов
Hazelcast
Tarantool
Репликация на 1 узел (master-master)
Репликация на 1 узел (master-slave)
med
p(90)
p(95)
med
p(90)
p(95)
Set_keys
2.91ms
6.81ms
9.33ms
3.32ms
8.83ms
11.61ms
Get_keys
2ms
5.01ms
6.74ms
2.2ms
4.67ms
6.46ms
Del_keys
1.98ms
4.92ms
6.63ms
6.21ms
8.53ms
6.21ms
Вывод
Hazelcast при репликации master-master работает быстрее, чем Tarantool в режиме master-slave.
Общие выводы
Hazelcast
Hazelcast — это приложение Java без внешних зависимостей. Он предлагает те же интерфейсы и API, что и хорошо известный пакет java.util. Это позволяет комфортно работать с Hazelcast из Java-приложения. В отличие от Tarantool, поддерживает выполнение в нескольких потоках, которые можно конфигурировать. Это позволяет проще масштабировать приложение, но при этом несёт определенные риски доступа к данным.
Tarantool
ДокументацияВ отличие от Hazelcast, где часто встречаются устаревшие инструкции, у Tarantool более наглядная документация с примерами для актуальной версии. У обоих продуктов есть коммерческая поддержка.
SQLОба поддерживают запросы на SQL, но Tarantool ближе к привычной табличной организации данных, потому что поддерживает реляционную модель.
Поясним некоторые рассмотренные выше сценарии.
Сценарий 4 — режим персистентности Персистентность нужна для восстановления данных. Это in-memory решения, и чтобы не потерять все данные при аварийном завершении работы, необходимо логирование записей. В Tarantool и Hazelcast существуют разные режимы персистентности. По результатам теста Tarantool быстрее в режиме полной персистентности, чем Hazelcast вообще без персистентности.
Сценарий 5 — вторичные индексыTatantool быстрее в режиме key-value и при использовании вторичных индексов. Вторичные индексы часто используются при проектировании структуры базы данных. Это позволяет производить поиск не только по ключам, но и по значениям.
Пример: у нас имеется таблица вида «табельный номер — ФИО сотрудника», где табельный номер является ключом.
В Tarantool при создании вторичного индекса появляется возможность производить поиск не только по табельному номеру, но и по ФИО, что даёт возможность узнать табельный номер конкретного сотрудника
В Hazelcast тоже есть такая возможность, но производительность уступает Tarantool
Итоги. Tarantool оказался производительнее на запись и чтение и удаление в первых 5 сценариях. Если требуется полноценное решение для кэширования или хранения данных и взаимодействия с ними, которое можно использовать в качестве основной БД, рекомендуем присмотреться к Tarantool. Он ближе к привычной табличной организации данных, потому что поддерживает реляционную модель и запросы на SQL.
Совсем кратко:
Если не нужна репликация — используйте Tarantool.
Для сценариев с репликацией сейчас выигрывает Hazelcast, но разница небольшая при других плюсах Tarantool.
По итогу получается померили сетевые пакетные задержки + сериализация/десериализация как раз в районе нескольких милисекунд для локалхоста при малом размере данных, не в обиду сказано, но у меня сложилось такое впечатление. Что произойдёт если запустить параллельно? Что будет если отправлять изменения пачками по 10/100/1000/10000?
Отвечая на вопрос про параллельность - в тестах создается 100 виртуальных пользователей k6 (параметр vus), которые отправляют запросы параллельно. Сценарий с отправкой запросов пачками не тестировался, учтем в следующих сравнениях, спасибо за предложение.
arusakov
Спасибо, за подробную сводку. Даешь Tarantool vs Dragonfly!
makdenis Автор
Спасибо, примем к сведению!
aleks_raiden
Еще лучше сравните с keyDB и KVRocks
izhnox
По итогу получается померили сетевые пакетные задержки + сериализация/десериализация как раз в районе нескольких милисекунд для локалхоста при малом размере данных, не в обиду сказано, но у меня сложилось такое впечатление. Что произойдёт если запустить параллельно? Что будет если отправлять изменения пачками по 10/100/1000/10000?
makdenis Автор
Отвечая на вопрос про параллельность - в тестах создается 100 виртуальных пользователей k6 (параметр vus), которые отправляют запросы параллельно. Сценарий с отправкой запросов пачками не тестировался, учтем в следующих сравнениях, спасибо за предложение.