Ques/Help/Req Нагрузочный поединок: Tarantool 2.10 vs Redis 7.0.5

XakeR

Member
Регистрация
13.05.2006
Сообщения
1 912
Реакции
0
Баллы
16
Местоположение
Ukraine
Нагрузочный поединок: Tarantool 2.10 vs Redis 7.0.50


Привет! Меня зовут Денис, я бэкенд-тимлид в KTS.

Tarantool и Redis по большей части — два очень разных продукта. Начиная от заложенной в них функциональности и заканчивая протоколом, репликацией и кластерными решениями.

Тем не менее в них много схожего. И Tarantool, и Redis — «однопоточные» базы данных. Однопоточные взято в кавычки, потому что имеется в виду только транзакционный поток, работающий непосредственно с хранилищем. Конечно, есть и сетевые потоки, и потоки репликации, и потоки работы с диском. Также оба эти продукта — in-memory решения, если не брать в расчёт отдельный дисковый vinyl движок в Tarantool.

В статье мы хотим рассмотреть: что, если взять Tarantool как замену Redis? Просядет ли производительность из-за всех «дополнительных» фичей в Tarantool? Насколько хорошо или плохо справится дисковая подсистема с нагрузкой?

Мы взяли типичные кейсы работы с Redis и реализовали такие же механики на Tarantool, начиная от простых K-V операций и заканчивая вторичными ключами и производительностью кластерных решений: для Tarantool это Tarantool Cartridge, для Redis — Redis Cluster.

Выводы из нашего исследования можно прочесть в конце статьи.

Для тестирования использовали Grafana K6 — инструмент для нагрузочного тестирования, который позволяет создавать и запускать тестовые сценарии на JavaScript и анализировать результаты тестирования. Он имеет широкий набор функций для создания тестовых сценариев и может работать с различными протоколами, такими как HTTP, WebSocket, gRPC и т.д.

Grafana K6 можно использовать как в командной строке, так и в интерфейсе Grafana. Удобной особенностью K6 является возможность подключать сторонние расширения для работы с протоколами, которые изначально не поддерживаются К6. Так, из коробки К6 не умеет работать с Tarantool, поэтому мы использовали следующее расширение. Для подключения необходимо пересобрать исполняемый файл К6 с использованием исходного кода нужного дополнения.

За время тестирования мы рассмотрели 7 сценариев:


  • Сценарий 1: key-value c операциями set/get/delete

    • Redis


    • Tarantool


    • Сравнительные таблицы


    • Вывод

  • Сценарий 2: счетчик c операциями incr/decr

    • Redis


    • Tarantool


    • Сравнительные таблицы


    • Вывод

  • Сценарий 3: работа со множествами

    • Redis


    • Tarantool


    • Сравнительные таблицы


    • Вывод

  • Сценарий 4: работа с диском

    • Redis appendfsync: everysec


    • Redis appendfsync: Always


    • Redis appendfsync: No


    • Tarantool wal_mode Write


    • Tarantool wal_mode: None


    • Tarantool wal_mode: Fsync


    • Сравнительные таблицы


    • Вывод

  • Сценарий 5: вторичные индексы

    • Redis


    • Tarantool


    • Сравнительные таблицы


    • Вывод

  • Сценарий 6: влияние репликации на производительность

    • Redis master-slave


    • Tnt master-slave


    • Сравнительные таблицы


    • Вывод

  • Сценарий 7: кластер

    • Redis


    • Tarantool


    • Сравнительные таблицы


    • Вывод

  • Общие выводы из сравнительного нагрузочного тестирования

Сценарии 1-5 выполнялись на виртуальной машине со следующими характеристиками: Ubuntu, 4CPU, 16GB RAM, 30GB SSD.
Сценарий 6 выполнялся на двух виртуальных машинах Ubuntu, 4CPU 16GB RAM, 30GB SSD.
Все сценарии выполнялись с профилем нагрузки в 100 виртуальных пользователей, длительностью 120 секунд.

Сценарий 1. Простой Key-Value​


Берем 3 операции:


  • установка значения по ключу


  • чтение


  • удаление

Создаём 100 пользователей, которые начинают слать запросы. Ключом является id пользователя + номер его запроса, значение сохраняем равное ключу.

Redis:
Дефолтная конфигурация

Tarantool:
Дефолтная конфигурация
Спейс с полями (key string, value string)

🟥
RedisКод сценариев k6import redis from ‘k6/experimental/redis’; 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 = new redis.Client({ addrs: new Array(‘host:port’), password: », db: 0, }); export function set_keys() { client.set(exec.vu.iterationInInstance + exec.vu.idInInstance * 100, exec.vu.iterationInInstance + exec.vu.idInInstance * 100); } export function get_keys() { client.get(exec.vu.iterationInInstance + exec.vu.idInInstance * 100); } export function del_keys() { client.del(exec.vu.iterationInInstance + exec.vu.idInInstance * 100); }

Сценарии set_keys, get_keys, del_keys запускались последовательно.

Результаты выполнения сценариевСреднее RPS


Set_keys

25583​

Get_keys

31967​

Del_keys

31355​

Время выполнения запросов


Действие

avg

min

med

max

p(90)

p(95)

Set_keys

3.78ms​

75.47µs​

2.19ms​

132.3ms​

8.36ms​

12.36ms​

Get_keys

2.96ms​

52.6µs​

1.76ms​

132.48ms​

6.36ms​

9.37ms​

Del_keys

3.09ms​

55.94µs​

1.83ms​

115.23ms​

6.62ms​

9.95ms​

🟦
Tarantool

Для проведения сценария создадим таблицу в Тарантуле вида ключ-значение, где ключ – это число, а значение – строка. Для поиска по ключу нам понадобится первичный индекс:

Первичный индексbox.cfg{listen=»127.0.0.1:3301″} box.schema.space.create(«test») box.space.test:format({{name=»name», type=»unsigned»}, {name=»value», type=»string»}}) box.space.test:create_index(«primary», {parts={«name»}})

Код сценариев k6import 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 запускались последовательно.

Результаты выполнения сценариевСреднее RPS


Set_keys

26813​

Get_keys

33250​

Del_keys

30873​

Время выполнения запросов


Действие

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


Redis

Tarantool

Set_keys

25583​

26813​

Get_keys

31967​

33250​

Del_keys

31355​

30873​

Сравнительная таблица по медиане и перцентилям времени выполнения запросов


Действие

Redis

Tarantool

med

p(90)

p(95)

med

p(90)

p(95)

Set_keys

2.19ms​

8.36ms​

12.36ms​

2.94ms​

7.51ms​

9.93ms​

Get_keys

1.76ms​

6.36ms​

9.37ms​

2.18ms​

4.72ms​

6.7ms​

Del_keys

1.83ms​

6.62ms​

9.95ms​

2.32ms​

5.29ms​

7.35ms​

Вывод по сценарию 1

Tarantool чуть быстрее в операциях записи и чтения, а Redis — в удалении.

Сценарий 2. Счетчик​


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

Используем INCR/DECR в Redis и аналогичные update операции в Tarantool.

Сценарии incr и decr выполняются параллельно.

Конфигурация

Redis:
Дефолтная конфигурация

Tarantool:
Дефолтная конфигурация.
Создаем спейс с полями (key string, value integer).

🟥
RedisКод сценариев к6import redis from «k6/experimental/redis»; import exec from «k6/execution»; export const options = { discardResponseBodies: true, scenarios: { test_incr: { executor: «constant-vus», exec: «incr», vus: 50, duration: «120s», }, test_decr: { executor: «constant-vus», exec: «decr», vus: 50, duration: «120s», }, }, }; const client = new redis.Client({ addrs: new Array(«host:port»), password: «», db: 0, }); export function incr() { client.incr(«id»+exec.vu.idInInstance); } export function decr() { client.decr(«id»+exec.vu.idInInstance); }

Среднее RPS


INCR/DECR

38985​

Время выполнения запросов


avg

min

med

max

p(90)

p(95)

INCR/DECR

2.53ms​

46.41µs​

1.57ms​

78.78ms​

5.27ms​

7.92ms​

🟦
TarantoolСкрипт инициализации tarantoolbox.cfg{listen=»127.0.0.1:3301″} box.schema.space.create(«test») box.space.test:format({{name=»name», type=»string»}, {name=»value», type=»integer»}}) box.space.test:create_index(«primary», {parts={«name»}})

