Ir al contenido principal
Ingeniería

Desmintiendo los mitos sobre LTAP

El data lake es el almacenamiento de la base de datos, no una réplica. Por eso Postgres se mantiene rápido, los análisis están actualizados y no se necesita ningún flujo CDC

por Sergey Melnik

  • El diseño LTAP de Lakebase hace que el data lake sea el almacenamiento de la base de datos y no una réplica: una tabla Delta o Iceberg, un catálogo, con cachés de Postgres y servidores de páginas al frente para mayor velocidad.
  • Las búsquedas puntuales leen páginas de montones de Postgres y los análisis leen Parquet; además, cada consulta analítica ve una instantánea coherente, incluidas las confirmaciones que aún no están en el data lake.
  • La replicación lógica reproduce cada cambio a través de un flujo que debe mantenerse al día, lo que la convierte en una forma costosa de crear la copia del data lake.

La publicación de Reynold Xin "From monolith to Lakebase to LTAP" explicó qué es LTAP y cómo la arquitectura de Lakebase lo hace posible: una copia gobernada de datos operacionales, que sirve tanto para Postgres como para analítica, sin necesidad de un pipeline de CDC ni de una segunda base de datos.

Una base de datos tradicional mantiene su WAL y sus archivos de datos en una sola máquina. Lakebase los saca de una sola máquina y los lleva a un almacenamiento independiente y escalable

Gran parte de los comentarios subsiguientes interpretaron esa afirmación a través de sistemas que la gente ya conoce. Surgieron cuatro interpretaciones con frecuencia:

  • “LTAP es CDC con otro nombre”
  • “Una sola copia de los datos solo puede tener un diseño físico, por lo que las búsquedas puntuales o los escaneos deben ser lentos”
  • “Las tablas Iceberg o Delta en el almacenamiento de objetos están desactualizadas por naturaleza”
  • “Postgres ya proporciona la ruta de extracción: la replicación lógica”

Cada uno de estos mitos se basa en una suposición errónea sobre cómo Lakebase almacena los datos. Analicemos uno por uno.

Mito 1: “LTAP es replicación”

La realidad: LTAP mantiene una copia duradera de cada tabla en el lake. Las capas frente a ella retienen algunos de los mismos bytes para que esa tabla sea duradera y rápida, pero ninguna de ellas es una segunda base de datos.

Desde fuera, LTAP puede parecer un pipeline familiar. Postgres escribe filas, un proceso rastrea el registro (log), los cambios llegan a una tabla Iceberg y la analítica lee Iceberg. Ese pipeline es CDC. También es la estructura de la replicación lógica, la duplicación en espejo (mirroring) y la mayoría de los productos de cero ETL. Por lo tanto, es fácil clasificar a LTAP con el mismo diseño.

Para ver por qué no es así, ayuda ser precisos sobre qué se considera una segunda copia. Hay dos formas distintas en que un sistema puede terminar almacenando los mismos datos en más de un lugar: 

  • La replicación mantiene dos bases de datos sincronizadas mediante el envío de cambios de una a otra. Cada lado tiene su propio catálogo y su propia línea de tiempo, y se puede consultar cualquiera de los dos como fuente de verdad. Si el envío se detiene, las dos copias se desincronizan y nada las obliga a unirse de nuevo.
  • El almacenamiento en niveles (tiering) mantiene una base de datos y coloca una pila de cachés delante. Las cachés retienen algunos de los mismos bytes para que las lecturas sean rápidas. Si una lectura no encuentra el dato en la caché, baja una capa y genera cierta latencia. Nunca crea un segundo catálogo y, si se pierde una caché, la tabla no se pierde.

Por lo tanto, la prueba es simple: ¿se puede consultar esta capa, o conmutar por error hacia ella, como su propia base de datos? Si la respuesta es sí, es una réplica. Si es no, es un nivel (tier).

La replicación mantiene dos bases de datos sincronizadas. LTAP mantiene una sola base de datos, con el lake como el nivel duradero y cachés delante de este

Según esa prueba, Postgres siempre ha tenido niveles. El WAL, la caché del búfer y los índices almacenan bytes que se superponen con el montículo (heap). Nadie llama al índice una réplica de la tabla, porque no tiene su propio catálogo ni su propia línea de tiempo. 

LTAP mantiene esa misma jerarquía. La traslada al almacenamiento de objetos y permite que un motor de lakehouse lea el nivel inferior y duradero.

