Apache Iceberg — это высокопроизводительный формат для огромных аналитических таблиц. В интернете есть много руководств о том, как использовать Iceberg. Этот пост немного отличается, он для тех, кому интересно узнать внутренний механизм Iceberg. В этом посте я буду использовать Spark sql для создания/вставки/удаления/обновления таблицы Iceberg в Apache Zeppelin и объясню, что происходит при каждой операции.
- Запуск Docker-контейнера Zeppelin
- Архитектура Iceberg
- Слой каталога
- Слой метаданных
- Слой данных
- Подготовка
- Скачайте jq и avro tools jar
- Настройте Spark
- Создание таблицы Iceberg
- Проверка папки таблицы
- Вставка 3 записей (S1)
- Проверка папки таблицы
- Обновление записи (S2)
- Проверьте результат после обновления
- Проверьте папку с таблицами
- Удаление записи (S3)
- Проверьте папку с таблицами
- Просмотр метаданных
- Проверить метаданные истории
- Проверить метаданные моментального снимка
- Проверить метаданные манифеста
- Проверить метаданные файла
- Резюме
- Ссылки
Запуск Docker-контейнера Zeppelin
Чтобы продемонстрировать внутренний механизм более интуитивно, я использую Apache Zeppelin для запуска всего кода примера. Вы можете легко воспроизвести то, что я сделал, с помощью Zeppelin docker. О том, как воспроизвести Spark в докере Zeppelin, вы можете прочитать в этой статье. Здесь я просто кратко описал следующие шаги:
- Шаг 1. git clone https://github.com/zjffdu/zeppelin-notebook.git
- Шаг 2. Скачать Spark 3.2.1
- Шаг 3. Выполните следующую команду для запуска докер-контейнера Zeppelin. ${zeppelin_notebook} — папка notebook, которую вы клонировали в шаге 1, ${spark_location} — папка Spark, которую вы загрузили в шаге 2.
docker run -u $(id -u) -p 8080:8080 -p 4040:4040 --rm -v
${spark_location}:/opt/spark -v
${zeppelin_notebook}:/opt/notebook -e
ZEPPELIN_NOTEBOOK_DIR=/opt/notebook -e SPARK_HOME=/opt/spark
-e ZEPPELIN_LOCAL_IP=0.0.0.0 --name zeppelin
apache/zeppelin:0.10.1
Затем откройте http://localhost:8080 в браузере и откройте блокнот Spark/Deep Dive into Iceberg, который содержит весь код в этой статье.
Архитектура Iceberg
В основном, в Iceberg есть 3 слоя:
- слой каталога
- слой метаданных
- Слой данных
Слой каталога
Слой каталога имеет 2 реализации:
- Hive catalog, который использует метахранилище hive. Hive metastore использует реляционную базу данных для хранения файла снимков текущей версии.
- Каталог на основе пути, который основан на файловой системе. В этом учебнике используется каталог на основе пути. Он использует файлы для хранения файла метаданных текущей версии. (version-hint.text — это указатель, который указывает на файл метаданных каждой версии v[x].metadata.json в примерах ниже).
Слой метаданных
В слое метаданных есть 3 типа файлов:
- Файл метаданных. Каждая операция CRUD генерирует новый файл метаданных, который содержит всю информацию о метаданных таблицы, включая схему таблицы, все исторические снимки до настоящего времени и т.д. Каждый снимок связан с одним файлом списка манифестов.
- Файл списка манифестов. Каждая версия снапшота имеет один файл списка манифестов. Файл списка манифестов содержит коллекцию файлов манифестов.
- Файл манифеста. Файл манифеста может быть общим для всех файлов снапшотов. Он содержит коллекцию файлов данных, в которых хранятся данные таблицы. Кроме того, он также содержит другую метаинформацию для потенциальной оптимизации, например, количество строк, нижняя граница, верхняя граница и т.д.
Слой данных
Уровень данных представляет собой набор паркетных файлов, которые содержат все исторические данные, включая новые добавленные записи, обновленные записи и удаленные записи. Подмножество этих файлов данных составляет одну версию снапшота.
Приведенная выше диаграмма представляет собой архитектуру Iceberg, а также демонстрирует то, что мы сделали в этом учебнике.
- S1 означает версию после того, как мы вставили 3 записи
- S2 означает версию после обновления одной записи
- S3 означает версию после удаления одной записи.
Подготовка
Скачайте jq и avro tools jar
jq используется для отображения json, avro tools jar используется для чтения файлов метаданных айсберга (формат avro) и отображения их в виде обычного текста.
Настройте Spark
%spark.conf
— это специальный интерпретатор для настройки интерпретатора Spark в Zeppelin. Здесь я настраиваю интерпретатор Spark, как описано в этом кратком руководстве. Кроме того, я указываю папку хранилища spark.sql.catalog.local.warehouse в явном виде, чтобы я мог легко проверить папку с таблицами позже в этом руководстве. Теперь давайте начнем использовать Spark и играть в Iceberg в Zeppelin.
Создание таблицы Iceberg
Сначала создадим таблицу Iceberg с 2 полями: id и data.
Затем опишите эту таблицу, чтобы проверить ее детали
Проверка папки таблицы
Что же делает Iceberg под этим sql-оператором create? На самом деле, Iceberg сделал 2 вещи:
- Создать каталог events в папке склада /tmp/warehouse
- Добавить папку метаданных, которая содержит всю информацию о метаданных.
Поскольку это вновь созданная таблица, в ней нет никаких данных. Существует только одна папка метаданных в папке таблицы (/tmp/warehouse/db/events ). В этой папке находятся 2 файла:
- version-hint.text. Этот файл содержит только одно число, которое указывает на текущий файл метаданных v[n].medata.json)
- v1.metadata.json. Этот файл содержит метаданные этой таблицы, такие как схема, расположение, снимки и т.д. На данный момент в этой таблице нет данных, поэтому в этом файле метаданных нет снимков.
Вставка 3 записей (S1)
Теперь вставим 3 новые записи (1, a
), (2, b
), (3, c
).
Затем используйте оператор select для проверки результата.
Проверка папки таблицы
На самом деле для этой операции вставки произошло две вещи.
- В папке data создаются 3 паркетных файла. По одной записи в каждом паркетном файле.
- В папке метаданных содержимое файлаversion-hint.text изменено на 2, создан файл v2.metadata.json, который содержит один вновь созданный снимок, указывающий на один файл списка манифестов. Этот файл списка манифестов указывает на один файл манифеста, который указывает на 3 паркетных файла.
Мы можем использовать avro tools jar для чтения файла списка манифестов, который имеет формат avro. И мы обнаружим, что он хранит местоположение файла манифеста и другую мета-информацию, такую как счетчик добавленных_данных_файлов, счетчик удаленных_данных_файлов и т.д.
Затем используем avro tools jar для чтения файла манифеста, который содержит путь к файлам данных и другую связанную с ними метаинформацию.
Мы можем использовать spark api для чтения необработанных паркетных файлов данных, и мы можем обнаружить, что в каждом паркетном файле есть одна запись.
Обновление записи (S2)
Теперь давайте используем оператор update для обновления одной записи.
Проверьте результат после обновления
Проверьте папку с таблицами
- В папке данных существующие паркетные файлы не изменяются. Но создается один новый паркетный файл.(3,
c_updated
) - В папке метаданных содержимое файлаversion-hint.text изменяется на 3, создается файл v3.metadata.json, который имеет 2 снимка. Один снимок является первым снимком в вышеприведенном шаге, другой новый снимок создается, который имеет новый файл списка манифеста.
Возможно, вам будет интересно узнать, как Iceberg реализует операцию обновления без изменения существующих данных. Это волшебство происходит в слое метаданных Iceberg. Если вы посмотрите файл метаданных этой версии, то увидите, что теперь он содержит 2 снимка, и каждый снимок связан с одним файлом списка манифеста. Первый снимок такой же, как и выше, а второй снимок связан с новым файлом списка манифестов. В этом файле списка манифестов есть 2 файла манифеста.
Первый файл манифеста указывает на недавно добавленный файл данных (3, c_updated
). Во втором файле манифеста вы увидите, что он по-прежнему содержит 3 файла данных, которые содержат (1, a
), (2, b
), (3, c
), но статус третьего файла данных (3, c
) равен 2, что означает, что этот файл данных удален, поэтому когда Iceberg читает эту версию таблицы, он пропускает этот файл данных. Таким образом, будут прочитаны только (1,a
), (2, b
).
Удаление записи (S3)
Теперь давайте удалим запись (2, b
).
Используйте оператор select для проверки результата
Проверьте папку с таблицами
- В папке данных ничего не изменилось.
- В папке метаданных содержимое файлаversion-hint.text изменено на 4, создан файл v4.metadata.json, который содержит еще один снимок (всего 3 снимка).
Файл списка манифестов, связанный с новым снапшотом, содержит 2 файла манифеста.
Файл списка манифестов, связанный с новым снапшотом, содержит 2 файла манифестов.
Первый манифест указывает на 1 файл данных (3, c_updated
), второй манифест указывает на файлы данных (1, a
), (2, b
). Но статус файла данных (2, b
) равен 2, что означает, что он был удален, поэтому, когда Iceberg читает эту версию таблицы, он просто пропускает этот файл данных. Поэтому будет прочитан только файл (1, a
).
Используйте spark api для чтения этих файлов данных.
Просмотр метаданных
Вы также можете читать таблицы метаданных, чтобы проверить историю таблицы, снимки и другие метаданные.
Проверить метаданные истории
Проверить метаданные моментального снимка
Проверить метаданные манифеста
Проверить метаданные файла
Резюме
В этой статье я выполнил 4 основных шага для игры в Apache Iceberg:
- Создать таблицу
- Вставка данных
- Обновить данные
- Удалить данные
На каждом шаге я проверяю, что изменилось в папке таблицы. Все шаги выполняются в докер-контейнере Apache Zeppelin, вы можете легко воспроизвести их. Помните только одно: имена файлов генерируются случайным образом (файл снапшота, файл манифеста, файл паркета), поэтому вам нужно обновить код, чтобы использовать правильное имя файла. Надеюсь, эта статья будет полезна для вас, чтобы понять внутренний механизм Apache Iceberg.
Ссылки
- https://zeppelin.apache.org/docs/0.10.1/interpreter/spark.html
- https://iceberg.apache.org/
- https://www.dremio.com/resources/guides/apache-iceberg-an-architectural-look-under-the-covers/
- https://www.starburst.io/blog/trino-on-ice-iv-deep-dive-into-iceberg-internals/