Алгоритм отложенного обновления вторичных LSM индексов
в Tarantool

Докладчик:

Шпилевой Владислав Дмитриевич

План доклада

  1. B- и LSM деревья в БД
  2. Проблема нескольких LSM-индексов
  3. Существующие решения
  4. Новый алгоритм
  5. Планы

Базы данных и B-деревья

id name email salary
... ... ... ...

Таблица

name id
... ...
email id
... ...

Индекс 1

Индекс 2

SELECT WHERE name = ...

SELECT WHERE email = ...

UPDATE WHERE name = ...

Индексы - для быстрого поиска, удаления, обновления данных.

Это способ хранения и сортировки. Одни данные - много индексов, вариантов сортировок.

Вариант 1 - Б-дерево

Read/Write

balance

HDD

SSD

Баланс скорости случайных чтения/записи

Дисбаланс скорости последовательных

чтения/записи

"Бесплатные" чтения

 > 100х скорость HDD 

Случайные записи

LSM-деревья

Память

Диск

Уровень 0

Уровень 1

Уровень N

  • Версионность записей
  • Горячие данные в памяти
  • Запись на диск всегда последовательна
  • Удаление старых версий всегда последовательно

Обновление индексов

Б-дерево

LSM-дерево

INSERT OR REPLACE

DELETE

INSERT OR REPLACE

DELETE

Индекс

Индекс

Найти старую запись 

Вставить новую запись

Заменить старую запись

Запись на диск

Найти старую запись

Удалить

старую запись

Чтение диска

Вставить в нулевой уровень:

{данные, INSERT, версия}

Вставить в нулевой уровень:

{ключ, DELETE, версия}

Нет обращений к диску. Последовательная запись при сбросе уровня 0 на диск.

Проблема нескольких LSM-индексов: пример

a

b

c

d

Таблица

Вторичный индекс

Первичный индекс

INSERT (1,2,3,4)

{a=1, b=2, c=3, d=4, version=1}

{b=2, c=3, a=1, version=1}

REPLACE (1,5,6,7)

{a=1, b=2, c=3, d=4, version=1}

{a=1, b=5, c=6, d=7, version=2}

{b=2, c=3, a=1, version=1}

{b=5, c=6, a=1, version=2}

Удаление старых версий

{a=1, b=5, c=6, d=7, version=2}

{b=2, c=3, a=1, version=1}

{b=5, c=6, a=1, version=2}

Так как version 1 и 2 равны по ключу индекса:

{a=1} == {a=1}

{b=2, c=3} != {b=5, c=6}

!!!

Ошибка! Количество записей не одинаково

Проблема нескольких LSM-индексов: итог

Версионность вторичных индексов не работает

Чтение диска на каждую операцию

Старые версии данных нужно удалять из вторичных индексов сразу, из-за чего:

Отложенное обновление B-деревьев

Возможна ребалансировка при обновлении вторичных ключей

Случайная запись - не дорогая

UPDATE

Прочитать первичный индекс

Применить обновления

Разбросать по файлам

Дифференциальный

файл

Замещение старых

записей, ребалансировка

{new tuple, new tuple, ...}

Двухуровневое B-дерево и SSD

Hash LID -> {RID}

LID B-tree

LID B-tree

LID B-tree

{... tuple, tuple, tuple, tuple, tuple, tuple, tuple ...}

LID - Logical Record IDentifier

RID - Physical Row IDentifier

Версионирование на уровне приложения

Аналитика

SSD - дорого и мало

Предложенный алгоритм обновления данных

Если все вторичные индексы неуникальны, то чтение первичного нужно только для удаления мусора

Можно писать во все индексы не удаляя читая и удаляя старые записи сразу, а отложить это до слияния уровней

REPLACE - писать во все индексы как есть

DELETE - писать только в первичный индекс

Для этого можно использовать 100% актуальность первичного индекса

Предложенный алгоритм обновления данных

Рассмотрим обновление данных через REPLACE на примере таблицы:

Первичный индекс

Вторичный индекс

{1,2,3,4, version=1}

{1,5,6,7, version=2}
{1,8,9,10, version=3}

a

b

c

d

{2,3,1, version=1}

{5,6,1, version=2}

{8,9,1, version=3}

Первичный индекс объединяет LSM-уровни

Первичный индекс

{1,8,9,10, version=3}

Удаленные из первичного индекса записи можно использовать:

{1,2,3,4, version=1} и {1,5,6,7, version=2}

DELETE {2,3,1 version=1}

DELETE {5,6,1 version=2}

Вторичный индекс

{2,3,1, version=1}

{5,6,1, version=2}

{8,9,1, version=3}

Вторичный индекс объединяет LSM-уровни

Вторичный индекс

{8,9,1, version=3}

Старые версии удалены из обоих индексов без чтений диска!

Предложенный алгоритм удаления данных

Рассмотрим удаление данных на той же таблице

Первичный индекс

Вторичный индекс

{1,2,3,4, version=1}

{delete 1, version=2}

a

b

c

d

{2,3,1, version=1}

Первичный индекс объединяет LSM-уровни

Первичный индекс

{empty}

Удаленные из первичного индекса записи по dry delete можно использовать:

{1,2,3,4, version=1}

DELETE {2,3,1 version=1}

Вторичный индекс

{2,3,1, version=1}

{delete 2,3,1, version=1}

Вторичный индекс объединяет LSM-уровни

Вторичный индекс

Старые версии удалены из обоих индексов без чтений диска!

{empty}

Предложенный алгоритм поиска данных

SELECT * FROM test WHERE sk = sk1

Вторичный

индекс

Первичный

индекс

{pk1, sk1, vers. = 3}

{pk1, sk2, vers. = 4}

{pk2, sk1, vers. = 2}

{pk2, sk2, vers. = 5}

{pk3, sk1, vers. = 1}

{pk3, sk1, vers. = 1}

Результат

Реализация

TX поток

Уровни первичного индекса

Vinyl

worker

}

Слияние уровней первичного индекса

...

...

B+ деревья по вторичным ключам

Новые уровни для всех индексов

Первичный индекс

Каждый вторичный индекс

Оценки сложности

Ускорение DELETE

Ускорение REPLACE

Планы

  • Не сортировать удаляемые записи полностью в памяти
  • Не читать служебные файлы с удалениями
  • Можно расширить DELETE на уникальные индексы

Новые LSM индексы в Tarantool

By Vladislav Shpilevoy

Новые LSM индексы в Tarantool

  • 1,493