Así es como se ve esa jerarquía en Lakebase, siguiendo una operación de escritura y luego una de lectura:

  • Una escritura es duradera cuando su WAL llega a un quórum de safekeepers. A continuación, el pageserver aplica el registro, mantiene las páginas activas en la memoria y en el disco local, y materializa los datos en el almacenamiento de objetos.
  • Una lectura comienza en el nodo de cómputo, que mantiene una caché de búfer y una caché de archivos local. Los índices, TOAST y los mapas de visibilidad se encuentran en la misma ruta crítica (hot path). Una página que no esté almacenada en caché allí proviene del pageserver.

El almacenamiento de objetos en sí funciona de la misma manera. Cuando haces un PUT de un objeto en S3, este se almacena más de una vez, a menudo en zonas de disponibilidad utilizando codificación de borrado (erasure coding). La API sigue nombrando a un solo objeto y no se ejecuta ningún trabajo de sincronización entre las copias. Lakebase aplica la misma idea frente al lake: registro, cachés, pageserver, almacenamiento de objetos. Los archivos adicionales son la forma en que una tabla se vuelve duradera y rápida.

El CDC crea una segunda base de datos. Decodifica un flujo de cambios lógicos en un esquema externo, por lo general utilizando una clave primaria, y realiza un upsert en una tabla que la fuente nunca vuelve a leer. Esa tabla secundaria se puede consultar de forma independiente y puede desincronizarse con la fuente: los tipos pueden variar, las sentencias DDL pueden perderse, una ranura de replicación puede omitir filas y las tablas que nadie seleccionó nunca aparecen. El resultado son dos catálogos.

LTAP no tiene una segunda tabla que mantener sincronizada. No hay una lista de tablas para suscribirse. Una tabla que existe en Postgres existe en el lake, y las páginas que sirve la fuente primaria son cachés de ese almacén.

Mito 2: “Una sola copia significa búsquedas lentas o escaneos lentos”

La realidad: dos codificaciones sin pérdida de las mismas filas pueden servir para diferentes rutas de acceso: páginas de montículo para búsquedas puntuales y Parquet para escaneos. Cada consulta lee el diseño que le resulta rápido.

Incluso si los archivos adicionales forman una jerarquía, el diseño sigue siendo una cuestión independiente. Las búsquedas puntuales son eficientes en las filas; los escaneos son eficientes en las columnas. Si solo hay una codificación en el disco, uno de esos patrones de acceso consume E/S (I/O). Llamar a la tabla una única copia lógica no cambia eso.

Ese razonamiento es correcto, pero se basa en una suposición: que una sola copia implica una sola codificación. No es así, siempre y cuando dos formatos puedan representar las mismas filas sin pérdida. 

Por lo tanto, la pregunta es si los dos formatos de LTAP no tienen pérdida:

  • El formato principal son las páginas de montículo de Postgres, las cuales son ideales para búsquedas puntuales y actualizaciones.
  • El segundo formato está diseñado para el acceso analítico: Parquet respaldado por Delta o Iceberg. Los valores se conservan y los archivos contienen suficiente metadatos físicos (bloque de montículo, desplazamiento y versiones MVCC) como para reconstruir las páginas originales. Los valores que Parquet no puede representar sin pérdida no se fuerzan ni se descartar; viajan en un campo de desbordamiento (overflow field) en la misma tabla.

Como no se pierde nada, la copia columnar puede ser el almacenamiento duradero en el lake y las páginas de montículo se convierten en una caché de este. De este modo, cada ruta de acceso lee el formato que le conviene. Las búsquedas consultan páginas de 8 KB en el nodo de cómputo, en el disco local y en el pageserver. Los escaneos consultan Parquet a través de un motor OLAP. Los índices permanecen en el nivel rápido (hot tier); no se transcodifican a Parquet.

Postgres ya funciona de esta manera. Mantiene dos estructuras físicas sobre las mismas filas para diferentes rutas de acceso: un montículo y un índice de cobertura. Nadie trata al índice como una réplica CDC de customer. SELECT * FROM t WHERE id = 1 y SELECT count(*) FROM t son dos rutas de acceso sobre una sola tabla.

Las búsquedas puntuales leen páginas de montículo y los escaneos leen Parquet. Las páginas se pueden reconstruir a partir de Parquet, por lo que ambas contienen la misma fila

