Las P contra la industria — qué hacen Cloudflare, Databricks y Snowflake
Para qué. Antes de ejecutar cada P, saber qué número o qué patrón usan los que ya
operan a esta escala. No para copiar: para no inventarse un valor cuando existe un
consenso, y para saber cuándo apartarse de él a propósito.Medido en documentación oficial el 2026-07-31. Cruza con
warehouse-infrastructure-priorities.md.
P3 · Retención y borrado — el consenso es 7 días, y es un suelo
| Qué hace | |
|---|---|
| Snowflake | Time Travel 0–90 días (defecto 1 día en tablas permanentes) + Fail-safe de 7 días NO configurable — en ese tramo sólo Snowflake puede recuperar |
| Databricks UC | UNDROP TABLE, 7 días por defecto, configurable a 0 (desactivado) o 7–30 días. «un periodo más largo da protección añadida frente al borrado accidental de datos críticos de producción» |
| Cloudflare R2 Data Catalog | expiración automática con DOS parámetros: --older-than-days y --retain-last. Ambas condiciones deben cumplirse para expirar un snapshot |
Tres lecturas que aplican directamente:
① Siete días es el suelo, no una opción. Databricks no permite valores entre 1 y 6: o desactivas la recuperación, o das al menos una semana. Y añade una regla dura: «nunca ejecutes VACUUM con una retención menor de 7 días» — porque corrompe transacciones largas en vuelo. No es sólo protección contra el error humano: es correctitud.
② El patrón de Cloudflare es mejor que el de la edad sola. Expirar por antigüedad únicamente puede dejar una tabla sin ningún snapshot si no ha recibido escrituras en el periodo. Exigir además un mínimo de snapshots retenidos lo hace imposible. Es el patrón a copiar.
③ Snowflake separa dos capas: lo que el usuario puede deshacer (Time Travel) y lo que sólo el proveedor puede rescatar (Fail-safe). Nosotros no tenemos proveedor detrás — el Fail-safe no existe para nosotros, así que nuestro único colchón es la retención que configuremos. Eso hace la decisión más importante, no menos.
⇒ La recomendación para P3
delete-profilesoft con 7 días de retención, y expiración de snapshots por
edad + mínimo retenido, no sólo por edad. Siete es el suelo de la industria y el
límite por debajo del cual Databricks advierte de corrupción; no hay razón para inventar
otro número.
✅ APLICADO (2026-07-31) — y la mitad que no se pudo
delete-profile: hard → soft · 7 días (604.800s), aplicado al warehouselakehouse
y releído del catálogo para verificarlo. Script:
scripts/dataspaces/warehouse-p3-soft-delete.ts(en seco por defecto,--applypara
ejecutar). UnDROP TABLEes ahora recuperable durante una semana.La expiración de snapshots NO se pudo configurar. Lakekeeper 0.13.0 responde 200 en
…/task-queue/expire_snapshots/config, pero:
- la cola no aparece entre las activas del servidor (
/management/v1/infolista
tabular_expiration,tabular_purge,task_log_cleanup— y nada más);- el config devuelto no expone parámetros de retención: sólo
queue-namey
max-seconds-since-last-heartbeat. No hay dónde ponerolder-than-daysni
retain-last.⇒ El patrón de Cloudflare —expirar por edad + mínimo retenido— queda pendiente de
una versión de Lakekeeper que lo exponga, o de hacerlo nosotros con un motor. Se anota
aquí para que no se dé por hecho: hoy los snapshots no se expiran solos, y eso
significa que la historia se acumula sin techo.
P2 · Autorización — el patrón que merece copiarse
Databricks tiene un privilegio dedicado, EXTERNAL USE SCHEMA, para que un motor externo
pueda pedir credenciales temporales. Y lo trata de forma deliberadamente incómoda:
No está incluido en
ALL PRIVILEGES— «para evitar exfiltración accidental» — y
los dueños del esquema no lo tienen por defecto. Hay que concederlo explícitamente,
siempre.
Eso es una decisión de diseño excelente y transferible: el permiso de sacar datos fuera del sistema no se hereda de ningún otro. Ser dueño de una tabla no implica poder entregarla; son dos cosas distintas y se conceden por separado.
Aplicado a nuestro caso — y con una corrección del 2026-08-04: allow-all no se
retiró y no se va a retirar, porque Cedar no está en el build OSS de Lakekeeper. La regla
de abajo se cerró en la autenticación (LAKEKEEPER__OPENID_AUDIENCE) y la aplicación por
acción vive arriba, en la cara REST de Index Catalog — que además sabe separar «ver la
metadata» de «recibir la llave», que es justo el patrón de esta sección y que el catálogo
no puede expresar:
- cada servicio con identidad propia en el catálogo — hoy
warehouse-writeryml-runnercomparten el cliente OIDClakekeeper-ml-runner, cuyo nombre además ya quedó rancio; warehouse-writer→ escribir ·duck-server→ leer. Declarado en el catálogo, no deducido de qué llave lleva cada uno;- y el permiso de entregar credenciales a terceros (el día del EDC) separado de todo lo demás, siguiendo a Databricks.
El perímetro que acabamos de construir protege por geografía —quién tiene la llave—.
P2 lo convierte en lógica —qué se le permite a cada quién—. Son complementarios: sin
el perímetro, la autorización no sirve; sin autorización, el perímetro es todo lo que hay.
P4 · Formato v2 vs v3 — confirmado
Databricks lo dice sin ambigüedad: «deletion vectors aren't supported for Iceberg v2 reads, but Apache Iceberg v3 supports deletion vectors».
Y describe el coste de no tenerlos: en v2, borrar marca los datos en ficheros de metadata
que el lector debe abrir y cruzar; hay que ejecutar REORG TABLE … APPLY (PURGE) para
materializarlo reescribiendo ficheros. A petabytes con updates constantes, ésa es la
diferencia entre viable e inviable.
Nuestro warehouse tiene hoy cero delete files, así que no urge — pero la decisión de
crear tablas en v2 o v3 hay que tomarla antes de que haya petabytes en el formato
viejo. Lakekeeper ya permite v3 (allowed-format-versions: [1,2,3]); sólo está en v2 por
defecto.
P5 · Metadata y compaction — y una tensión que conviene nombrar
Cloudflare describe exactamente el problema que medimos en nuestro censo:
«sin compactación, los motores tendrán que abrir y leer cada fichero individual, lo que
resulta en consultas más lentas y costes mayores, más sobrecarga de metadata que alarga
la planificación de la consulta, y peor eficiencia de compresión»
Es literalmente nuestro layout: fichero medio de 9 KB, ~6 round-trips para servir 4 KB.
⚠️ La tensión: R2 Data Catalog compacta; Lakekeeper no
Cloudflare ofrece compactación automática y expiración de snapshots en su propio
catálogo Iceberg, sin coste adicional y con panel de seguimiento de los jobs.Nosotros elegimos Lakekeeper, que expira snapshots y limpia huérfanos pero no
compacta — compactar es reescribir datos, y eso exige un motor. Así que la compactación
es trabajo nuestro, y no lo era si hubiéramos ido con R2 Data Catalog.Esto no invalida la elección —Lakekeeper da control de acceso, multi-tenancy,
despliegue propio y no ata al proveedor; R2 Data Catalog estaba además en beta cuando se
decidió—. Pero es un coste real que hay que asumir explícitamente, y conviene tenerlo
escrito antes de que aparezca como sorpresa. Cuando la compactación haga falta, habrá que
construirla sobre un motor propio (DuckDB es el candidato).
Resumen aplicable
| P | Qué adoptar de la industria |
|---|---|
| P3 | soft-delete 7 días (suelo de Databricks) · expirar por edad + mínimo retenido (patrón Cloudflare) · recordar que no tenemos Fail-safe |
| P2 | identidad por servicio · el permiso de entregar datos fuera explícito y no heredable (patrón EXTERNAL USE SCHEMA) |
| P4 | v3 por deletion vectors, decidido antes de tener volumen en v2 |
| P5 | la compactación es nuestra — Lakekeeper no la hace; presupuestarla |
Cruza con: warehouse-infrastructure-priorities.md · storage-perimeter.md · warehouse-open-catalog.md (por qué Lakekeeper y no R2 Data Catalog).