Привет! Меня зовут Денис Макаров, я бэкенд-тимлид в KTS.
В прошлый раз мы сравнили Tarantool с Redis, а в этой статье решили провести тесты с Hazelcast. Исследование проводили с коллегой, нашим бэкенд-разработчиком и автором блога Линой Костян.
Денис Макаров
Бэкенд-тимлид
Лина Костян
Бэкенд-разработчик
Так же, как в прошлой статье, мы рассматриваем вариант Tarantool как замены: берём типичные кейсы работы с Hazelcast и реализуем такие же механики на Tarantool.
Выводы из нашего исследования можно прочесть в конце статьи.
Для тестирования брали Grafana K6 — инструмент для нагрузочного тестирования, который позволяет создавать и запускать тестовые сценарии на JavaScript и анализировать результаты тестирования. Он имеет широкий набор функций для создания тестовых сценариев и может работать с различными протоколами, такими как HTTP, WebSocket, gRPC и т.д.
Grafana K6 можно использовать как в командной строке, так и в интерфейсе Grafana. Удобной особенностью K6 является возможность подключать сторонние расширения для работы с протоколами, которые изначально не поддерживаются К6. Так, из коробки К6 не умеет работать с Tarantool, поэтому мы использовали расширение xk6-tarantool.
Для работы с Hazelcast нам пришлось написать собственный плагин, ознакомиться с которым можно по ссылке. Для подключения необходимо пересобрать исполняемый файл К6 с использованием исходного кода нужных дополнений.
Примечание: все тесты были проведены на виртуалках, и это могло немного повлиять на производительность
За время тестирования мы рассмотрели 6 сценариев:
Сценарии 1-5 выполнялись на виртуальной машине со следующими характеристиками: Ubuntu, 4CPU, 16GB RAM, 30GB SSD.
Сценарий 6 выполнялся на двух виртуальных машинах Ubuntu, 4CPU 16GB RAM, 30GB SSD.
Все сценарии выполнялись с профилем нагрузки в 100 виртуальных пользователей, длительностью 120 секунд.
Сценарий 1: key-value c операциями set/get/delete
Используем SET/GET/DEL команды в Hazelcast и аналоги в Tarantool.
Hazelcast:
Дефолтная конфигурация
Tarantool:
Дефолтная конфигурация
Спейс с полями (key string, value string)
???? Hazelcast
Код сценариев k6
import hazelcast from "k6/x/hazelcast";
import exec from "k6/execution";
export const options = {
discardResponseBodies: true,
scenarios: {
test: {
executor: "constant-vus",
exec: "set_keys",
vus: 100,
duration: "120s",
},
test: {
executor: "constant-vus",
exec: "get_keys",
vus: 100,
duration: "120s",
},
test: {
executor: "constant-vus",
exec: " del_keys",
vus: 100,
duration: "120s",
},
},
};
const client = hazelcast.connect([“host:port”]);
const map = hazelcast.getMap(client, "test");
export function set_keys() {
hazelcast.set(map, exec.vu.iterationInInstance + exec.vu.idInInstance * 100, exec.vu
.iterationInInstance + exec.vu.idInInstance * 1000);
}
export function get_keys() {
hzCast.get(map, exec.vu.iterationInInstance + exec.vu.idInInstance * 100);
}
export function del_keys() {
hazelcast.del(map, exec.vu.iterationInInstance + exec.vu.idInInstance * 100);
}
Сценарии set_keys, get_keys, del_keys запускались последовательно.
Результаты выполнения сценариев
Время выполнения запросов
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
Скрипт инициализации
import tarantool from "k6/x/tarantool";
import exec from 'k6/execution';
const conn = tarantool.connect(“host:port”);
export const options = {
discardResponseBodies: true,
scenarios: {
set: {
executor: 'constant-vus',
exec: 'set',
vus: 100,
duration: '120s',
},
get: {
executor: 'constant-vus',
exec: 'get',
vus: 100,
duration: '120s',
},
del: {
executor: 'constant-vus',
exec: 'del',
vus: 100,
duration: '120s',
},
},
};
export function set() {
tarantool.replace(conn, "test", [exec.vu.iterationInInstance + exec.vu.idInInstance * 100, (exec.vu.iterationInInstance + exec.vu.idInInstance * 100).toString()])
};
export function get() {
tarantool.call(conn, "box.space.test:select", [exec.vu.iterationInInstance + exec.vu.idInInstance * 100])
};
export function del() {
tarantool.call(conn, "box.space.test:delete", [exec.vu.iterationInInstance + exec.vu.idInInstance * 100])
};
Сценарии set_keys, get_keys, del_keys запускались последовательно.
Результаты выполнения сценариев
Время выполнения запросов
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 |
26813 |
Get_keys |
33250 |
Del_keys |
30873 |
Сравнительная таблица по RPS
Hazelcast |
Tarantool |
|
Set_keys |
19509 |
26813 |
Get_keys |
25736 |
33250 |
Del_keys |
26170 |
30873 |
Сравнительная таблица по медиане и перцентилям времени выполнения запросов
Hazelcast |
Tarantool |
|||||
med |
p(90) |
p(95) |
med |
p(90) |
p(95) |
|
Set_keys |
3.55ms |
11.59ms |
11.15ms |
3.21ms |
8.31ms |
10.85ms |
Get_keys |
2.75ms |
8.63ms |
11.15ms |
2.58ms |
5.69ms |
7.85ms
|
Del_keys |
2.72ms |
8.43ms |
10.87ms |
2.74ms |
6.38ms |
8.84ms |
Вывод
Tarantool производительнее на несколько тысяч rps в операциях записи, чтения и удаления.
Сценарий 2. Счётчик
Используем Increment и Decrement операции в счетчике в Hazelcast и аналогичные update операции в Tarantool.
Сценарии incr и decr выполняются параллельно.
Hazelcast:
Дефолтная конфигурация
Tarantool:
Дефолтная конфигурация
Создаём спейс с полями (key string, value integer)
???? Hazelcast
Код сценариев к6
import hazelcast from "k6/x/hazelcast";
import exec from "k6/execution";
export const options = {
discardResponseBodies: true,
scenarios: {
test_incr: {
executor: 'constant-vus',
exec: 'incr',
vus: 100,
duration: '120s',
},
test_decr: {
executor: 'constant-vus',
exec: 'decr',
vus: 100,
duration: '120s',
},
},
};
const client = hazelcast.connect([“host:port”]);
export function incr() {
hazelcast.incr(client,'aa'+exec.vu.idInInstance);
}
export function decr() {
hazelcast.decr(client,'aa'+exec.vu.idInInstance);
}
Результаты выполнения сценариев
Время выполнения запросов
avg |
min |
med |
max |
p(90) |
p(95) |
|
INCR/DECR |
6.98ms |
69.04µs |
5.26ms |
131.56ms |
15.36ms |
18.94ms |
Среднее RPS
INCR/DECR |
28533 |
???? Tarantool
Скрипт инициализации tarantool
box.cfg{listen="127.0.0.1:3301"}
box.schema.space.create("test2")
box.space.test2:format({{name="name", type="string"}, {name="value", type="integer"}})
box.space.test2:create_index("primary", {parts={"name"}})
Код сценария к6
import tarantool from "k6/x/tarantool";
import exec from 'k6/execution';
const conn = tarantool.connect("host:port");
export const options = {
discardResponseBodies: true,
scenarios: {
incr: {
executor: 'constant-vus',
exec: 'decr',
vus: 100,
duration: '120s',
},
decr: {
executor: 'constant-vus',
exec: 'decr',
vus: 100,
duration: '120s',
},
},
};
export function setup() {
for (let i = 1; i < 101; i++) {
tarantool.replace(conn, "test2", [i.toString(), 0]);
}
};
export function incr() {
tarantool.call(conn, "box.space.test2:update", [exec.vu.idInInstance.toString(), [["+", 2, 1]]])
}
export function decr() {
tarantool.call(conn, "box.space.test2:update", [exec.vu.idInInstance.toString(), [["-", 2, 1]]])
}
Результаты выполнения сценариев
Время выполнения запросов
avg |
min |
med |
max |
p(90) |
p(95) |
|
INCR/DECR |
3.06ms |
100.01µs |
2.51ms |
72.29ms |
5.26ms |
7.05ms |
Среднее RPS
INCR/DECR |
32552 |
Сравнительная таблица по RPS
Hazelcast |
Tarantool |
|
INCR/DECR |
28533 |
32552 |
Сравнительная таблица по медиане и перцентилям времени выполнения запросов
Hazelcast |
Tarantool |
|||||
med |
p(90) |
p(95) |
med |
p(90) |
p(95) |
|
INCR/DECR |
5.26ms |
15.36ms |
18.94ms |
2.51ms |
5.26ms |
7.05ms |
Вывод
Tarantool несколько производительнее и быстрее в операциях incr/decr.
Сценарий 3. Работа с множествами
Используем set и get для multimap... и реализовываем аналогичные возможности в Tarantool.
Hazelcast:
Дефолтная конфигурация
Tarantool:
Дефолтная конфигурация
Создаём спейс kv с полями (key string, element string)
???? Hazelcast
Код сценариев к6
import hazelcast from "k6/x/hazelcast";
import exec from "k6/execution";
export const options = {
discardResponseBodies: true,
scenarios: {
test: {
executor: "constant-vus",
exec: "set_keys",
vus: 100,
duration: "120s",
},
},
};
const client = hazelcast.connect([“host:port”]);
const map = hazelcast.getMultimap(client, "multi_test");
export function set_keys() {
hazelcast.multimapSet(map, 'test'+exec.vu.idInInstance*1000, exec.vu.iterationInInstance + exec.vu.idInInstance * 100, exec.vu
.iterationInInstance + exec.vu.idInInstance * 1000);
}
export function get_keys() {
hazelcast.multimapMembers(map, exec.vu.iterationInInstance + exec.vu.idInInstance * 100);
}
Время выполнения запросов
avg |
min |
med |
max |
p(90) |
p(95) |
|
Set_keys |
5.74ms |
112.09µs |
3.91ms |
127.62ms |
13.09ms |
17.16ms |
Get_keys |
4.11ms |
80.38µs |
2.85ms |
144.19ms |
9.22ms |
12.07ms |
Среднее RPS
Set_keys |
17301 |
Get_keys |
24132 |
???? Tarantool
Скрипт инициализации
box.cfg{listen="127.0.0.1:3301"}
box.schema.space.create("test3")
box.schema.sequence.create('S',{min=1, start=1})
box.space.test4:format({{name="id", type="unsigned"},{name="name", type="string"}, {name="value", type="string"}})
box.space.test4:create_index("primary", {sequence='S', parts={"id"}})
box.space.test4:create_index("name", {unique=false, parts={"name"}})
Сценарий к6
import tarantool from "k6/x/tarantool";
import exec from 'k6/execution';
const conn = tarantool.connect(“host:port”);
export const options = {
discardResponseBodies: true,
scenarios: {
add: {
executor: 'constant-vus',
exec: 'add',
vus: 100,
duration: '120s',
},
members: {
executor: 'constant-vus',
exec: 'members',
vus: 100,
duration: '120s',
},
},
};
export function add() {
tarantool.insert(conn, "test3", [null, (exec.vu.idInInstance*1000).toString(), (exec.vu.iterationInInstance + exec.vu.idInInstance * 100).toString()])
}
export function members() {
tarantool.call(conn, "box.space.test3.index.name:select", [(exec.vu.idInInstance*1000).toString()])
}
Время выполнения запросов
avg |
min |
med |
max |
p(90) |
p(95) |
|
Set_keys |
4.45 ms |
126.08 µs |
3.47ms |
73.07 ms |
8.93ms |
11.73ms |
Get_keys |
3.34 ms |
104.19 µs |
2.71ms |
73.04 ms |
5.98 ms |
8.33 ms |
Среднее RPS
Set_keys |
22355 |
Get_keys |
29766 |
Сравнительная таблица по RPS
Hazelcast |
Tarantool |
|
Set_keys |
17301 |
22355 |
Get_keys |
24132 |
29766 |
Сравнительная таблица по медиане и перцентилям времени выполнения запросов
Hazelcast |
Tarantool |
|||||
med |
p(90) |
p(95) |
med |
p(90) |
p(95) |
|
Set_keys |
3.91ms |
13.09ms |
17.16ms |
3.47ms |
8.93ms |
11.73ms |
Get_keys |
2.85ms |
9.22ms |
12.07ms |
2.71ms |
5.98ms |
8.33ms |
Вывод
При работе с множествами Tarantool производительнее на несколько тысяч RPS для операций добавления и чтения.
Сценарий 4. Работа с диском
Используем команды Set/Get/… и реализовываем аналогичные возможности в Tarantool.
Тестируем Сценарий 1, меняя конфигурацию БД. Цель теста — определить производительность работы с диском Hazelcast vs Tarantool.
Hazelcast:
Для тестов меняем параметр persistence enabled (false, true) и fsync (false, true)
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 |
19509 |
26335 |
Get_keys |
25736 |
33017 |
Del_keys |
26170 |
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” .
???? Tarantool
Скрипт инициализации
box.cfg{listen="127.0.0.1:3301"}
box.schema.space.create("test5")
box.space.test6:format({{name="id", type="unsigned"}, {name="value", type="string"}})
box.space.test6:create_index("primary", {parts={"id"}})
box.space.test6:create_index("secondary", {parts={"value"}})
Результаты выполнения сценариев
Время выполнения запросов
avg |
min |
med |
max |
p(90) |
p(95) |
|
Set_keys |
3.43ms |
112.54µs |
2.68ms |
48.15ms |
6.63ms |
8.96ms |
Get_keys |
2.73ms |
82.87µs |
2.21ms |
56.86ms |
4.78ms |
6.7ms |
Среднее RPS
Set_keys |
29031 |
Get_keys |
36382 |
???? Hazelcast
Скрипт инициализации
const map = hazelcast.getMap(client, "test");
hazelcast.addIndex(map,["this"], "value");
Результаты выполнения сценариев
Время выполнения запросов
avg |
min |
med |
max |
p(90) |
p(95) |
|
Set_keys |
5.13ms |
99.21µs |
3.52ms |
204.68ms |
11.62ms |
15.36ms |
Get_keys |
3.8ms |
77.39µs |
2.71ms |
60.73ms |
8.48ms |
10.95ms |
Среднее RPS
Set_keys |
19370 |
Get_keys |
26126 |
Сравнительная таблица по RPS
Hazelcast |
Tarantool |
|
Set_keys |
19370 |
29031 |
Get_keys |
26126 |
36382 |
Сравнительная таблица по медиане и перцентилям времени выполнения запросов
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 ближе к привычной табличной организации данных, потому что поддерживает реляционную модель.
Сценарии 1, 2, 3 чаще встречаются в повседневной работе.
Сценарий 4 — режим персистентности.
Персистентность нужна для восстановления данных. Это in-memory решения, и при случайном завершении работы можно потерять все данные. Чтобы такого не произошло, необходимо логирование записей. В Tarantool и Hazelcast существуют разные режимы персистентности. По результатам теста Tarantool быстрее в режиме полной персистентности, чем Hazelcast вообще без персистентности. Это видно по сценарию 4.
Сценарий 5 — вторичные индексы Tatantool быстрее в режиме key-value и при использовании вторичных индексов.
Вторичные индексы часто используются при проектировании структуры базы данных. В случае Tarantool это позволяет производить поиск не только по ключам, но и по значениям.
Пример: у нас имеется таблица вида «табельный номер — ФИО сотрудника», где табельный номер является ключом.
В Tarantool при создании вторичного индекса появляется возможность производить поиск не только по табельному номеру, но и по ФИО, что даёт возможность узнать табельный номер конкретного сотрудника
В Hazelcast тоже есть такая возможность, но производительность уступает Tarantool
Итоги. Tarantool оказался производительнее на запись и чтение и удаление в первых 5 сценариях. Если требуется полноценное решение для кэширования или хранения данных и взаимодействия с ними, которое можно использовать в качестве основной БД, рекомендуем присмотреться к Tarantool. Он ближе к привычной табличной организации данных, потому что поддерживает реляционную модель и запросы на SQL.
Совсем кратко:
Если не нужна репликация — берите Tarantool.
Для сценариев с репликацией сейчас выигрывает Hazelcast, но разница небольшая при других плюсах Тарантула.