Код сценариев к6import 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: 50, duration: ‘120s’, }, decr: { executor: ‘constant-vus’, exec: ‘decr’, vus: 50, duration: ‘120s’, }, }, }; export function setup() { for (let i = 1; i < 51; i++) { tarantool.replace(conn, «test», [i.toString(), 0]); } }; export function incr() { tarantool.call(conn, «box.space.test:update», [exec.vu.idInInstance.toString(), [[«+», 2, 1]]]) } export function decr() { tarantool.call(conn, «box.space.test:update», [exec.vu.idInInstance.toString(), [[«-«, 2, 1]]]) }


Средний RPS


INCR/DECR

32552​

Время выполнения запросов


avg

min

med

max

p(90)

p(95)

INCR/DECR

3.06ms​

100.01µs​

2.51ms​

72.29ms​

5.26ms​

7.05ms​

Сравнительная таблица по RPS


Redis

Tarantool

INCR/DECR

38985​

32552​

Сравнительная таблица по медиане и перцентилям времени выполнения запросов


Redis

Tarantool

med

p(90)

p(95)

med

p(90)

p(95)

INCR/DECR

1.57ms​

5.27ms​

7.92ms​

2.51ms​

5.26ms​

7.05ms​

Вывод по сценарию 2

По результатам теста Tarantool незначительно уступил Redis.

Сценарий 3. Работа с множествами

Добавляем и получаем значения из множества, используя команды SADD/SMEMBERS в Redis и реализовываем аналогичные возможности в Tarantool.

Конфигурация

Redis:
Дефолтная конфигурация

Tarantool:
Дефолтная конфигурация.
Создаем спейс kv с полями (key string, element string)

🟥
RedisКод сценариев к6import redis from ‘k6/experimental/redis’; import exec from ‘k6/execution’; export const options = { discardResponseBodies: true, scenarios: { test_add: { executor: ‘constant-vus’, exec: ‘add’, vus: 100, duration: ‘120s’, }, test_mem: { executor: ‘constant-vus’, exec: ‘members’, vus: 100, duration: ‘120s’, }, }, }; const client = new redis.Client({ addrs: new Array(‘host:port’), password: », db: 0, }); export function add() { client.sadd(‘test’+exec.vu.idInInstance*1000, (exec.vu.iterationInInstance + exec.vu.idInInstance * 100).toString()); } export function members() { client.smembers(‘test’+exec.vu.idInInstance*1000); }

Время выполнения запросов


avg

min

med

max

p(90)

p(95)

Set_keys

4.2ms​

83.29µs​

2.44ms​

142.34ms​

9.5ms​

13.87ms​

Get_keys

3.33ms​

63.02µs​

2.01ms​

121.31ms​

7.18ms​

10.63ms​

Среднее RPS


Set_keys

22983​

Get_keys

29242​

🟦
Tarantool​


Скрипт инициализацииbox.cfg{listen=»127.0.0.1:3301″} box.schema.space.create(«test») box.schema.sequence.create(‘S’,{min=1, start=1}) box.space.test:format({{name=»id», type=»unsigned»},{name=»name», type=»string»}, {name=»value», type=»string»}}) box.space.test:create_index(«primary», {sequence=’S’, parts={«id»}}) box.space.test:create_index(«name», {unique=false, parts={«name»}})

Сценарий к6import 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, «test», [null, (exec.vu.idInInstance*1000).toString(), (exec.vu.iterationInInstance + exec.vu.idInInstance * 100).toString()]) } export function members() { tarantool.call(conn, «box.space.test.index.name:select», [(exec.vu.idInInstance*1000).toString()]) }

Среднее RPS


Set_keys

22355​

Get_keys

29766​

Время выполнения запросов


avg

min

med

max

p(90)

p(95)

Set_keys

4.45ms​

126.08µs​

3.47ms​

73.07ms​

8.93ms​

11.73ms​

Get_keys

3.34ms​

104.19µs​

2.71ms​

73.04ms​

5.98ms​

8.33ms​

Сравнительная таблица по RPS


Redis

Tarantool

Set_keys

22983​

22355​

Get_keys

29242​

29766​

Сравнительная таблица по медиане и перцентилям iterations_duration


Redis

Tarantool

med

p(90)

p(95)

med

p(90)

p(95)

Set_keys

2.44ms​

9.5ms​

13.87ms​

3.47ms​

8.93ms​

11.73ms​

Get_keys

2.01ms​

7.18ms​

10.63ms​

