Порівняння архітектури Redis і Dragonfly
Всім привіт! Мене звати Борис і я Principal Engineer у компанії DragonflyDB. У цій статті я хочу дуже поверхово оглянути архітектуру Redis та Dragonfly.
Redis, сховище даних у пам’яті, яке є синонімом швидкості, заслужило свою репутацію завдяки блискавичній продуктивності. Але як і будь-який хороший спринтер, він чудово себе показує на коротких дистанціях. Коли перегони стають довшими, і гори даних накопичуються, Redis починає відчувати труднощі.
Горизонтальне масштабування через кластер додає рівень абстракції і вимагає деякого обмеження на розподіл ключів, що потребує складного управління. Також не завжди ефективне управління пам’яттю може спричинити раптові всплески її використання, які можуть призвести до ситуацій з нестачею пам’яті.
Ці обмеження призводять до збільшення витрат на інфраструктуру та проблем з обслуговуванням, перетворюючи початкове прискорення у довготривалу боротьбу.
Чи вас засмучують ці проблеми? Нас теж. Саме тому ми створили Dragonfly, наступне покоління сховища даних у пам’яті, створене для подолання обмежень Redis. Dragonfly зберігає швидкість, яка вам довподоби, але додає вертикальне масштабування, що потрібна для легкого оброблення великого масиву даних.
Крім того, його архітектура, ефективна з точки зору пам’яті, мінімізує всплески використання пам’яті і тримає ваші витрати на інфраструктуру під контролем.
Занурьмося трохи глибше у проблеми Redis та подивимось які інноваційні рішення, пропонує Dragonfly. Ми порівняємо та протиставимо відмінності між архітектурою Redis та Dragonfly. Швидкість важлива, але масштабованість та ефективність є ключами до перемоги у довготривалих перегонах.
Dragonfly shared-nothing архітектура проти однопотокового підходу Redis
Redis за замовчуванням є однопотоковою, event-driven системою. З таким підходом архітектура досить проста, але ця простота має свою ціну. Зі зростанням навантаження один потік стає вузьким місцем, обмежуючи продуктивність і масштабування.
Dragonfly обирає інший шлях, використовуючи багатопотокову архітектуру та підхід shared-nothing, щоб забезпечити вражаючу продуктивність і масштабованість.
Як Dragonfly досягає цього
Шардування та паралельна обробка: Dragonfly ділить усю базу даних на менші, незалежні секції, звані шардами. Кожен шард призначається окремому потоку, що дозволяє паралельну обробку запитів. Це усуває вузьке місце однопотоковості, яке обмежує Redis, дозволяючи Dragonfly обробляти значно більші навантаження.
Мінімальне блокування та синхронізація: архітектура shared-nothing мінімізує потребу в складних механізмах блокування та синхронізації, додатково підвищуючи продуктивність та знижуючи потенційні вузькі місця.
Асинхронні операції та затримка: Dragonfly не зупиняється на досягнутому. Він використовує асинхронні операції (з використанням io_uring під капотом) для завдань, як-от дисковий ввід/вивід. Це перемежовуюче виконання гарантує, що довготривалі завдання, як-от створення знімків бази, не впливають на відгук інших операцій, тримаючи систему швидкою навіть під великим навантаженням.
Абстрактний ввід/вивід та ефективні файбери: Dragonfly використовує власний фреймворк, який абстрагує операції вводу/виводу, використовуючи файбери з власним стеком для ефективного управління завданнями в кожному потоці. Це поєднання оптимізує використання ресурсів і гарантує обробку одночасних запитів без зайвих затримок.
По суті, багатопотокова архітектура Dragonfly з підходом shared-nothing та акцентом на асинхронні операції відкриває значні переваги в продуктивності та масштабованості порівняно з Redis, роблячи його привабливим вибором для вимогливих робочих навантажень.
Обробка запитів
Коли клієнт надсилає запит до Redis, система аналізує запит і формує об’єкт (використовуючи патерн команда), який містить усю відповідну інформацію. Тривалість життя цього об’єкта залежить від характеру команди: неблокуючої або блокуючої. Команди, що не блокують, обробляються негайно, тоді як команди, що блокують, виконуються Redis раз за разом, доки не будуть виконані їхні конкретні вимоги.
Dragonfly використовує транзакційну модель, яка відповідає його багатопотоковій архітектурі shared-nothing, полегшуючи асинхронну обробку запитів. Хоча цей транзакційний підхід може трохи збільшити середню затримку, поєднання асинхронних операцій та багатопотоковості значно підвищує загальну пропускну спроможність і знижує максимальну затримку.
На відміну від Redis, який послідовно обробляє команди, Dragonfly здатний виконувати кілька команд одночасно. Dragonfly оптимізує продуктивність, призупиняючи виконання файберу під час завдань доступу або модифікації даних, коли потрібно чекати на необхідні дані, тим самим знижуючи непотрібне споживання CPU на невдалі спроби.
Команди, що використовують кілька ключів, які потребують роботи через різні шарди, Dragonfly розділяє на окремі підкоманди. Кожна підкоманда містить ключі для одного відповідного шарду та виконується у відповідному потоці, а результати агрегуються та надсилаються назад клієнту.
Щоб забезпечити атомарність у багатоключових операціях, Dragonfly використовує останні наукові дослідження, конкретно алгоритм Very Lightweight Locking (VLL). Блокується кожен ключ, що бере участь у транзакції, щоб запобігти одночасному доступу. Транзакції, які намагаються отримати доступ до заблокованих ключів, ставляться в чергу, доки всі необхідні ключі не стануть доступними, забезпечуючи організоване виконання без конфліктів.
Збереження та реплікація
Безпечне створення знімків або реплікацій даних у пам’яті під час обробки одночасних записів може бути складним. Це особливо актуально для Redis, який може зіткнутися зі всплесками використання пам’яті та проблемами продуктивності під час створення знімків бази даних.
Redis використовує традиційний метод створення знімків, заснований на управлінні пам’яттю «copy-on-write», використовуючи виклик fork. Такий підхід може призвести до подвоєння використання пам’яті під час процесу, оскільки будь-яка зміна даних спричиняє копіювання сторінки пам’яті, що містить ці дані.
Відповідно під час великої кількості запитів на запис існує ймовірність, що вся використана пам’ять може бути продубльована. Такий сценарій може призвести до нестабільності системи та обмеження продуктивності, особливо в середовищах з інтенсивною активністю запису. Щоб уникнути цієї ситуації, Dragonfly використовує інший підхід з кількома ключовими особливостями:
- Версіонування: кожна клітина даних має номер версії, який збільшується з модифікаціями. При створенні знімку включаються лише клітини з номерами версій, старшими за версію знімка, забезпечуючи послідовність і уникаючи дублікатів.
- Асинхронна серіалізація: дані серіалізуються та записуються на диск асинхронно, запобігаючи блокуванню та дозволяючи одночасні записи.
- Передоновлення: оновлення спричиняє відправлення клітини даних до серіалізаційного потоку, якщо знімок активний, і клітина ще не була серіалізована, забезпечуючи збереження всіх клітин один раз.
- Без створення додаткових процесів чи потоків: Dragonfly уникає операції fork і дублювання пам’яті, результатом чого є стабільне використання пам’яті під час створення знімків.
Кластер
Redis та Dragonfly працюють однаково в режимі кластера. У режимі кластера обидві бази даних використовують підхід шардування, розподіляючи ключі між 16384 хеш-слотами. Хеш-слот ключа визначається шляхом взяття його CRC16 значення та застосування модуля 16384.
Кожен вузел кластера керує певною частиною цих хеш-слотів. Вузли Redis спілкуються один з одним за допомогою протоколу gossip, підтримуючи інформацію про стан кластера та власність на слоти. Наразі Dragonfly підтримує лише емульований режим кластера або статичні вузли кластера. Повний механізм управління кластером та міграції для Dragonfly перебуває у розробці.
Остаточна версія повинна мати наступну форму: розробляється контрольна панель, яка буде керувати всім кластером, вузли знають про конфігурацію кластера, але спілкуються лише з контрольною панеллю (деяке спілкування між вузлами можливе лише під час процесу міграції слотів).
Також потрібно додати, що режим кластера для Dragonfly є більш рідкісним випадком порівняно з Redis через можливість вертикального масштабування першого.
Висновки
Я надав базове порівняння між підходами архітектури Dragonfly та Redis, уникаючи надмірно складних деталей. Зокрема, я не заглиблювався в реалізацію хеш-таблиці Dragonfly та його більш ефективне управління пам’яттю, оскільки обговорення цих структур даних виходить за межі цієї статті. Однак, варто зазначити, що Dragonfly іноді може зменшити використання пам’яті більш ніж на 40%.
Основне, що потрібно взяти до уваги, це те, що Redis та Dragonfly мають принципово різні підходи. Основні цілі Dragonfly — не лише покращити продуктивність, але й спростити складність, підвищити ефективність використання пам’яті та знизити витрати для користувачів.
103 коментарі
Додати коментар Підписатись на коментаріВідписатись від коментарів