Теперь, когда мы знаем компоненты (MemTable, WAL, SSTable), давай проследим, что происходит, когда твой код делает запись и чтение.
Операция WRITE
Секрет феноменальной скорости LSM кроется в отсутствии случайных дисковых операций во время записи.
- Когда приходит запрос на запись, база делает ровно два действия: дописывает лог в WAL (O(1) для диска) и обновляет дерево в MemTable (O(log N) в памяти).
- Всё! Клиент мгновенно получает ответ «ОК». База не ждет, пока перестроятся индексы на диске, как это делает B+ Tree.
- Дальнейший перенос данных из переполненной MemTable в SSTable (Flush) происходит асинхронно, в фоновом потоке, вообще не блокируя новые входящие записи.
Операция READ
Если запись в LSM бесплатна, то чтение — это расплата. Поскольку данные постоянно сбрасываются в новые SSTable файлы, база не знает точно, в каком именно файле лежит нужный ключ. Ей приходится искать его по слоям.
- RAM-кэши: Сначала ищем в активной MemTable. Если нет — в замороженной MemTable. Если нет — в Block Cache (это кэш горячих блоков диска в оперативной памяти). Если попали сюда — нам повезло (Cache Hit).
- Поиск по диску: Если в памяти ключа нет, базе придется проверять файлы SSTable на диске, начиная с самых свежих (Level 0) и спускаясь к самым старым (Level N).
Но подожди, читать каждый файл на диске — это же самоубийство для производительности!
Именно поэтому в LSM-деревьях используется гениальная структура данных — Bloom Filter (Фильтр Блума).
Магия Bloom Filter
Bloom Filter — это очень компактная структура в оперативной памяти (хэш-таблица битов), которая привязана к каждому файлу SSTable. У нее есть только одна задача: экономить обращения к диску.
Когда база хочет проверить SSTable на наличие ключа, она сначала спрашивает Bloom Filter. Он может дать только два ответа:
- «Точно НЕТ»: Фильтр гарантирует, что ключа в файле нет. База пропускает этот файл и не трогает медленный диск.
- «Возможно ДА»: Фильтр говорит, что ключ скорее всего есть (бывают ложноположительные срабатывания). Только тогда база лезет на диск, читает индекс блока и достает сами данные.
Да, в LSM-дереве один ключ часто «прыгает» через 1–2 уровня при чтении. Но в OLTP-системах, где доминирует запись (write-heavy), феноменальная скорость вставки полностью перекрывает эти затраты на поиск.