2.71ms​

5.98ms​

8.33ms​

Вывод по сценарию 3

При работе со множествами Tarantool и Redis показали себя одинаково.

Сценарий 4. Работа с диском​


Тестируем Сценарий 1, меняя конфигурацию БД. Цель теста — определить производительность работы с диском Redis vs Tarantool.

Конфигурация

Redis:
Для тестов меняем параметр appendfsync (no, everysecond, always)

Tarantool:
Для тестов меняем параметр wal_mode (none, write, fsync)

🟥
Redis appendfsync: everysecВремя выполнения запросов


avg

min

med

max

p(90)

p(95)

Set_keys

3.78ms​

75.47µs​

2.19ms​

132.3ms​

8.36ms​

12.36ms​

Get_keys

2.96ms​

52.6µs​

1.76ms​

132.48ms​

6.36ms​

9.37ms​

Del_keys

3.09ms​

55.94µs​

1.83ms​

115.23ms​

6.62ms​

9.95ms​

Среднее RPS


Set_keys

25583​

Get_keys

31967​

Del_keys

31355​

🟥
Redis appendfsync: AlwaysВремя выполнения запросов


avg

min

med

max

p(90)

p(95)

Set_keys

4.07ms​

79.09µs​

2.35ms​

135.39ms​

9.17ms​

13.28ms​

Get_keys

3.22ms​

60.93µs​

1.93ms​

129.49ms​

7.01ms​

10.32ms​

Del_keys

3.13ms​

57.96µs​

1.88ms​

113.63ms​

6.8ms​

10.02ms​

Среднее RPS


Set_keys

23773​

Get_keys

29467​

Del_keys

30741​

🟥
Redis appendfsync: NoВремя выполнения запросов


avg

min

med

max

p(90)

p(95)

Set_keys

3.94ms​

76.25µs​

2.26ms​

155.91ms​

8.81ms​

12.95ms​

Get_keys

3.14ms​

63.19µs​

1.74ms​

122.84ms​

6.81ms​

9.98ms​

Del_keys

2.73ms​

54.07µs​

1.63ms​

110.17ms​

5.8ms​

8.46ms​

Среднее RPS


Set_keys

24541​

Get_keys

31999​

Del_keys

35179​

🟦
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​

🟦
Tarantool 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​

🟦
Tarantool wal_mode: FsyncСреднее RPS


Set_keys

25055​

Get_keys

31342​

Del_keys

28758​

Время выполнения запросов


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


Redis

Tarantool

appendfsync: everysec

wal_mode Write

Set_keys

25583​

26813​

Get_keys

31967​

33250​

Del_keys

31355​

30873​
[TD]
appendfsync: no
[/TD]

[TD]
wal_mode: None
[/TD]​
[TR]
[TD]
Set_keys
[/TD]

[TD]
24541​
[/TD]

[TD]
26335​
[/TD]
[/TR]
[TR]
[TD]
Get_keys
[/TD]

[TD]
31999​
[/TD]

[TD]
33017​
[/TD]
[/TR]
[TR]
[TD]
Del_keys
[/TD]

[TD]
35179​
[/TD]

[TD]
34273​
[/TD]
[/TR]
[TR]
[TD] [/TD]

[TD]
appendfsync: Always
[/TD]

[TD]
wal_mode: Fsync
[/TD]​
[/TR]
[TR]
[TD]
Set_keys
[/TD]

[TD]
23773​
[/TD]

[TD]
25055​
[/TD]
[/TR]
[TR]
[TD]
Get_keys
[/TD]

[TD]
29467​
[/TD]

[TD]
31342​
[/TD]
[/TR]
[TR]
[TD]
Del_keys
[/TD]

[TD]
30741​
[/TD]

[TD]
28758​
[/TD]
[/TR]​

Сравнительная таблица по медиане и перцентилям iterations_duration​


Redis

Tarantool

appendfsync: everysec

wal_mode: write

med

p(90)

p(95)

med

p(90)

p(95)

Set_keys

2.19ms​

8.36ms​

12.36ms​

2.94ms​

7.51ms​

9.93ms​

Get_keys

1.76ms​

6.36ms​

9.37ms​

2.18ms​

4.72ms​

6.7ms​

Del_keys

1.83ms​

6.62ms​

9.95ms​

2.32ms​

5.29ms​

7.35ms​
[TD]
appendfsync: no
[/TD]

[TD]
wal_mode: None
[/TD]​
[TR]
[TD]
Set_keys
[/TD]

[TD]
2.26ms​
[/TD]

[TD]
8.81ms​
[/TD]

[TD]
12.95ms​
[/TD]

[TD]
3.28ms​
[/TD]

[TD]
7.85ms​
[/TD]

[TD]
10.36ms​
[/TD]
[/TR]
[TR]
[TD]
Get_keys
[/TD]

[TD]
1.74ms​
[/TD]

[TD]
6.81ms​
[/TD]

[TD]
9.98ms​
[/TD]

[TD]
2.66ms​
[/TD]

[TD]
5.9ms​
[/TD]

[TD]
8.23ms​
[/TD]
[/TR]
[TR]
[TD]
Del_keys
[/TD]

[TD]
1.63ms​
[/TD]

[TD]
5.8ms​
[/TD]

[TD]
8.46ms​
[/TD]

[TD]
2.32ms​
[/TD]

[TD]
5.17ms​
[/TD]

[TD]
7.25ms​
[/TD]
[/TR]
[TR]
[TD] [/TD]

[TD]
appendfsync: always
[/TD]

[TD]
wal_mode: fsync
[/TD]​
[/TR]
[TR]
[TD]
Set_keys
[/TD]

[TD]
2.35ms​
[/TD]

[TD]
9.17ms​
[/TD]

[TD]
13.28ms​
[/TD]

[TD]
3.21ms​
[/TD]

[TD]
8.31ms​
[/TD]

[TD]
10.85ms​
[/TD]
[/TR]
[TR]
[TD]
Get_keys
[/TD]

[TD]
1.93ms​
[/TD]

[TD]
7.01ms​
[/TD]

[TD]
10.32ms​
[/TD]

[TD]
2.58ms​
[/TD]

[TD]
5.69ms​
[/TD]

[TD]
7.85ms​
[/TD]
[/TR]
[TR]
[TD]
Del_keys
[/TD]

[TD]
1.88ms​
[/TD]

[TD]
6.8ms​
[/TD]

[TD]
10.02ms​
[/TD]

[TD]
2.74ms​
[/TD]

[TD]
6.38ms​
[/TD]

[TD]
8.84ms​
[/TD]
[/TR]​

Вывод по сценарию

При логировании каждой записи (appendfsync always в redis и wal_mode fsync в tarantool) tarantool показал лучший результат.

Сценарий 5. Вторичные индексы​


KV в tarantool (id, value) со вторичным индексом на value.

Для добавления вторичных индексов в Redis использовался модуль Redisearch, скомпилированный под Ubuntu и запущенный через loadmodule

🟦
TarantoolСкрипт инициализацииbox.cfg{listen=»127.0.0.1:3301″} box.schema.space.create(«test») box.space.test:format({{name=»id», type=»unsigned»}, {name=»value», type=»string»}}) box.space.test:create_index(«primary», {parts={«id»}}) box.space.test: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​

Search

2.73ms​

82.87µs​

2.21ms​

56.86ms​

4.78ms​

6.7ms​

Среднее RPS


Set_keys

29031​

Get_keys

36382​

🟥
RedisВремя выполнения запросов


avg

min

med

max

p(90)

p(95)

Set_keys

3.66ms​

70.83µs​

2.26ms​

89.86ms​

8.27ms​

12.15ms​

Search

2.94ms​

62.1µs​

1.86ms​

83.79ms​

6.32ms​

9.41ms​

Среднее RPS


Set_keys

27122​

Get_keys

33801​

Сравнительная таблица по RPS


Redis

Tarantool

Set_keys

27122​

29031​

Search

33801​

36382​

Сравнительная таблица по медиане и перцентилям iterations_duration


Redis

Tarantool

med

p(90)

p(95)

med

p(90)

p(95)

Set_keys

2.68ms​

6.63ms​

8.96ms​

2.26ms​

8.27ms​

12.15ms​

Get_keys

2.21ms​

4.78ms​

6.7ms​

1.86ms​

6.32ms​

9.41ms​

Вывод по сценарию 5

Tarantool производительнее на несколько тысяч rps при работе со вторичными индексами и не требует дополнительных модулей для их работы.

Сценарий 6. Влияние репликации на производительность​


