Представление "Позитивных таблиц" – нового C/C++ движка, выполняющего до полумиллиона пишущих транзакций в секунду к табличным и key-value данным, и одновременно до миллиона читающих запросов на каждом ядре процессора.
libfpta обеспечивает полностью параллельно выполнение запросов чтения/поиска без блокировок внутри БД и без атомарных операций, а также реализует эффективное хранение multi-value значений. Поэтому интегрально libfpta опережает по производительности и Tarantool и RocksDB. А разница с такими "быстрыми" решениями как Hazelcast или Apache Ignite достигает иногда 10-ти и более раз.
Highload++2013: TopGun - архитектура терабитной платформы DPI
libfpta: в памяти, с персистентностью, быстрее хайпа
1. libfpta:
– в памяти
– с персистентностью
– быстрее хайпа
Леонид Юрьев
Advanced Research @ Positive Technologies
Алексей Копытов
Эксперт @ Голос Разума
3. libfpta: Постановка задачи
Локально, DATA < RAM
– один нагруженный сервер
– несколько читателей и 2-3 процесса-писателя
Быстро
– если медленно, то не нужно
Долговечность иногда не важна
– при аварии питания данные устаревают
Высокая готовность
– минимальное время восстановления
– падение не должно ломать или прятать данные
4. Позитивные таблицы
1. Обзор
2. Варианты использования: Целевой и Неправильный
3. Плюсы
4. Минусы
5. Планы
6. Чем не устроили: Ignite, Tarantool, SQLite, RocksDB…
5. libfpta – Движок хранения
Компактная библиотека с лицензией LGPL
libfpta = libmdbx (key-value) + libfptu (tuples) + t1ha (hash)
Таблицы с «утиной» схемой, всяческие индексы
Экстремально быстрый, но без WAL (пока)
Похожий, но Иной
6. libfpta: 80% как у всех
1. Набор таблиц с колонкам и индексами
2. Машинные типы, дата-время, строки, NULL…
3. Курсоры
4. BREAD
5. Рой процессов
6. Пока отсутствуют: FOREIGN KEYs, JOINs
Внутри транзакций
чтения/записи
7. libfpta: Внутри
Данные отображены в RAM
– B+Tree, не LSM
– ACID* поверх MVCC
– MVCC посредством COW на уровне страниц
Key-value, кортежи, список таблиц, список колонок…
– нет имен, только дайджесты t1ha
Предельно эффективно для машины
– считаем кэш-линии и такты
– ничего лишнего или неэффективного
8. libfpta: Не подойдет
Много «апдейтов» и
– нельзя потерять при аварии питания
– допустим простой при восстановлении
= показан WAL
READ < WRITE && RAM < DATA
= показан LSM
9. libfpta: Идеально
Требуется предельная производительность
– ACID для локальной группы процессов
– с выборкой диапазонов и курсорами
Не нужен WAL
– требуется минимальное время простоя
– допустимо потерять «хвост» при аварии
( при kill -9 ничего не потеряется )
– диск терпит WAF от апдейтов
READ > WRITE || RAM > DATA
– иначе LSM даст больше
10. libfpta: Скорость
READ / GET
𝑂 log(𝑁) = поиск в B+tree
Как std::map или чуть
быстрее (за счет локальности)
На каждом CPU
без блокировок в БД
Подкачка если DATA > RAM
WRITE / UPSERT
𝑂 log(𝑁) = Изменение B+tree
Копирование страниц по
высоте дерева
Транзакции строго
последовательны
Фиксация на диске
12. libfpta: «Утиная» схема
Записи являются кортежами
Схема задает минимальный набор
Полей может быть больше…
Для «лишних» полей
– машинный тип
– числовой тэг (до 1000)
– будет: справочник схемы
Дополнительные
полу-структурированные
данные
13. libfpta: Кортежи
Реализованы в libfptu:
– похожи на BSON и MessagePack
– без сжатия
– поддерживаются коллекции (repeated в ProtoBuf)
– в заголовке есть «индекс»
– предельно удобны для машины
– подключаемый словарь схемы (будет, вместе с JSON)
– могут быть вложенным
– предусмотрены массивы
14. libfpta: Дубликаты
Дубликаты – это multi-value
– во вложенных деревьях
– ключи не дублируются
– значения отсортированы
– курсоры могут ходить по «дубликатам»
– быстрый поиск и позиционирование
15. libfpta: Конкуренция
Один писатель
– Один разделяемый мьютекс (1)
– Изменения всегда последовательны
Много читателей
– Подключение/отключение под вторым мьютексом (2)
– Выполнение без блокировок внутри БД
Временно
– Изменение схемы под мьютексом внутри процесса (3)
16. libfpta: Индексы
Составные
– по совокупному значению колонок
Неупорядоченные
– хэши t1ha вместо значений, требуют меньше места
Реверсивные
– ключи сравниваются с конца, хорошо для доменов
Функциональные / Пользовательские (обдумываем)
– как генераторы ключей, не компараторы
– collate/uppercase
17. libfpta: Немного деталей
Первичный индекс есть всегда
Нет RowID
– есть последовательности
– будет auto (эмуляция RowID)
Вторичные индекс через PK
– как в MySQL, НЕ как в PostgreSQL
– требуют уникальности PK
18. libfpta: Не как у людей…
Контроль уникальности
– это атрибут индекса
NULL в индексах
– заменяется на Designated NIL
– проверяется на уникальность
Триггеры
– пока не хотим, нет «сервера»
Пока отсутствуют
– Collate и Case Insensitive
– FOREIGN KEYs
– JOINs
– OPTIMIZER / REWRITER
Пока не требовалось,
но будет…
19. libfpta: Недостатки
Отсутствие WAL
– требует смены формата
Проблема долгих чтений
– требует большого рефакторинга
Наследство от LMDB
Были причины не трогать
Будем устранять
20. libfpta: WAL или NO-WAL?
Без WAL
– Большой WAF
– Медленно на HDD
+ Моментальная готовность
Тем не менее
+ OOM и kill = не проблема
+ есть LIFO для BBWC
Нам было достаточно,
но WAL скоро будет
+ Небольшой WAF
+ Быстрее на HDD
± sync/flush (всё-таки нужен…)
– Replay после аварии
21. libfpta: Планы и хотелки
libmdbx (key-value):
– Новое API
– Рефакторинг…
– Асинхронная фиксация
– Merkle Tree
– WAL
– Другая «сборка мусора»
– Вынос span-pages и
поддержка RAW-устройств
(Nexenta Edge)
libfptu (кортежи):
– поддержка справочника схемы
– (де)сериализация в JSON
– (де)сериализация в MsgPack
libfpta (всё вместе):
– поддержка python…
– «оптимизатор» запросов
– FK, JOIN, GIN…
22. libfpta: Трудности
KISS
– взвешенный аскетизм, не переинженерить, меньше ребусов
Тесты
– комбинаторная сложность
– оркестр процессов
– поведенческие паттерны
Люди
– ищем в команду
23. Apache Ignite?
Java = неустранимые накладные расходы
– не для предельной производительности
libfpta:
1) Не нужна распределённость
2) Не делает лишнего
3) В несколько раз быстрее
24. Tarantool, Aerospike, etc…?
Сеть = неустранимые накладные расходы
– системные вызовы, маршалинг, event loop
libfpta:
1) Чтение линейно масштабируется по CPU
2) Чтение без блокировок, непосредственно из RAM
3) Интегрально в несколько раз быстрее*
25. SQLite, RocksDB…?
Одна БД = Один процесс
libfpta:
1) Рой локальных процессов
2) Два разделяемых мьютекса
3) В несколько раз быстрее