Una observación más específica es válida. Los archivos columnares de Postgres están ordenados por montículo: las filas se ubican según el número de página, ya que la página es la unidad que se reescribe en cada compactación. Ese diseño es eficiente para reconstruir una página y para reescribir únicamente las páginas modificadas (dirty pages). Es una clave de agrupación deficiente para WHERE order_date >= …. Si una consulta de un data warehouse necesita esa agrupación, se puede derivar de la misma manera en que las tablas silver ya se derivan de cualquier fuente operacional. Lo que ya no se necesita es un pipeline de CDC cuyo propósito era crear la copia en el lake.

Mito 3: “Los formatos de tabla abierta implican consistencia eventual”

La realidad: cada consulta analítica lee una instantánea consistente. Las confirmaciones (commits) que aún no han llegado al lake se leen desde los pageservers, por lo que no se pierde nada confirmado antes de la consulta.

Iceberg y Delta proporcionan aislamiento de instantáneas en el almacenamiento de objetos, y este tiene una alta latencia. Por lo tanto, es natural concluir que el análisis siempre va retrasado, que muchas tablas pequeñas no pueden mantenerse actualizadas y que una unión entre tablas no puede ser coherente. Esa descripción encaja con la ingesta de CDC en un lago de datos.

Esto depende de una suposición: que una consulta solo puede ver lo que ya se ha guardado en el almacenamiento de objetos. En LTAP, una consulta también puede ver páginas que aún no están en el almacenamiento de objetos. Eso cambia la respuesta, y se ve más fácilmente siguiendo una consulta.

Cuando comienza una consulta analítica,

  1. Pide a Postgres el LSN actual. Eso es una búsqueda de metadatos.
  2. Lee casi todos los datos del almacenamiento de objetos: todo lo materializado hasta ese LSN. Un motor que no comparte la CPU con el nodo OLTP realiza esta lectura.
  3. Combina el resto desde el servidor de páginas. Las páginas que se confirmaron después de la última materialización provienen del servidor de páginas y se combinan encima.

Postgres no atiende nada del tráfico de lectura masiva; devuelve un número y, como mucho, esas páginas recientes. El lago no necesita contener la última confirmación para que esa confirmación sea visible. Necesita contener casi todo, además de una forma de recuperar las páginas que se confirmaron después de la última materialización. El LSN es el límite: le indica al motor hasta dónde tiene que llegar la combinación.

El mismo LSN también mantiene las uniones coherentes. CDC se aplica tabla por tabla, por lo que una relación puede estar en una posición de ranura posterior a otra, y una unión mezcla dos puntos en tiempo diferentes. LTAP lee cada tabla en un único LSN, el mismo tipo de límite que Postgres usa para REPEATABLE READ, en lugar de hacerlo en el último momento en que cada canalización guardó los cambios. Ese LSN es una marca de agua compartida. Se están desarrollando API para leer cambios recientes desde una marca de agua tanto de forma nativa para Lakebase como como una extensión para Postgres anterior.

Parquet proporciona la mayor parte de la tabla, y los servidores de páginas completan las confirmaciones recientes hasta el LSN

Las tablas pequeñas representan un coste de metadatos, no una limitación de frescura. La sobrecarga de Iceberg son los archivos y las instantáneas. Para una relación de unas pocas filas, ese registro cuesta más de lo que ahorra, y el diseño no importa para el rendimiento del análisis. Esas tablas permanecen en la caché de páginas, participan en la lectura coherente por LSN y se saltan la confirmación de Iceberg.

Esto deja dos afirmaciones que parecen iguales pero no lo son:

  • "Una consulta larga no ve las nuevas confirmaciones": es verdad y es correcto. Una consulta que comenzó en el LSN X no verá las confirmaciones posteriores a X. Eso es aislamiento de instantáneas, el mismo contrato que REPEATABLE READ, no un retraso de réplica.
  • "A una consulta le faltan datos confirmados": esto sería un resultado incorrecto, ya que una consulta comenzó en X y se perdió una confirmación que ya era persistente en X porque todavía estaba en un búfer de CDC. La combinación de páginas recientes a partir de ese LSN es cómo LTAP evita este caso.

La instantánea columnar materializada puede retrasarse con respecto a la principal por el intervalo de compactación más reciente, pero la consulta en sí no. El hecho de que los archivos Parquet puedan estar retrasados varios minutos no significa que un lector no pueda ver los datos confirmados.

Mito 4: “La replicación de Postgres es todo lo que necesitamos”

La realidad: la replicación lógica es una forma costosa de mantener el lago sincronizado con la base de datos. Reproduce cada cambio, fila por fila, y necesita una canalización que pueda mantenerse al día. Decodificar el WAL en paralelo no evita esto, porque los registros de registro no se pueden procesar de forma independiente.