Тестируем cценарий 1, меняя конфигурацию репликации. Цель теста — определить влияние репликации на производительность БД.

Проводим 2 теста:


  • Сценарий 6.1 Redis с репликацией на 1 узел


  • Сценарий 6.2 Tarantool с master-slave репликацией на 1 узел

🟥
Сценарий 6.1 Redis master-slaveВремя выполнения запросов


avg

min

med

max

p(90)

p(95)

Set_keys

3.86ms​

72.13µs​

2.76ms​

78.53ms​

8.12ms​

11.68ms​

Get_keys

3.08ms​

52.11µs​

1.81ms​

64.77ms​

6.65ms​

9.93ms​

Del_keys

2.96ms​

50.08µs​

1.74ms​

72.78ms​

6.34ms​

9.39ms​

Среднее RPS


Set_keys

25766​

Get_keys

30689​

Del_keys

32378​

🟦
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


Redis

Tarantool

Репликация на 1 узел

Репликация на 1 узел (master-slave)

Set_keys

25766​

22883​

Get_keys

30689​

30452​

Del_keys

32378​

28830​

Сравнительная таблица по медиане и перцентилям iterations_duration


Redis

Tarantool

Репликация на 1 узел

Репликация на 1 узел (master-slave)

med

p(90)

p(95)

med

p(90)

p(95)

Set_keys

2.76ms​

8.12ms​

11.68ms​

3.32ms​

8.83ms​

11.61ms​

Get_keys

1.81ms​

6.65ms​

9.93ms​

2.2ms​

4.67ms​

6.46ms​

Del_keys

1.74ms​

6.34ms​

9.39ms​

2.78ms​

6.21ms​

8.53ms​

Вывод по сценарию 6

По результатам теста при репликации master-slave Redis с минимальным перевесом обошёл Tarantool в операциях чтения и удаления.

Сценарий 7. Кластер​


В данном сценарии были развернуты кластеры Redis и Tarantool в следующей конфигурации: 3 шарда, в каждом шарде 1 мастер и 2 реплики.

Характеристики виртуальных машин: Ubuntu, 4 cpu, 8 gb RAM, 10 gb ssd. Запускались тесты из сценария 1.

🟥
Кластер RedisВремя выполнения запросов


avg

min

med

max

p(90)

p(95)

Set_keys

3.17ms​

231.06µs​

2.31ms​

220.89ms​

6.5ms​

8.62ms​

Get_keys

2.73ms​

223.4µs​

2.01ms​

124.6ms​

6.01ms​

7.05ms​

Del_keys

2.61ms​

214.5µs​

1.91ms​

105.32ms​

5.06ms​

6.89ms​

Среднее RPS


Set_keys

31390​

Get_keys

37245​

Del_keys

38158​

🟦
Кластер Tarantool

Топология кластера

Нагрузочный поединок: Tarantool 2.10 vs Redis 7.0.51


Реализована пользовательская роль, реализующая следующие функции:

Кодfunction del(id) local result, err = crud.delete(‘test’, id) if err ~= nil then return err end return result end function add(id, value) local result, err = crud.insert(‘test’, {id, value}) if err ~= nil then return err end return result end function get(id) local result, err = crud.get(‘test’, id) if err ~= nil then return err end return result end

Для операций с данными использовался модуль crud.

Время выполнения запросов


avg

min

med

max

p(90)

p(95)

Set_keys

5.13ms​

636.41µs​

4.35ms​

75.47ms​

8.34ms​

11ms​

Get_keys

4ms​

399.47µs​

3.4ms​

39.65ms​

6.16ms​

8.69ms​

Del_keys

4.22ms​

548.83µs​

3.65ms​

73.67ms​

6.5ms​

8.73ms​

Среднее RPS


Set_keys

19436​

Get_keys

24888​

Del_keys

23627​

Сравнительная таблица по RPS


Redis

Tarantool

Set_keys

31390​

19436​

Get_keys

37245​

24888​

Del_keys

38158​

23627​

Сравнительная таблица по медиане и перцентилям iterations_duration

[TD]
Redis
[/TD]

[TD]
Tarantool
[/TD]​
[TR]
[TD]
med
[/TD]

[TD]
p(90)
[/TD]

[TD]
p(95)
[/TD]

[TD]
med
[/TD]

[TD]
p(90)
[/TD]

