Открыть сервис

FlatBuffers

FlatBuffers — это кроссплатформенная библиотека сериализации данных с открытым исходным кодом, разработанная компанией Google. Она предназначена для эффективного бинарного представления структурированных данных, обеспечивая прямой доступ к данным без этапа парсинга (распаковки) и с минимальными накладными расходами на память. FlatBuffers относится к классу форматов сериализации, таких как Protocol Buffers (protobuf) или Apache Thrift, но отличается от них своей архитектурой, ориентированной на максимальную производительность чтения и низкое потребление оперативной памяти.

История

Разработка FlatBuffers была начата в компании Google как внутренний проект для решения проблем, связанных с производительностью и загрузкой игровых ресурсов. Основной целью было создание формата, который позволял бы загружать большие объёмы данных (например, 3D-модели, текстуры, конфигурации уровней) без затрат времени на парсинг и с возможностью использования данных непосредственно из буфера памяти. В 2014 году проект был опубликован как открытый (под лицензией Apache 2.0) и размещён на GitHub. Первая стабильная версия (1.0) вышла в 2015 году. С тех пор FlatBuffers активно развивается, поддерживается сообществом и используется в ряде проектов Google, включая игровой движок Google Play Games и некоторые компоненты Android.

Архитектура и принцип работы

Сериализация без парсинга

Ключевая особенность FlatBuffers — это возможность чтения данных напрямую из бинарного буфера, не требуя предварительного разбора (десериализации) в объекты языка программирования. Это достигается за счёт того, что буфер содержит все необходимые смещения (указатели) на поля и вложенные структуры в самом начале. При обращении к полю программа вычисляет его адрес в памяти относительно начала буфера, используя эти смещения, и читает значение напрямую. Это кардинально ускоряет загрузку данных по сравнению с форматами, требующими полного парсинга (например, JSON или XML).

Схема данных (Schema)

Данные в FlatBuffers описываются с помощью специального языка описания схем (IDL — Interface Definition Language). Схема определяет структуру данных (таблицы, структуры, перечисления) и их типы. Пример схемы:

`` table Monster { name: string; hp: short; mana: short = 150; pos: Vec3; inventory: [ubyte]; } ``

