
Что такое RocksDB? Встраиваемое хранилище «ключ — значение»
RocksDB — одна из самых распространенных систем хранения данных, хотя почти никто не настраивает ее напрямую. Она лежит в основе Kafka, MySQL через MyRocks, TiDB, YugabyteDB, Ceph и реестров подавляющего большинства валидаторов Solana.
Удивительно, но о столь критически важной системе написано крайне мало.
Официальная документация отлично подходит в качестве справочника, но плохо — для первого знакомства. Большинство других объяснений предполагают, что у читателя уже есть базовые знания, например о том, что такое LSM-дерево.
Это первая статья из серии о внутреннем устройстве RocksDB. Начнем с очевидного вопроса.
Что такое RocksDB?
RocksDB — встраиваемое персистентное хранилище «ключ — значение», оптимизированное для быстрой работы с данными. Оно принимает ключи и значения в виде произвольных массивов байтов, сортирует их и надежно сохраняет на диске.
Главное, что нужно сразу понять: RocksDB — это библиотека, а не сервер. Здесь нет процесса, к которому нужно подключаться, порта, который нужно открывать, или языка запросов, который нужно изучать.
RocksDB интегрируется в приложение и работает внутри его процесса, читая и записывая файлы на локальном диске. Именно поэтому RocksDB работает быстро: между кодом приложения и обрабатываемыми данными нет сетевого перехода. Система остается минималистичной, поскольку намеренно оставляет репликацию, шардинг и выполнение запросов решениям, построенным поверх нее.
Проще говоря, RocksDB — это движок хранения, вокруг которого построены такие базы данных, как TiDB и YugabyteDB.
RocksDB и LevelDB — это одно и то же?
Нет, но они происходят из одной кодовой базы. RocksDB появилась в 2012 году как форк LevelDB — легковесного хранилища «ключ — значение», созданного в Google Jeff Dean и Sanjay Ghemawat.
LevelDB создавалась для сред с умеренными нагрузками, например для бэкенда IndexedDB в браузере или отдельного встраиваемого устройства. Поэтому в ее архитектуре были приняты соответствующие решения: однопоточное уплотнение, экономное использование памяти и минимум возможностей для тонкой настройки.
Инженеры Facebook, ныне Meta, взяли эту основу и переработали ее для серверных нагрузок. Их задачей было полностью задействовать возможности современного оборудования при постоянном потоке записи и объемах данных, значительно превышающих доступную память.
В 2013 году исходный код RocksDB стал открытым. С тех пор система значительно отошла от LevelDB и получила многопоточное уплотнение, семейства столбцов, транзакции, резервное копирование, операторы слияния, подключаемые стратегии уплотнения и знаменитый длинный список параметров настройки.
Между LevelDB и RocksDB заметно семейное сходство, но считать их взаимозаменяемыми стало неразумно еще десять лет назад.
Как работает RocksDB?
RocksDB построена на основе лог-структурированного дерева слияния (LSM-дерева) — структуры данных, которая жертвует простотой чтения ради высокой пропускной способности записи.
Поступающие записи сначала сохраняются в буфере в памяти — memtable. Одновременно они добавляются в журнал упреждающей записи на диске, что обеспечивает надежность хранения.
Когда memtable заполняется, она замораживается и сбрасывается на диск в виде неизменяемого отсортированного файла — Sorted String Table (SST). SST-файлы накапливаются в многоуровневой иерархии, а фоновый процесс под названием уплотнение постоянно объединяет их, удаляя перезаписанные значения и удаленные ключи. В результате структура остается упорядоченной, отсортированной и надежно сохраненной.
При чтении RocksDB сначала проверяет memtable, а затем последовательно просматривает уровни SST-файлов. Фильтры Блума позволяют пропускать файлы, в которых искомого ключа точно нет, а блочный кеш хранит часто используемые данные в памяти. Поэтому для большинства операций чтения достаточно обратиться лишь к одному или двум файлам.
Чем LSM-деревья отличаются от B-деревьев?
B-деревья, которые используются в большинстве традиционных баз данных, обновляют данные на месте. Поэтому случайные операции записи распределяются по всему диску. LSM-деревья добавляют и группируют данные, создавая крупные последовательные операции записи — именно то, что требуется SSD и системам с интенсивным приемом данных. Компромисс в том, что актуальное значение ключа может находиться в нескольких файлах. Чтобы ограничить последствия этого компромисса, нужны уплотнение, фильтры Блума и кеширование.
Каждое архитектурное решение в LSM-дереве в конечном счете сводится к балансу трех факторов:
- Амплификация записи
- Амплификация чтения
- Амплификация пространства
Улучшение любых двух показателей обычно ухудшает третий.
Этот треугольник — важнейшая ментальная модель для понимания настройки RocksDB.
Для чего используется RocksDB?
RocksDB используют, когда приложению требуется быстрое, надежное и упорядоченное локальное хранилище «ключ — значение» без накладных расходов на отдельный сервер базы данных. Конкретные примеры объясняют этот паттерн лучше, чем общие категории.
Kafka Streams хранит состояние каждой задачи обработки — текущие агрегации, соединения и оконные вычисления — в локальном хранилище RocksDB. Благодаря этому состояние может превышать объем памяти и сохраняться после перезапуска, а для каждого поиска не требуется дополнительный сетевой запрос.
Система Meta ZippyDB дополняет RocksDB уровнем репликации, управлением шардами и сервисами конфигурации, чтобы предоставить полностью управляемое распределенное хранилище «ключ — значение». Задачи четко разделены: RocksDB отвечает за хранение, а вся серверная инфраструктура строится вокруг нее.
Уровень хранения TiDB запускает RocksDB на каждой ноде как движок распределенной SQL-базы данных. Структура таблиц кодируется в префиксах ключей, поэтому сканирование таблицы превращается в одно непрерывное чтение отсортированных ключей.
Каждый валидатор Solana на базе Agave записывает реестр в RocksDB, используя слот в качестве ключа. Поэтому последовательные данные реестра располагаются на диске рядом.
Последние два примера интересны тем, что ключи хранятся в отсортированном порядке — по байтам по умолчанию или с помощью пользовательского компаратора. Это делает сканирование диапазонов и поиск по префиксам эффективными.
Значительная часть проектирования реальных схем в системах на базе RocksDB сводится к использованию этого порядка.
Кто использует RocksDB?
Помимо перечисленных выше систем, RocksDB лежит в основе любых решений, которым нужен встраиваемый, проверенный в реальных условиях и оптимизированный для записи движок хранения. Команды выбирают RocksDB, потому что получают результат более чем десятилетней эксплуатации и закалки системы в Meta, а не создают движок с нуля.
В частности:
- Kafka Streams использует RocksDB как стандартный движок хранилищ состояния
- Apache Flink предлагает бэкенд состояния RocksDB для состояния с контрольными точками, которое не помещается в памяти
- MyRocks встраивает RocksDB как движок хранения MySQL. Он был разработан в Meta, чтобы уменьшить объем хранилища в некоторых крупнейших существующих кластерах MySQL
- Уровень хранения TiDB, TiKV, использует отдельные экземпляры RocksDB для журналов Raft и данных «ключ — значение»
- Хранилище документов YugabyteDB, DocDB, использует RocksDB
- BlueStore в Ceph использует RocksDB для метаданных объектного хранилища
- Начиная с версии 3.4 ArangoDB поставляет RocksDB как стандартный движок хранения, а с версии 3.7 — как единственный движок
RocksDB преимущественно используется на SSD в нагрузках с интенсивной записью и объемом данных, превышающим доступную память. К этому вопросу мы вернемся далее в статье.
Как Solana использует RocksDB?
Solana — высокопроизводительный блокчейн с низкой задержкой на основе Proof of Stake, известный своим акцентом на скорости, эффективности и пользовательских приложениях. Реестр Solana хранится в RocksDB. Клиент валидатора Agave сохраняет его в Blockstore — компоненте с базой данных RocksDB, разделенной на независимые настраиваемые пространства ключей.
Отдельные семейства столбцов хранят данные шредов и коды исправления ошибок шредов, то есть исходные единицы данных реестра в том виде, в котором они поступают по сети, а также статусы транзакций, индексы соответствия адресов и подписей и различные метаданные.
Паттерн записи валидатора экстремален по сравнению с большинством нагрузок баз данных. Валидатор должен непрерывно принимать шреды на линейной скорости сети, используя в качестве ключей почти монотонно возрастающие номера слотов, и делать это всегда. Полный архив реестра без очистки значительно превышает сотни терабайт и ежегодно увеличивается как минимум на десятки терабайт.
При многоуровневом уплотнении семейства столбцов шредов создавали настолько большую фоновую нагрузку, что валидаторы начали сталкиваться с приостановкой записи. Это встроенный механизм RocksDB, который замедляет прием данных, когда уплотнение не успевает за записью.
Примерно в 2021 году семейства столбцов шредов перевели на уплотнение FIFO — минималистичную стратегию, при которой после достижения лимита размера просто удаляется самый старый файл. Обычно FIFO небезопасно для нагрузок общего назначения. Однако ключи шредов поступают почти в монотонном порядке слотов, поэтому валидаторы могли удалять самый старый файл, содержащий самые старые слоты. Стратегия уплотнения почти идеально соответствовала характеру нагрузки.
Последующие оптимизации многоуровневого уплотнения снизили амплификацию ввода-вывода настолько, что FIFO перестало давать преимущества. Поэтому путь FIFO объявили устаревшим в июне 2024 года, а в ноябре того же года удалили.
Firedancer, написанный на C клиент валидатора Solana от Jump Crypto, полностью отказывается от RocksDB в пользу специализированного внутреннего уровня хранения.
Гибридный клиент Frankendancer по-прежнему использует Agave RocksDB Blockstore, а формат каталога реестра остается совместимым с RocksDB. Поэтому операторы могут переходить между клиентами без повторной синхронизации.
Сможет ли созданный с нуля движок хранения превзойти результаты десятилетия доработок и настройки RocksDB — интересный открытый вопрос в разработке валидаторов.
Когда RocksDB не подходит?
RocksDB оказывается неподходящим инструментом чаще, чем можно предположить по ее распространенности. Возможности настройки огромны: система предлагает сотни параметров с неочевидным взаимодействием. Поэтому ошибочная настройка — скорее правило, чем исключение.
Кроме того, стандартные настройки RocksDB разумны, но не оптимальны. Чтобы добиться реального прироста производительности, разработчикам нужно понимать описанные выше компромиссы амплификации. Продолжительный интенсивный прием данных может обогнать фоновое уплотнение и вызвать приостановки записи, которые обычно происходят в моменты максимальной нагрузки на систему.
Более того, RocksDB — библиотека, а не сервер. Все функции типичного сервера базы данных, включая репликацию, шардинг, резервное копирование, контроль доступа, уровень запросов и операционные инструменты, необходимо создавать отдельно.
Характер нагрузки также имеет огромное значение.
RocksDB — это строчно-ориентированный движок для точечного поиска и сканирования диапазонов. Для аналитических нагрузок, которые сканируют большие объемы данных и выполняют агрегацию по столбцам, лучше подходит колоночное хранилище, такое как ClickHouse.
Все это не означает, что RocksDB следует избегать. Но выбирать ее нужно осознанно. В Helius мы напрямую оценили эти риски при перепроектировании нашего архивного уровня и все равно выбрали RocksDB, поскольку характер нагрузки точно соответствовал задачам, для которых она создавалась: точечный поиск и узкое сканирование диапазонов в большом наборе данных с преобладанием операций добавления.
Заключение
RocksDB — встраиваемое персистентное отсортированное хранилище «ключ — значение», которое жертвует удобством эксплуатации ради максимальной производительности на локальном диске. Оно возникло на основе LevelDB, прошло закалку в Meta для работы с SSD и многоядерными системами, а сегодня используется в самых разных решениях по всему миру: от обработчиков потоков и распределенных SQL-баз данных до кластеров хранения и реестра Solana.
Если вам интересно работать над высокопроизводительными конфигурациями RocksDB в большом масштабе, присоединяйтесь к нашей команде.
Solana стремится стать расчетным уровнем для глобальных финансов, а ее базовая инфраструктура работает на тех самых механизмах, которым посвящена эта серия. Решайте сложные системные задачи на одном из лучших доступных оборудований в планетарном масштабе.
Мы расширяем инженерную команду. Все открытые вакансии доступны на helius.dev/careers.
Похожие статьи
Подпишитесь на Helius
Следите за новостями разработки на Solana и получайте уведомления о наших публикациях


