TGViewer
дата инженеретта дата инженеретта @data_engineerette · 3.43K subscribers
Post #503 2.49K
Как движки вас газлайтят?

Расскажу историю, которая на днях прозошла на нашем кластере

💋Что надо сделать? Создать табличку и запустить пайплайн заливки данных. Казалось бы - что может быть проще?

1. Создаем таблицу в Trino:


CREATE TABLE iceberg.raw.first_table (
my_beautiful_column varchar
)
WITH (
format = 'PARQUET',
format_version = 2
)


2. Запускаем пайплайн - создается веточка:


ALTER TABLE raw.first_table
CREATE OR REPLACE BRANCH my_branch



SELECT *
FROM iceberg.raw."first_table$refs"
--main BRANCH
--my_branch BRANCH


Пайплайн падает, не успев записать данные. Но я правлю ошибку и перезапускаю - теперь все прекрасно 🙌 Ужастики так-то тоже начинаются с размеренной жизни

Но в один момент я создаю таблицу через Spark:


CREATE TABLE raw.second_table (
my_beautiful_column STRING
)
USING iceberg


Снова запускаю пайплайн, и он снова падает. Я правлю ошибку и перезапускаю...


Exception in thread "main" java.lang.IllegalArgumentException: Cannot complete replace branch operation on raw.second_table, main has no snapshot


Что случилось? Таблица точно такая же, код точно такой же. Просчитался, но... где? 🤔

😑 Тут начинаются раскопки. Создаю табличку через трино и через спарк, иду на s3 смотреть файл с метаданными

Оказывается, что трино создает отдельный снепшот с добавлением 0 строк:
🤍"current-snapshot-id" : 677178324561195060
🤍таблица raw.first_table.history имеет 1 строку

А спарк такого не делает - он их создает, только когда данные меняются, компактятся:
🤍"current-snapshot-id" : -1
🤍таблица raw.second_table.history пустая

Теперь идем в репку айсберга, а там такое:


if (create && replace && !refExists) {
safeCreateBranch()
} else if (replace) {
Preconditions.checkArgument(snapshotId != null,
"Cannot complete replace branch operation on %s, main has no snapshot", ident)
manageSnapshots.replaceBranch(branch, snapshotId)
}


🩵Какой ход событий получается:

1. Попадаем в условие if: create есть, replace есть, ветки еще нет. Ветка создается
2. Пытаемся записать данные в ветку
3. Код падает, а ветка остается(!)
4. Перезапускаем и в условие if уже не попадаем - ветка уже есть
5. Попадаем в else if (replace) - вспоминаем, что через спарк никакой снепшот не создается, поэтому snapshotId у нас null

➡️ Как решаем проблему

Перед созданием ветки нужно дропнуть существующую, если вдруг пайплайн упал и не успел почистить ветку:


ALTER TABLE raw.second_table
DROP BRANCH IF EXISTS my_branch


Либо добавить catch/except, который дропнет ее в самом конце

Общий вывод такой: при работе с разными движками любой кусок может работать по-разному. Даже самая простейшая штука, которую вы не ожидали🥺

@data_engineerette
  • 👍 18
  • 🔥 10
  • ❤ 1
  • 💯 1
More from @data_engineerette
  1. Sep 25, 2026Как прошла SmartData 2026? Я вот перечитываю свои впечатления от прошлого года и понимаю,…
  2. Sep 24, 2026Исследование data-people Тут ребята из DevCrowd запустили ежегодное исследование специалис…
  3. Sep 22, 20265 октября начнется 19-й поток программы Data Engineer от Newprolab Программа для junior- и…
  4. Sep 15, 2026Каким должен быть хороший DE? Меня однажды спросили на собесе: 🤩Какие 3 качества важны дл…
  5. Sep 12, 2026Mermaid-диаграммы Наконец-то дошли руки поковыряться в mermaid-диаграммах, это что за имба…
  6. Sep 2, 2026Iceberg — это внезапный бум или планомерная подготовка? Заметили, как с определенного моме…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →