Módulo 7: Catalogs Maintenance And Delta Lake By Contrast
Catálogos más allá de lo local: REST, Glue, Unity Catalog, Polaris
Descripción
Desde el módulo 2, esta guía usa un catálogo llamado kiosko, respaldado por un archivo SQLite y un warehouse en tu propio filesystem. Funcionó perfecto: costó $0, no necesitó ninguna cuenta, y cumplió su única función —apuntar siempre al archivo de metadata vigente de cada tabla— sin fallar ni una sola vez en seis módulos. Esta lección no reemplaza ese catálogo. Nombra, uno por uno, los cuatro catálogos que sí se usan cuando ese mismo trabajo tiene que sostenerse con muchos motores distintos, escribiendo a la vez, desde máquinas distintas — sin implementar ninguno, sin cuenta de nube, sin credenciales.
Conexión con el módulo. La lección 1 prometió nombrar los catálogos de producción "por su garantía, sin implementarlos". Esta lección cumple esa promesa: primero precisa qué garantía exacta resuelve cualquier catálogo de Iceberg —la misma que kiosko ya te dio, sin que lo notaras—, y después nombra los cuatro que la sostienen a escala de producción.
La garantía que ya tenías, sin saber que tenía nombre
Vuelve al módulo 2, lección 2: el catálogo kiosko guarda, para kiosko.fact_orders, la ruta exacta de un archivo — el metadata.json vigente. Cada vez que escribiste algo nuevo en esa tabla —cada append(), overwrite(), upsert() de los módulos 1 a 6—, PyIceberg hizo dos cosas, siempre en este orden: escribió un archivo de metadata nuevo, completo, sin tocar el anterior; y después, solo si esa escritura completó sin errores, le pidió al catálogo que actualizara su puntero para que apuntara al archivo nuevo. Esa segunda operación —"actualiza el puntero, pero solo si nadie más lo cambió mientras yo escribía"— es una actualización atómica condicional (en inglés, compare-and-swap: "compara el valor actual contra el que yo esperaba, y solo entonces reemplázalo"). Es la garantía mínima, no negociable, de cualquier catálogo de Iceberg, sea kiosko/SQLite o el más sofisticado de los cuatro que vas a conocer en esta lección.
¿Por qué importa el "condicional"? Porque si dos escrituras completan casi al mismo tiempo, sin esa condición el catálogo podría aceptar las dos, y la segunda pisaría silenciosamente el trabajo de la primera. Con la condición, la segunda escritura descubre, en el momento de actualizar el puntero, que el valor ya no es el que esperaba —alguien más llegó primero— y su commit falla, obligándola a reintentar sobre el estado más reciente. SQLite, por ser una base de datos transaccional de verdad, ya te dio esta garantía en los seis módulos anteriores, aunque nunca la pusiste a prueba con dos escritores compitiendo de verdad — porque, en toda esta guía, el único escritor fue tu propio script.
Una analogía: el mismo mostrador, ahora con cien ventanillas
El mostrador del banco de la lección 1 del módulo 6 resolvía un solo trámite a la vez, con un solo cliente enfrente. Un catálogo de producción es ese mismo mostrador, pero con cien ventanillas abiertas al mismo tiempo, todas actualizando la misma cuenta bancaria al mismo instante — un motor Spark corriendo un MERGE INTO, un pipeline de Python haciendo upsert(), un analista consultando desde un notebook, todos leyendo o escribiendo la misma tabla Iceberg, quizás desde continentes distintos. El banco necesita algo que la ventanilla única de kiosko/SQLite nunca tuvo que demostrar bajo presión real: un sistema central que sepa, sin ambigüedad, cuál de cien actualizaciones simultáneas llegó "primero" según el registro oficial, y que rechace, con una señal clara de "reintenta", a cualquiera que haya llegado tarde.
Los cuatro catálogos de producción
REST Catalog — el protocolo, no un producto
El REST Catalog no es un catálogo específico — es una especificación abierta, publicada por el propio proyecto Apache Iceberg, de cómo cualquier motor debería hablarle a cualquier catálogo por HTTP: un conjunto estándar de endpoints (GET /v1/namespaces/{ns}/tables/{table}, entre otros) y payloads JSON, documentados con OpenAPI. La idea central: en vez de que cada motor (Spark, Trino, PyIceberg, DuckDB…) necesite un cliente distinto para cada tipo de catálogo (Hive Metastore, Glue, SQL…), un motor implementa el protocolo REST una sola vez, y desde ahí puede hablar con cualquier catálogo que también implemente ese mismo protocolo — incluidos Unity Catalog y Polaris, los dos siguientes de esta lista.
La actualización atómica condicional, en este protocolo, ocurre así: el cliente envía los cambios propuestos junto con el metadata.json que esperaba encontrar vigente; el servidor REST valida esa expectativa contra su propio registro, y solo si coincide, acepta el cambio y mueve el puntero. Si no coincide —otro cliente ya escribió primero—, el servidor responde con un error explícito de conflicto, y el cliente decide si reintenta.
PyIceberg ya trae soporte nativo para este protocolo, verificado en tu propia instalación:
from pyiceberg.catalog import AVAILABLE_CATALOGS
print(AVAILABLE_CATALOGS)
{<CatalogType.REST: 'rest'>: ..., <CatalogType.HIVE: 'hive'>: ...,
<CatalogType.GLUE: 'glue'>: ..., <CatalogType.DYNAMODB: 'dynamodb'>: ...,
<CatalogType.SQL: 'sql'>: ..., <CatalogType.IN_MEMORY: 'in-memory'>: ...,
<CatalogType.BIGQUERY: 'bigquery'>: ...}
Conectarte a un catálogo REST real sería, en código, tan simple como cambiar dos argumentos de la línea que ya conoces desde el módulo 1:
# NO se ejecuta en esta guia -- necesita un servidor REST real y credenciales.
# Mismo load_catalog() de siempre, type="rest" en vez de type="sql".
catalog = load_catalog("kiosko", type="rest", uri="https://tu-servidor-rest/", ...)
Esa línea no corre en esta guía a propósito: necesitarías un servidor REST real corriendo en algún lado, con sus propias credenciales — exactamente la frontera que esta lección respeta.
AWS Glue Data Catalog — el metastore administrado de AWS
AWS Glue Data Catalog es un servicio administrado de AWS que actúa como metastore central para todo el ecosistema de datos de una cuenta — no nació pensando solo en Iceberg, pero lo soporta de forma nativa desde hace varios años. Cuando una tabla Iceberg usa Glue como catálogo, Glue guarda la ubicación del metadata.json vigente como un parámetro de su propio registro de tabla, y usa mecanismos internos de bloqueo (con actualización atómica condicional respaldada por DynamoDB) para resolver la misma garantía de "un solo puntero, actualizado sin ambigüedad" que ya conoces.
La ventaja concreta de Glue frente a levantar tu propio servidor REST: es serverless —no hay ningún proceso que tú tengas que operar—, se integra directamente con IAM (los mismos permisos que ya gestionan el resto de tu cuenta de AWS), y es, en la práctica, el catálogo por defecto para cualquier equipo que ya vive dentro de AWS. La desventaja declarada: acceder a Glue desde fuera de AWS exige configurar credenciales de IAM explícitas, y el servicio tiene límites de tasa de peticiones que pueden volverse un cuello de botella con muchos escritores concurrentes.
Unity Catalog — gobierno + Iceberg, con un puente hacia Delta
Unity Catalog, de Databricks, empezó como un catálogo de gobierno de datos —permisos, linaje, auditoría— para tablas Delta. En 2026 implementa, de forma nativa, el protocolo REST Catalog de Iceberg: soporta tablas Iceberg administradas (creadas, leídas, escritas y optimizadas directamente dentro de Unity Catalog) con acceso de lectura/escritura completo para clientes Iceberg externos —Spark, Trino, DuckDB, o cualquier motor que hable el protocolo REST—, con credential vending: en vez de entregarte credenciales de larga duración, el catálogo genera credenciales temporales, de alcance mínimo, para cada operación puntual.
La pieza que conecta esta lección con la lección 7 de este mismo módulo: Unity Catalog también soporta Delta UniForm, una función de Delta Lake que genera, junto a cada tabla Delta, metadata compatible con Iceberg sobre los mismos archivos Parquet — así que una tabla nativa de Delta puede leerse, sin conversión, desde un cliente que solo sabe hablar Iceberg. No es casualidad que el catálogo de gobierno de Databricks termine implementando el protocolo abierto de su competidor histórico: es, con evidencia concreta, la misma convergencia que la lección 7 desarrolla a fondo.
Apache Polaris — REST + control de acceso, donado a Apache
Apache Polaris, originado en Snowflake y donado como proyecto de código abierto a la Apache Software Foundation, es un servidor de catálogo REST diseñado específicamente para coordinación multi-motor y multi-nube. Implementa el protocolo REST Catalog como base, y le agrega control de acceso basado en roles (RBAC) de grano fino y credential vending propio: cuando un motor pide acceso a una tabla, Polaris contacta al servicio de tokens de seguridad (STS) del proveedor de nube correspondiente para generar credenciales de almacenamiento de corta duración y alcance restringido — nunca entrega una llave maestra.
La diferencia de enfoque frente a Glue o Unity Catalog: Polaris no está atado a un solo proveedor de nube ni a un solo motor de cómputo — su objetivo explícito es ser el catálogo neutral que cualquier combinación de motores (Spark en un lado, Snowflake en otro, Trino en un tercero) pueda compartir sin que ninguno tenga que "ser el dueño" de la infraestructura del catálogo.
Diagrama: la misma garantía, cuatro implementaciones
flowchart TB
G["La garantia comun:\nun solo puntero al metadata.json vigente,\nactualizacion atomica condicional"]
G --> K["kiosko / SQLite\n(esta guia, M1-M6, M7-M8)\n1 proceso, sin concurrencia real"]
G --> R["REST Catalog\nprotocolo abierto, HTTP,\ncualquier motor compatible"]
G --> GL["AWS Glue Data Catalog\nmetastore serverless de AWS,\nIAM + DynamoDB"]
G --> U["Unity Catalog\nREST + gobierno + credential vending,\npuente Delta UniForm"]
G --> P["Apache Polaris\nREST + RBAC + credential vending,\nmulti-nube, multi-motor"]
Profundización: por qué esta guía nunca conecta a ninguno de los cuatro
Sería técnicamente posible, con una cuenta de AWS o un workspace de Databricks, adaptar cualquier código de esta guía a uno de estos cuatro catálogos cambiando solo el argumento type= de load_catalog() — la API de PyIceberg que ya conoces (create_namespace(), create_table(), table.append(), table.scan()) no cambia según el catálogo que uses por debajo. Pero esta guía declaró, desde su diseño, una frontera explícita: catálogos gestionados con cuenta y credenciales reales son terreno de aws-core-services-guide, no de esta guía. La razón no es solo de alcance — es que verificar de verdad estas cuatro conexiones exigiría, para cada una, una cuenta activa, credenciales configuradas correctamente, y (en el caso de Glue y Unity Catalog) un costo real de infraestructura, aunque sea mínimo. Esta lección prefiere nombrar cada garantía con precisión y citar su documentación oficial, en vez de fingir una conexión que no se verificó de verdad — la misma disciplina que ya viste en el módulo 6 con el MERGE INTO de Spark.
Errores comunes
Pensar que "catálogo REST" significa "un catálogo específico llamado REST". Qué pasa: alguien busca "REST catalog" esperando encontrar un producto instalable con ese nombre exacto, y se confunde al descubrir que Unity Catalog, Polaris, e incluso Glue (con una capa adicional) pueden hablar "REST". Por qué pasa: el nombre suena a producto, pero es un protocolo. Cómo detectarlo: si tu confusión es "¿cuál de los cuatro ES el REST catalog?", la pregunta está mal planteada. Cómo corregirlo: REST Catalog es la especificación —el conjunto de endpoints HTTP y payloads JSON—; Unity Catalog y Polaris son implementaciones de esa especificación (entre otras que existen en el ecosistema, como el catálogo REST de referencia del propio proyecto Iceberg, o Project Nessie); Glue tiene su propio protocolo nativo, distinto de REST, aunque en 2026 muchos motores también pueden hablarle a Glue a través de una capa de compatibilidad REST.
Asumir que un catálogo de producción resuelve, por sí solo, el control de acceso a los datos. Qué pasa: alguien configura un catálogo REST o Glue, confirma que el puntero al metadata funciona, y da por hecho que ya tiene un sistema de permisos completo sobre quién puede leer o escribir cada tabla. Por qué pasa: el catálogo sí controla quién puede actualizar el puntero —esa es su garantía central—, pero eso es distinto de un sistema de gobierno de datos con roles, columnas sensibles enmascaradas, o auditoría de accesos. Cómo detectarlo: si tu pregunta es "¿quién puede ver la columna unit_cost de dim_product?", ya saliste del alcance de "qué garantiza el catálogo" y entraste al de gobierno de datos. Cómo corregirlo: Unity Catalog y Polaris sí incluyen control de acceso de grano fino como parte de su propuesta —por eso esta lección los menciona explícitamente—, pero un catálogo REST "puro" o Glue sin capas adicionales no lo incluyen automáticamente; ese tema pertenece a data-reliability-and-governance-guide, no a esta lección.
Ejercicios
Ejercicio 1 — Clasifica los cuatro catálogos según dos ejes: "protocolo abierto vs. propietario" y "administrado por un proveedor vs. auto-hospedado". Con lo que leíste en esta lección, ubica REST Catalog, Glue, Unity Catalog y Polaris en esos dos ejes.
Ver solución
Protocolo: REST Catalog es, por definición, abierto —es la especificación misma—; Unity Catalog y Polaris implementan ese protocolo abierto (además de sus propias capas adicionales); Glue tiene un protocolo nativo propio de AWS, aunque con compatibilidad REST creciente en el ecosistema. Hospedaje: Glue y Unity Catalog son servicios administrados por un proveedor (AWS y Databricks respectivamente) — tú no operas el servidor; Polaris, aunque nació en Snowflake, es código abierto y se puede auto-hospedar en tu propia infraestructura; un servidor REST "genérico" también puede auto-hospedarse. La conclusión práctica: si tu equipo ya vive dentro de AWS, Glue es la opción de menor fricción; si necesitas multi-nube o multi-motor sin depender de un solo proveedor, Polaris auto-hospedado o un REST catalog genérico son las opciones más neutrales.
Ejercicio 2 — Explica por qué la actualización atómica condicional (compare-and-swap) es más importante en un catálogo de producción que en kiosko/SQLite. Piensa en cuántos procesos distintos escribieron sobre kiosko.dim_product a lo largo de esta guía.
Ver solución
A lo largo de los módulos 1 a 6, exactamente un proceso a la vez escribió sobre kiosko.dim_product — tu propio script, corrido de forma secuencial, nunca dos scripts compitiendo por el mismo commit al mismo tiempo. SQLite te dio la garantía de actualización atómica condicional, pero nunca la puso a prueba bajo concurrencia real, porque nunca hubo un segundo escritor compitiendo. En un catálogo de producción, con Spark, un notebook y un pipeline de ingesta escribiendo simultáneamente sobre la misma tabla, esa garantía deja de ser teórica: sin ella, dos commits que llegan casi al mismo tiempo podrían pisarse silenciosamente —uno de los dos ganaría sin que el catálogo detectara el conflicto—, corrompiendo la historia de snapshots que hace posible el time travel del módulo 3. La garantía siempre estuvo ahí; esta lección es la primera vez que esta guía explica por qué importa de verdad.
Ejercicio 3 — Predicción: si aws-core-services-guide conectara esta misma tabla kiosko.dim_product a un AWS Glue Data Catalog real, ¿qué línea de código cambiaría, y cuál se mantendría idéntica? Usa la línea de load_catalog() que ya conoces desde el módulo 1.
Ver solución
Cambiaría la llamada a load_catalog() — type="sql" con uri="sqlite:///..." y warehouse="file://..." se reemplazaría por type="glue" con las credenciales de AWS correspondientes (región, y típicamente un warehouse apuntando a un bucket S3 en vez de un path local). Todo lo demás se mantendría idéntico: catalog.create_namespace("kiosko"), catalog.create_table("kiosko.dim_product", schema=...), table.append(...), table.overwrite(...), table.scan(snapshot_id=...), table.maintenance.expire_snapshots() — cada línea de código de los módulos 1 a 7 de esta guía funcionaría sin cambios contra un catálogo Glue real. Esta es, con precisión, la razón por la que Iceberg separa "formato de tabla" de "catálogo": el código que habla con la tabla no necesita saber, ni le importa, cuál de los cinco catálogos de esta lección (kiosko incluido) está resolviendo el puntero por debajo.
Resumen y siguiente paso
En esta lección precisaste la garantía mínima que cualquier catálogo de Iceberg cumple —un solo puntero al metadata vigente, actualizado de forma atómica y condicional—, la misma que kiosko/SQLite te dio sin que lo notaras desde el módulo 2. Conociste los cuatro catálogos de producción que sostienen esa garantía a escala real: REST Catalog (el protocolo abierto), AWS Glue Data Catalog (el metastore administrado de AWS), Unity Catalog (gobierno + Iceberg + puente hacia Delta) y Apache Polaris (REST + control de acceso, multi-nube). Ninguno de los cuatro se conectó de verdad — esa conexión, con cuenta y credenciales reales, pertenece a aws-core-services-guide.
Antes de avanzar deberías poder: explicar la actualización atómica condicional con tus propias palabras; y nombrar, para cada uno de los cuatro catálogos, qué lo distingue de los otros tres.
La lección 3 vuelve, por fin, a código que sí corre: reconstruye kiosko.dim_product con el estado exacto que dejó el módulo 3, le agrega cinco noches de un pipeline que se repite sin necesidad, y mide, con table.history() real, cuánto cuesta eso.
Recursos
- Apache Iceberg — REST Catalog Open API Specification, la fuente formal del protocolo que Unity Catalog y Polaris implementan. iceberg.apache.org/rest-catalog-spec. En inglés.
- PyIceberg — referencia de API, la sección
Catalog, con la lista completa de tipos de catálogo soportados (rest,glue,sql,hive,dynamodb,bigquery,in-memory), verificada en la instalación de esta guía. py.iceberg.apache.org/api. En inglés. - Databricks — documentación oficial, "What is Apache Iceberg in Databricks", fuente de las tablas Iceberg administradas por Unity Catalog y su soporte del protocolo REST Catalog. docs.databricks.com/aws/en/iceberg. En inglés.
- DISEÑO de esta guía — la sección del módulo 7, y la frontera explícita con
aws-core-services-guideque esta lección respeta.src/guides/lakehouse-and-iceberg-guide/DISENO.md. En español.