[TD]
p(95)
[/TD]
[/TR]
[TR]
[TD]
Set_keys
[/TD]

[TD]
2.31ms​
[/TD]

[TD]
6.5ms​
[/TD]

[TD]
8.62ms​
[/TD]

[TD]
4.35ms​
[/TD]

[TD]
8.34ms​
[/TD]

[TD]
11ms​
[/TD]
[/TR]
[TR]
[TD]
Get_keys
[/TD]

[TD]
2.01ms​
[/TD]

[TD]
6.01ms​
[/TD]

[TD]
7.05ms​
[/TD]

[TD]
3.4ms​
[/TD]

[TD]
6.16ms​
[/TD]

[TD]
8.69ms​
[/TD]
[/TR]
[TR]
[TD]
Del_keys
[/TD]

[TD]
1.91ms​
[/TD]

[TD]
5.06ms​
[/TD]

[TD]
6.89ms​
[/TD]

[TD]
3.65ms​
[/TD]

[TD]
6.5ms​
[/TD]

[TD]
8.73ms​
[/TD]
[/TR]​

Вывод по сценарию 7

При запуске в режиме кластера Redis выигрывает.

Общие выводы из сравнительного нагрузочного тестирования​


Redis

Имеет важные преимущества. Он популярнее и как следствие, имеет большее комьюнити. В интернете представлено больше информации по вопросам использования Redis, следовательно, у технологии более низкий порог входа.

В основном Redis используется для реализации кеширования, и он хорошо подходит для этой роли: например, в первом сценарии он лишь незначительно уступил Tarantool.

Tarantool

Если требуется полноценное решение для кеширования или хранения данных и взаимодействия с ними, которое можно использовать в качестве основной БД, рекомендуем присмотреться к Tarantool. Он ближе к привычной табличной организации данных, потому что поддерживает реляционную модель и запросы на SQL. При этом в большинстве случаев он способен выдерживать нагрузку, сравнимую с K-V БД вроде Redis.

Tarantool показал себя лучше под нагрузкой в сценариях 1, 4, 5: у него меньше время ответа, он держит большее количество RPS, в нем из коробки реализованы вторичные индексы. В сценарии 3 Tarantool и Redis проявили себя одинаково.

В результате Tarantool:


  • Немного быстрее работает в режиме key-value и при использовании вторичных индексов


  • Быстрее работает в режиме полной персистентности

Рассмотрим эти преимущества подробнее.

1. Tarantool немного быстрее работает в режиме key-value и при использовании вторичных индексов​


Вторичные индексы часто используются при проектировании структуры базы данных. В случае Tarantool это позволяет производить поиск не только по ключам, но и по значениям.

Например: у нас имеется таблица вида «табельный номер — ФИО сотрудника», где табельный номер является ключом.


  • В Tarantool при создании вторичного индекса появляется возможность производить поиск не только по табельному номеру, но и по ФИО, что даёт возможность узнать табельный номер конкретного сотрудника


  • В Redis тоже есть такая возможность, но для этого необходимо устанавливать модуль RediSearch. При этом производительность решения будет уступать Tarantool

2. Tarantool быстрее работает в режиме полной персистентности в in-memory базах​


Tarantool показывает большую производительность при сбросе данных на диск в режимах wal_mode=write и wal_mode=fsync — в сравнении с Redis с параметром appendfsync=everysec и appendfsync=always соответственно.


Почему это важно: эти режимы нужны для возможности восстановления данных в случае сбоя. Все операции сохраняются в специальный файл, и в случае неисправности их можно воспроизвести и не потерять данные.
Разница между режимами выше — в частоте записи в файл. В режиме полной персистентности, когда операции записываются в файл сразу после их выполнения с wal_mode=fsync, Tarantool выигрывает у Redis. Это дает возможность выдерживать большую нагрузку при максимальной сохранности данных.

Совсем кратко​


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

Исходный код тестов для К6 можно посмотреть в репозитории.
 

AI G

Moderator
Команда форума
Регистрация
07.09.2023
Сообщения
786
Реакции
2
Баллы
18
Местоположение
Метагалактика
Сайт
golo.pro
Native language | Родной язык
Русский
Sorry I couldn't contact the ChatGPT think tank :(
 
198 101Темы
635 072Сообщения
3 618 396Пользователи
TwixOnFire69Новый пользователь
Верх