Una forma estándar de realizar análisis en un Postgres actualizado es habilitar la replicación lógica. Debezium, PeerDB, pgoutput y herramientas similares parten de la observación de que la base de datos ya emite un flujo de cambios y se preguntan qué formato de almacenamiento se necesita además de eso.

La cuestión es si un flujo de cambios es una buena manera de construir una tabla en el lago. Dos propiedades del flujo dicen que no: cuánto tiene que leer y cuántos estados tiene que mantener.

La replicación lógica lee cada cambio

El WAL es un registro físico de ediciones de páginas, escrito para que Postgres pueda fallar y recuperarse. La decodificación lógica lo convierte en eventos de fila en el orden de confirmación. Esa conversión no puede colapsar muchas actualizaciones de la misma página en la imagen actual de la página; cada cambio tiene que pasar. En una página activa, Postgres puede registrar los mismos 8 KB cien veces entre puntos de control. La decodificación lógica emite cien eventos, y luego un trabajo posterior los actualiza en Parquet por clave principal. Por el contrario, una ruta de organización por niveles de página lee la página una vez. En las cargas de trabajo con uso intensivo de escritura que hemos medido, CDC lee al menos el volumen de WAL, mientras que la compactación de páginas sucias puede leer una fracción de este.

La replicación lógica transporta estado

Una ranura de replicación es un cursor en el WAL que el consumidor debe seguir avanzando. Si el consumidor se retrasa, el WAL permanece en el disco hasta que se elimina la ranura o se llena el disco. La decodificación lógica no emite DDL, por lo que ALTER TABLE, los cambios de tipo y los cambios de nombre hacen que los eventos sean incoherentes con el catálogo actual o invalidan la ranura. Las tablas sin una clave principal necesitan REPLICA IDENTITY FULL. Debido a que la canalización es costosa, normalmente se aplica a un subconjunto de tablas. Eso es lo opuesto a que cada tabla de Postgres aparezca en el lago por el hecho de existir.

Una afirmación relacionada: se puede omitir la decodificación lógica y decodificar el WAL en paralelo

Los servidores de páginas ya consumen WAL, por lo que una ruta paralela de registro a Parquet puede parecer un pequeño paso adicional. Es posible en principio. No se ha creado como un extractor de producción y no es la ruta que utiliza LTAP. Los registros WAL están ordenados porque los posteriores asumen los anteriores. La visibilidad reside en pg_xact, la matriz de procesos y el catálogo en ese LSN, no en la tupla. Los trabajadores independientes no pueden decodificar cada uno un rango de bytes disjunto y emitir filas actuales correctas.

Lo que LTAP paraleliza son las páginas, no los registros de registro. El sistema pregunta qué páginas han cambiado desde la última instantánea (resúmenes de WAL en Postgres 17+ o los árboles de combinación estructurados en registros del servidor de páginas), y cada página sucia es un trabajo independiente. Ese conjunto se particiona, las páginas se transcodifican y se confirma una instantánea de Iceberg. El registro es cómo se hicieron duraderas las escrituras y una forma de descubrir qué páginas cambiaron. La instantánea son las páginas actuales, no una reproducción de cada registro que las ensució.

Nada de esto convierte a la replicación en la herramienta incorrecta para los trabajos previstos: migraciones, actualizaciones de versiones principales y transiciones a un segundo Postgres. Pero usar la replicación lógica como almacenamiento produce una segunda fuente de la verdad.

Cierre

Los cuatro mitos provienen del mismo malentendido: tratar cada materialización de los datos como una segunda base de datos.

LTAP mantiene una tabla lógica, y el lago es su copia duradera. Las páginas de montón, los índices y las cachés son la forma en que Postgres sirve esa tabla con latencia OLTP, al igual que un índice de cobertura sirve consultas sobre un montón. Un motor OLAP escanea el Parquet directamente y combina los cambios coherentes a nivel transaccional desde la última materialización.

Ninguna de estas capas añade un segundo catálogo o una segunda fuente de la verdad que pueda desviarse.

Para obtener más información sobre cómo la arquitectura de almacenamiento de Lakebase conduce a LTAP, consulte esta publicación.

(Esta entrada del blog ha sido traducida utilizando herramientas basadas en inteligencia artificial) Publicación original

Etiquetas relacionadas:

Lakebase

Recibe las últimas publicaciones en tu bandeja de entrada

Suscríbete a nuestro blog y recibe las últimas publicaciones directamente en tu bandeja de entrada.