Схема компилируется специальным компилятором (flatc) в код на целевом языке программирования (C++, C#, Go, Java, JavaScript, TypeScript, Python, Rust, Swift, Lua и другие). Сгенерированный код предоставляет функции для построения (сериализации) и чтения данных.

Бинарный формат

Бинарный формат FlatBuffers выровнен по границам, что делает его эффективным для чтения на современных процессорах. Он использует прямой порядок байтов (little-endian) по умолчанию, но поддерживает и обратный. Внутренняя структура буфера включает:

  • Заголовок: содержит указатель на корневой объект.
  • Таблицы (Tables): основной тип данных. Таблицы содержат поля, которые могут быть необязательными (vtable — таблица виртуальных смещений). Каждое поле имеет свой идентификатор и смещение относительно начала таблицы. Это позволяет добавлять новые поля в схему без нарушения обратной совместимости.
  • Структуры (Structs): компактные, фиксированного размера блоки данных, хранящиеся встроенными в таблицы или другие структуры. Все поля структур обязательны.
  • Векторы (Vectors): массивы элементов одного типа.
  • Строки (Strings): хранятся как векторы байтов с завершающим нулём.
  • Смещения (Offsets): 32-битные или 64-битные указатели на другие объекты в буфере.

Сборка мусора и управление памятью

FlatBuffers не управляет памятью автоматически. После создания буфера он может быть передан в виде массива байтов, и его содержимое остаётся валидным, пока существует сам буфер. Освобождение памяти возлагается на пользователя. Это делает FlatBuffers подходящим для сред с ограниченными ресурсами (например, встраиваемые системы, игровые консоли).

Классификация и сравнение

FlatBuffers vs Protocol Buffers (protobuf)

  • Производительность чтения: FlatBuffers значительно быстрее при чтении, так как не требует парсинга. Protocol Buffers требует десериализации в объекты, что занимает время и память.
  • Размер буфера: FlatBuffers обычно компактнее protobuf, особенно для данных с большим количеством повторяющихся структур, так как он хранит данные в выровненном виде без дополнительных заголовков.
  • Гибкость: Protocol Buffers поддерживает больше типов данных (например, карты, oneof) и более сложные схемы. FlatBuffers проще и ориентирован на более плоские структуры.
  • Поддержка языков: Protocol Buffers имеет более широкую поддержку языков программирования, но FlatBuffers также покрывает основные платформы.

FlatBuffers vs JSON

  • Размер: FlatBuffers значительно компактнее JSON (в 2–5 раз и более), так как использует бинарное представление и не хранит ключи полей.
  • Скорость: FlatBuffers на порядки быстрее при чтении и записи, особенно для больших объёмов данных.
  • Человекочитаемость: JSON легко читается и редактируется человеком, FlatBuffers — нет. Для отладки FlatBuffers требуется специальный инструмент (flatc --json).
  • Совместимость: JSON является универсальным текстовым форматом, в то время как FlatBuffers требует предварительного определения схемы и компиляции.

Применение

FlatBuffers нашёл широкое применение в областях, где критичны производительность и низкое потребление памяти:

  • Игровая индустрия: загрузка игровых ресурсов (модели, анимации, текстуры, конфигурации уровней) без задержек на парсинг. Используется в игровых движках, таких как Unity (через плагины) и Unreal Engine.
  • Мобильные приложения: для хранения и передачи конфигураций, данных о пользователе, кэширования. Используется в Android (например, в Google Play Games).
  • Встраиваемые системы: для хранения данных на устройствах с ограниченной памятью и процессорной мощностью (микроконтроллеры, IoT-устройства).
  • Сетевые протоколы: для передачи данных в реальном времени (например, в многопользовательских онлайн-играх, финансовых системах), где низкая задержка критична.
  • Научные вычисления: для хранения и обмена большими наборами данных (например, результаты симуляций, данные с датчиков).

Пример использования

Ниже приведён упрощённый пример использования FlatBuffers на языке C++:

  1. Определение схемы (monster.fbs):

`` table Monster { name: string; hp: short; } root_type Monster; ``

  1. Компиляция схемы:

``bash flatc --cpp monster.fbs ``

  1. Создание буфера:

```cpp

include "monster_generated.h"

flatbuffers::FlatBufferBuilder builder; auto name = builder.CreateString("Orc"); auto monster = CreateMonster(builder, name, 100); builder.Finish(monster); uint8_t *buf = builder.GetBufferPointer(); size_t size = builder.GetSize(); ```

  1. Чтение из буфера:

``cpp auto monster = GetMonster(buf); std::cout << "Name: " << monster->name()->c_str() << std::endl; std::cout << "HP: " << monster->hp() << std::endl; ``

Инструменты и экосистема

  • Компилятор flatc: основной инструмент для генерации кода из схем. Поддерживает множество языков.
  • Библиотеки времени выполнения (runtime): предоставляются для каждого поддерживаемого языка и содержат классы для построения и чтения буферов.
  • Инструмент flatc --json: позволяет конвертировать бинарные FlatBuffers в читаемый JSON и обратно.
  • Плагины для IDE: существуют плагины для Visual Studio Code, CLion и других редакторов, обеспечивающие подсветку синтаксиса схем и автодополнение.

Критика и ограничения

  • Сложность отладки: бинарный формат нечитаем для человека, что затрудняет отладку без специальных инструментов.
  • Необходимость схемы: для использования FlatBuffers требуется предварительное определение схемы, что делает его менее гибким по сравнению с JSON или XML.
  • Отсутствие сжатия: FlatBuffers не сжимает данные. Для уменьшения размера буфера требуется внешнее сжатие (например, zlib).
  • Ограниченная поддержка динамических структур: FlatBuffers не предназначен для работы с данными, структура которых неизвестна на этапе компиляции.
  • Потенциальные проблемы с безопасностью: при чтении из непроверенного источника возможны атаки, связанные с некорректными смещениями (например, чтение за пределами буфера). Разработчики должны реализовывать проверки.

Источники

  • Официальная документация FlatBuffers на сайте Google.
  • Репозиторий проекта на GitHub.
  • Статья «FlatBuffers: A Memory-Efficient Serialization Library» в блоге Google.
  • Сравнительный анализ форматов сериализации (Protocol Buffers, FlatBuffers, Cap'n Proto) в технической литературе.

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →