Интеграция PostgreSQL и Apache Iceberg стала стратегическим направлением для гигантов вроде Snowflake и Databricks. Постгрес — для транзакционных операций, Iceberg — для масштабной аналитики. Но как только речь заходит о потоковом CDC (Change Data Capture), возникает тихая, но болезненная проблема: как удалять данные?
🔍 Два пути удаления в Iceberg
В Iceberg предусмотрены два механизма row-level delete:
- 📍 Position delete — удаление по физическому адресу (путь файла + номер строки).
✅ Отличная производительность чтения — движок просто пропускает строки.
❌ Требует заранее знать физическое расположение строки, что для стриминга почти нереально. - 🗝 Equality delete — удаление по значению столбцов (обычно по первичному ключу).
✅ Записываем только ключ — идеально для CDC.
❌ Чтение превращается в merge-on-read, а количество delete-файлов растёт → нужна регулярная компакция.
⚙ Почему equality delete — единственный вариант для CDC
В потоковом сценарии мы не знаем, в каком файле и на какой строке лежит удаляемая запись. CDC из Postgres через Debezium или Flink отдаёт нам только ключ и старое/новое значение.
💡 В итоге для CDC остаётся только equality delete, иначе придётся каждый раз сканировать Iceberg в поисках позиции строки, что убьёт латентность и пропускную способность.
🚧 Проблема совместимости
Поддержка equality delete в популярных движках выглядит печально:
- ❄ Snowflake: во внешних Iceberg-таблицах — только position delete.
- 🔥 Databricks: нет поддержки ни одного типа row-level delete.
- 🟥 Redshift: equality delete поддерживается (Iceberg v2, внешний каталог).
Итог — в большинстве экосистем CDC с equality delete просто не будет корректно читаться.
🛠 Инженерный взгляд: стратегия RisingWave
RisingWave предложил гибридный подход, чтобы CDC → Iceberg реально работал в продакшене:
- 🔄 На записи:
Если в одном батче ключ обновлялся несколько раз — применяем position delete (уже знаем физическую позицию).
Если ключ вне батча — используем equality delete. - 🧹 Компакция:
Планировщик удаляет накопившиеся equality delete и сливает мелкие файлы.
Режимы:
🏎 Low-latency — компакция каждые ~минуту.
💤 Offline — реже, чтобы снизить нагрузку на S3 и стоимость API-вызовов. - 🔗 Экспорт для несовместимых движков:
Перед экспортом делаем таргетную компакцию, чтобы отдать «чистую» версию без equality delete.
Внутренние сервисы продолжают читать «грязную» версию с минимальной задержкой. - 🛡 Гарантии exactly-once и идемпотентности:
Все коммиты повторяемы и проверяемы, что убирает дубликаты и потери данных.
📊 Реальный кейс: Siemens
До RisingWave:
- CDC → Iceberg с equality delete.
- Snowflake не мог читать эти удаления.
- Приходилось запускать Spark для полной очистки delete-файлов → задержки и рост стоимости.
После:
- Гибридная стратегия delete.
- Автокомпакция.
- Snowflake читает «чистую» версию без Spark.
- Задержка упала с батч-уровня до real-time.
💭 Мой вывод
Equality delete — это не баг, а цена стриминга. Мы переносим сложность с записи (где важна низкая задержка) на чтение (где можно оптимизировать асинхронно). Но без продуманной стратегии компакции и совместимости это превращается в ловушку для инженеров.
RisingWave показал, что грамотное сочетание position + equality, плюс планомерная компакция и экспорт могут сделать CDC → Iceberg жизнеспособным даже в условиях несовершенной поддержки движков.
🔗 Источник: The Equality Delete Problem in Apache Iceberg