Привет! Меня зовут Денис, я бэкенд-тимлид в 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 секунд. Берем 3 операции:  установка значения по ключу чтение удаление Создаём 100 пользователей, которые начинают слать запросы. Ключом является id пользователя + номер его запроса, значение сохраняем равное ключу. Redis:Дефолтная конфигурация Tarantool:Дефолтная конфигурацияСпейс с полями (key string, value string)  Сценарии set_keys, get_keys, del_keys запускались последовательно.  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 Для проведения сценария создадим таблицу в Тарантуле вида ключ-значение, где ключ – это число, а значение – строка. Для поиска по ключу нам понадобится первичный индекс:   Сценарии set_keys, get_keys, del_keys запускались последовательно.  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 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 Tarantool чуть быстрее в операциях записи и чтения, а Redis — в удалении. Создаем 100 пользователей, которые отправляют запросы на увеличение или уменьшение счетчика. Для каждого пользователя используется свой счетчик.  Используем INCR/DECR в Redis и аналогичные update операции в Tarantool. Сценарии incr и decr выполняются параллельно. Redis:Дефолтная конфигурация Tarantool:Дефолтная конфигурация.Создаем спейс с полями (key string, value integer).  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    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 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 По результатам теста Tarantool незначительно уступил Redis. Добавляем и получаем значения из множества, используя команды SADD/SMEMBERS в Redis и реализовываем аналогичные возможности в Tarantool. Redis:Дефолтная конфигурация Tarantool:Дефолтная конфигурация.Создаем спейс kv с полями (key string, element string)  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 Set_keys 22983 Get_keys 29242   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 Redis Tarantool Set_keys 22983 22355 Get_keys 29242 29766 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 При работе со множествами Tarantool и Redis показали себя одинаково. Тестируем Сценарий 1, меняя конфигурацию БД. Цель теста — определить производительность работы с диском Redis vs Tarantool. Redis:Для тестов меняем параметр appendfsync (no, everysecond, always) Tarantool:Для тестов меняем параметр wal_mode (none, write, fsync) 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 Set_keys 25583 Get_keys 31967 Del_keys 31355 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 Set_keys 23773 Get_keys 29467 Del_keys 30741 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 Set_keys 24541 Get_keys 31999 Del_keys 35179 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 Set_keys 26813 Get_keys 33250 Del_keys 30873 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 Set_keys 26335 Get_keys 33017 Del_keys 34273 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 Redis Tarantool appendfsync: everysec wal_mode Write Set_keys 25583 26813 Get_keys 31967 33250 Del_keys 31355 30873  appendfsync: no wal_mode: None Set_keys 24541 26335 Get_keys 31999 33017 Del_keys 35179 34273  appendfsync: Always wal_mode: Fsync Set_keys 23773 25055 Get_keys 29467 31342 Del_keys 30741 28758 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  appendfsync: no wal_mode: None Set_keys 2.26ms 8.81ms 12.95ms 3.28ms 7.85ms 10.36ms Get_keys 1.74ms 6.81ms 9.98ms 2.66ms 5.9ms 8.23ms Del_keys 1.63ms 5.8ms 8.46ms 2.32ms 5.17ms 7.25ms  appendfsync: always wal_mode: fsync Set_keys 2.35ms 9.17ms 13.28ms 3.21ms 8.31ms 10.85ms Get_keys 1.93ms 7.01ms 10.32ms 2.58ms 5.69ms 7.85ms  Del_keys 1.88ms 6.8ms 10.02ms 2.74ms 6.38ms 8.84ms При логировании каждой записи (appendfsync always в redis и wal_mode fsync в tarantool) tarantool показал лучший результат. KV в tarantool (id, value) со вторичным индексом на value. Для добавления вторичных индексов в Redis использовался модуль Redisearch, скомпилированный под Ubuntu и запущенный через loadmodule  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 Set_keys 29031 Get_keys 36382 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 Set_keys 27122 Get_keys 33801 Redis Tarantool Set_keys 27122 29031 Search 33801 36382 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 Tarantool производительнее на несколько тысяч rps при работе со вторичными индексами и не требует дополнительных модулей для их работы. Тестируем cценарий 1, меняя конфигурацию репликации. Цель теста — определить влияние репликации на производительность БД. Проводим 2 теста: Сценарий 6.1 Redis с репликацией на 1 узел Сценарий 6.2 Tarantool с master-slave репликацией на 1 узел 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 Set_keys 25766 Get_keys 30689 Del_keys 32378 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 Set_keys 22883 Get_keys 30452 Del_keys 28830 Redis Tarantool Репликация на 1 узел Репликация на 1 узел (master-slave) Set_keys 25766 22883 Get_keys 30689 30452 Del_keys 32378 28830 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 По результатам теста при репликации master-slave Redis с минимальным перевесом обошёл Tarantool в операциях чтения и удаления. В данном сценарии были развернуты кластеры Redis и Tarantool в следующей конфигурации: 3 шарда, в каждом шарде 1 мастер и 2 реплики.  Характеристики виртуальных машин: Ubuntu, 4 cpu, 8 gb RAM, 10 gb ssd. Запускались тесты из сценария 1. 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 Set_keys 31390 Get_keys 37245 Del_keys 38158 Топология кластера Реализована пользовательская роль, реализующая следующие функции:  Для операций с данными использовался модуль 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 Set_keys 19436 Get_keys 24888 Del_keys 23627 Redis Tarantool Set_keys 31390 19436 Get_keys 37245 24888 Del_keys 38158 23627  Redis Tarantool med p(90) p(95) med p(90) p(95) Set_keys 2.31ms 6.5ms 8.62ms 4.35ms 8.34ms 11ms Get_keys 2.01ms 6.01ms 7.05ms 3.4ms 6.16ms 8.69ms Del_keys 1.91ms 5.06ms 6.89ms 3.65ms 6.5ms 8.73ms При запуске в режиме кластера Redis выигрывает. Имеет важные преимущества. Он популярнее и как следствие, имеет большее комьюнити. В интернете представлено больше информации по вопросам использования Redis, следовательно, у технологии более низкий порог входа. В основном Redis используется для реализации кеширования, и он хорошо подходит для этой роли: например, в первом сценарии он лишь незначительно уступил Tarantool.  Если требуется полноценное решение для кеширования или хранения данных и взаимодействия с ними, которое можно использовать в качестве основной БД, рекомендуем присмотреться к Tarantool. Он ближе к привычной табличной организации данных, потому что поддерживает реляционную модель и запросы на SQL. При этом в большинстве случаев он способен выдерживать нагрузку, сравнимую с K-V БД вроде Redis. Tarantool показал себя лучше под нагрузкой в сценариях 1, 4, 5: у него меньше время ответа, он держит большее количество RPS, в нем из коробки реализованы вторичные индексы. В сценарии 3 Tarantool и Redis проявили себя одинаково. В результате Tarantool: Немного быстрее работает в режиме key-value и при использовании вторичных индексов Быстрее работает в режиме полной персистентности Рассмотрим эти преимущества подробнее. Вторичные индексы часто используются при проектировании структуры базы данных. В случае Tarantool это позволяет производить поиск не только по ключам, но и по значениям.  Например: у нас имеется таблица вида «табельный номер — ФИО сотрудника», где табельный номер является ключом.  В Tarantool при создании вторичного индекса появляется возможность производить поиск не только по табельному номеру, но и по ФИО, что даёт возможность узнать табельный номер конкретного сотрудника В Redis тоже есть такая возможность, но для этого необходимо устанавливать модуль RediSearch. При этом производительность решения будет уступать Tarantool Tarantool показывает большую производительность при сбросе данных на диск в режимах wal_mode=write и wal_mode=fsync — в сравнении с Redis с параметром appendfsync=everysec и appendfsync=always соответственно.  Почему это важно: эти режимы нужны для возможности восстановления данных в случае сбоя. Все операции сохраняются в специальный файл, и в случае неисправности их можно воспроизвести и не потерять данные. Разница между режимами выше — в частоте записи в файл. В режиме полной персистентности, когда операции записываются в файл сразу после их выполнения  с wal_mode=fsync, Tarantool выигрывает у Redis. Это дает возможность выдерживать большую нагрузку при максимальной сохранности данных. Tarantool во многих сценариях показал лучшее или такое же быстродействие по сравнению с Redis. Tarantool можно использовать как в качестве основного хранилища данных, так и для реализации кеширования. Исходный код тестов для К6 можно посмотреть в репозитории.