В условиях стремительного роста объемов данных и интенсивных нагрузок современные распределенные базы данных сталкиваются с рядом уникальных вызовов, связанных с производительностью и надежностью. Одним из наиболее важных показателей эффективности таких систем является задержка записи — параметр, напрямую влияющий на качество пользовательского опыта, устойчивость приложений и общую способность инфраструктуры обрабатывать масштабируемые рабочие нагрузки. Решение этой задачи требует глубокого понимания внутреннего устройства системы и тщательной оптимизации на уровне хранения данных. В этой статье мы подробно рассмотрим путь TiKV — одного из ключевых компонентов экосистемы TiDB — к снижению задержек записи и достижению плавной производительности даже при экстремальных нагрузках и масштабировании. TiKV выполняет роль распределенного движка ключ-значение, который выступает базисом для транзакционных нагрузок в распределенной СУБД TiDB.
Архитектура TiKV отделяет вычислительный слой от слоя хранения, что позволяет гибко масштабировать систему под разнообразные задачи и нагрузки. В этом хранении базовым элементом выступает RocksDB — высокопроизводительный движок на основе лог-структурированного дерева слияния (LSM-tree). При обработке больших объемов данных, например, во время миграций регионов (логических шардов данных) или масштабирования кластера, TiKV применяет метод IngestExternalFile(), который позволяет напрямую импортировать отсортированные таблицы SST-файлов в хранилище, минуя обычный путь записи. Это снижает нагрузку на память и уменьшает сборку мусора, что теоретически ускоряет процесс загрузки данных. Однако за видимой эффективностью скрывалась одна проблема.
Чтобы обеспечить согласованность последовательных номеров версий (sequence numbers) в RocksDB и избежать несовместимостей данных при чтении, процесс инжеста SST-файлов подразумевает временную приостановку обычных операций записи — так называемый write stall. Незначительная временная пауза в изоляции могла бы пройти незамеченной, но поскольку все регионы на одном узле TiKV используют один экземпляр RocksDB, пауза, запущенная одним регионом, блокировала операции записи во всех остальных. Особенно ярко эффект проявлялся при крупных миграциях и масштабировании, когда множество регионов одновременно участвовали в манипуляциях с данными, вызывая заметные всплески задержек записи, что снижало производительность и порождало нестабильность. Ключевой момент проблемы — строжайшие требования RocksDB к нарушению последовательности версий в LSM-структуре. Новые SST-файлы должны иметь номера последовательности, строго следующие за существующими записями.
Для этого, перед инжестом, если входящие данные пересекаются с теми, что еще существуют в MemTable (буффере записи), система сначала должна их сбросить (flush) в нижний уровень LSM, что активно потребляет ресурсы и еще больше удлиняет write stall. Усилия команды TiKV были направлены на решение этой тонкой технической задачи — как ускорить процесс, сохранив целостность данных и надежность работы. Первая и значимая оптимизация состояла в применении функции allow_blocking_flush в RocksDB. Раньше при необходимости сброса MemTable происходила пауза всей системы на выдерживание вовлеченного ввода-вывода. Новый подход пытался изначально выполнить инжест SST с запретом на блокирующий flush.
Если операция проходила без сбоев, задержка не возникала. В случае если flush был необходим, TiKV выносил его за грани write stall — сбрасывал MemTable асинхронно, не блокируя другие операции. После этого повторный инжест проводился при разрешенном flush, выполняясь быстро и без последующих пауз. Этот подход позволил сократить длительность write stall в худших случаях в сотни раз, обеспечив ощутимые улучшения в масштабируемости и реакции системы. Однако даже после столь значительного снижения временных задержек команда TiKV стремилась к полной ликвидации write stall.
Для этого необходимо было понять, могут ли вообще возникать факторы, требующие приостановки записи. Анализ показал, что благодаря использованию протокола консенсуса Raft для каждой области данных — Region — записи происходят строго последовательным образом, при этом один поток пишет в конкретный регион, что технически исключает взаимные конфликты при записи SST-файлов. Тем не менее оставалась исключительная ситуация, связанная с процедурой очистки устаревших данных MVCC (мультиверсии управления конкуренцией) при помощи compaction filter в RocksDB. Эта операция, выполняемая вне контроля Raft, инициирует дополнительные записи удаления ключей, что может пересекаться с инжестом и создавать условия гонки. Решением стал механизм allow_write — новая функциональность RocksDB, позволяющая проводить инжест без блокировки операций записи, при условии принятия ответственности за предотвращение конфликтов на уровне самой системы.
В TiKV для обеспечения безопасности этого процесса была внедрена система range latches — блокировок на ключевые диапазоны. Перед началом инжеста или очистки происходит захват диапазона ключей, что исключает любые пересечения операций записи и позволяет безопасно проводить инжест в режиме allow_write, полностью устраняя write stall. Реальные результаты подтверждают эффективность оптимизаций. В тестах TPCC, имитирующих нагрузки электронной коммерции, время ожидания потоков записи в пиковых 0.01% случаев сокращалось более чем на 90%, с 25 миллисекунд до 2.
Задержка записи на уровне 99-го процентиля падала вдвое, становясь стабильной и предсказуемой даже под высокой нагрузкой. Это открывает новые горизонты для использования TiKV в масштабных и требовательных приложениях. Заключение данного пути оптимизации демонстрирует, что решение глубоко технической, казалось бы узкой задачи может привести к мощным улучшениям всей распределенной базы. Понимание взаимодействия RocksDB и Raft, тщательная работа над устранением нежелательных пауз и нововведения на уровне хранения данных легли в основу значимого прорыва в снижении задержек записи TiKV. Эти разработки не только улучшают качество и стабильность работы самой TiKV и TiDB, но и служат ценным опытом для специалистов, работающих с высоконагруженными распределенными системами.
Оптимизации доступны в открытом исходном коде, предоставляя возможность интегрировать передовые решения в свои проекты и добиваться высокоуровневой предсказуемой производительности. Команда TiKV продолжает исследовать пути повышения эффективности, и приглашает инженеров и разработчиков к диалогу и обмену опытом через различные сообщества и каналы связи. Путь к созданию надежной и высокопроизводительной распределенной базы данных — это постоянное совершенствование, комбинирование теории и практики, и стремление создавать инструменты, которые помогают строить будущее данных без компромиссов.