Episodio 5 · día 1, 9:00

El informe del mes

lectura · 14 mindominio · BCPS Bankoperación · informe regulatorio

Un año de movimientos, sumados

Ayer cerró el mes y Reportingver en el mapa tiene que mandar al regulador su informe: cuánto dinero se ha movido, por tipo de movimiento (pagos con tarjeta, transferencias, nóminas, retiradas) y por mes, en los últimos doce meses. Una sola consulta. Doce filas por cuatro tipos: 48 números.

La tentación es lanzarla sobre una réplica de Cuentas. Tiene todos los movimientos, al día, con el mismo esquema que Reporting ya conoce, y la réplica ya está pagada. ¿Para qué montar otra base de datos? Pero para sacar esos 48 números hay que leer doce meses de movimientos: millones de filas. Y hoy es día 1, y son las nueve de la mañana: la misma réplica está atendiendo a todo el mundo que mira si le ha llegado la nómina.

Filas o columnas

El reloj va a un minuto por segundo, desde las 8:30. A la izquierda, el informe se lanza sobre la réplica de Cuentas, que guarda la tabla de movimientos por filas y que a la vez atiende a la app. A la derecha, sobre un warehouse que guarda cada columna por separado y que se carga desde el primario: una vez cada noche, cada hora o en streaming, con el conector del episodio 4. Cada casilla de la rejilla es un trozo de lo que hay en disco: un mes de filas enteras a la izquierda, un mes de una sola columna a la derecha.

Arranca y, hacia las 9:00, lanza el informe. Mira los bloques que lee cada lado, cuánto tarda y cómo lo nota la app. Luego busca un movimiento concreto y prueba las tres formas de cargar el warehouse.

Qué ha pasado

Filas y columnas: la misma consulta, cien veces menos disco

La base de datos de Cuentas guarda cada movimiento como una fila entera, todas sus columnas juntas: id, cuenta, fecha, tipo, importe, concepto, contraparte, canal, saldo después… Es lo que necesita para operar: registrar un movimiento es escribir una fila, y enseñárselo a Ana, leerla.probar en el laboratorio Pero el informe solo necesita tres columnas (fecha, tipo e importe) y, como están mezcladas con todas las demás, la réplica tiene que leer la tabla entera: 300.000 bloques, 2,4 GB. Un año de movimientos, aunque de cada fila se quede con una séptima parte.

El warehouse guarda cada columna por separado. Lee solo las tres que necesita y, como una columna de fechas o de tipos tiene muchos valores repetidos, las guarda muy comprimidas: 2.000 bloques. Más de cien veces menos, para el mismo resultado exacto. Es la diferencia entre OLTP (online transaction processing: muchas operaciones pequeñas sobre pocas filas, lo que hace Cuentas) y OLAP (online analytical processing: pocas consultas enormes sobre pocas columnas, lo que hace Reporting).

Cuándo hace daño: el informe sobre la réplica

Mientras el informe lee sus 300.000 bloques, la réplica está al 150 %: la app, en plena mañana del día de cobro, pasa de esperar una décima de segundo a esperar varios, y el informe tarda una media hora porque tiene que compartir. Hay un daño menos visible: una consulta larga en una réplica de PostgreSQL choca con los cambios que llegan del primario (a lo mejor borran filas que el informe todavía está leyendo), y la réplica deja de aplicarlos hasta 30 segundos para no romper la consulta. Los clientes que miran su saldo en esa réplica lo ven con 30 segundos de retraso. Y si el informe dura más, PostgreSQL lo cancela.probar en el laboratorio A las diez de la noche, con la app casi parada, el mismo informe sobre la réplica ya no molesta a nadie: solo es lento.

Al revés, la búsqueda que el episodio 4 llevó a un índice aparte tiene aquí su versión pura:probar en el laboratorio soporte busca el movimiento 8812, con todos sus datos. La réplica va por el índice de la clave primaria a un solo bloque, donde está el movimiento entero: 3 milisegundos. El warehouse no tiene índices así: recorre la columna de ids para encontrarlo y luego saca un trozo de cada una de las demás columnas para rehacer la fila. Más de un segundo. Cada almacenamiento es rápido para lo suyo y torpe para lo del otro.

Cargar el warehouse: batch, incremental o streaming

El warehouse tiene que recibir los datos de algún sitio, y cómo se cargan decide su edad.probar en el laboratorio En batch nocturno, a las dos de la mañana se extrae todo lo del día y se carga de una vez: una carga fuerte para el primario, a una hora en que nadie la nota, y un dato «de anoche» todo el día siguiente. Cada hora, se extrae solo lo que ha cambiado desde la vez anterior: cargas pequeñas y un dato de hace menos de una hora. En streaming, el conector de CDC del episodio 4 manda cada cambio en segundos, sin parar.

Para el informe regulatorio, las tres dan exactamente lo mismo: el mes que se informa cerró ayer, y el batch de esta noche lo tenía entero. El streaming es la carga más fresca y también la que está encendida las veinticuatro horas, con su conector, su slot vigilado y su cómputo en el warehouse. Para un informe que se mira una vez al mes, es coste sin beneficio. Para un panel de fraude que tiene que ver los pagos de hace un minuto, sería justo al revés.

ETL o ELT

Por el camino, los datos cambian de forma. En el ETL clásico (extract, transform, load) se extraen de Cuentas, se transforman en un servidor intermedio (se limpian, se traducen los códigos, se calculan los campos que el informe necesita) y se cargan ya transformados. En el ELT se cargan en bruto, tal y como vienen de Cuentas, y se transforman después dentro del propio warehouse, con SQL. Con warehouses columnares capaces de procesar mucho a la vez, el ELT se ha impuesto: los datos en bruto se quedan guardados, y si mañana cambia una regla del informe, se vuelve a transformar sin volver a extraer nada de Cuentas.

Criterio

Un warehouse no es una réplica en columnas: también cambia el modelo. En Cuentas, un movimiento está normalizado: su fila apunta a una cuenta, la cuenta a sus titulares, y el tipo es un código. Es lo que permite escribir sin repetir nada ni dejar nada a medias. En el warehouse, el mismo movimiento se reorganiza en estrella: una tabla de hechos en el centro, con una fila por movimiento y sus números (el importe), y alrededor las dimensiones por las que se agrupa y se filtra: la cuenta, la fecha y el tipo. La dimensión fecha, por ejemplo, ya trae el mes, el trimestre y si era festivo, para no calcularlos en cada informe.

Cuentas · normalizado movimientos id · cuenta_id fecha · tipo_cod importe · concepto saldo_tras · … cuentas id · iban · saldo titulares cuenta · cliente tipo_cod: TJ, TR, NO, RE Warehouse · en estrella hechos_movimientos cuenta_id · fecha_id tipo_id · importe dim_cuenta iban · oficina dim_fecha mes · trimestre dim_tipo tipo · categoría
El mismo movimiento: normalizado para escribirlo una vez sin repetir nada; en estrella para sumarlo y agruparlo de mil formas. El informe del mes es una suma de importe agrupada por dos dimensiones.
Cuando…Réplica de Cuentas (filas)Warehouse (columnas)
Se lee un movimiento, o unos pocosSí: índice y un bloqueTorpe
Se suma o se agrupa un año de datosLee la tabla entera y le quita capacidad a la appSí: solo las columnas necesarias
El dato tiene que estar al segundoSíSolo en streaming, y cuesta
Hay que cruzar con datos de otros contextos (Tarjetas, Transferencias)No los tieneSí: para eso está

Y para la carga: la frescura que pide el informe más exigente que se va a lanzar sobre esos datos, no más. El regulador, a día vencido: batch nocturno. El extracto mensual, a fin de mes: igual. Un panel de operaciones que se mira durante el día: cada hora. Un panel de fraude: streaming, y pagar lo que cuesta.

En el mundo real

Los warehouses columnares son hoy productos gestionados: Snowflake, Google BigQuery, Amazon Redshift, Azure Synapse, o ClickHouse y DuckDB si se prefiere el código abierto. Casi todos separan el almacenamiento del cómputo, así que un informe grande no le quita nada a otro; y cobran por lo que se lee o por el tiempo de cómputo, lo que convierte leer tres columnas en vez de veinte en un ahorro directo. Las herramientas de ELT, como dbt, han hecho que la transformación sea SQL versionado dentro del warehouse.

Hay más formas de estar entre los dos extremos. El data lake guarda los datos en bruto, en ficheros baratos (a menudo en formato columnar, como Parquet) y aplica el esquema al leer, no al escribir. El lakehouse (Delta Lake, Apache Iceberg, Apache Hudi) añade a esos ficheros transacciones y tablas de verdad, para tener un warehouse encima de un lake. Y los motores HTAP (SingleStore, TiDB con TiFlash, SQL Server con índices columnares, el motor columnar de AlloyDB) intentan servir las dos cargas en un solo sistema, con una copia columnar interna que se mantiene sola. Cuando funcionan, se ahorran todo el camino de este episodio; el precio es depender de un motor que hace las dos cosas bien a la vez.

En cuanto a cómo se cargan, las arquitecturas Lambda mantienen dos caminos: un batch que lo recalcula todo cada noche, fiable, y un streaming que da el dato fresco mientras tanto, a costa de programarlo todo dos veces. Las Kappa se quedan solo con el streaming y, si hay que recalcular, vuelven a leer el log de cambios desde el principio: el mismo log del episodio 4, convertido en la fuente de todo lo demás.

Final de la serie

Un día de cobro y cinco sitios de los que leer. El saldo con el que se autoriza un pago, del primario, al día y dentro de la transacción. El saldo de la app, de una réplica, con segundos de retraso, y a salvo de lo que se confirmó justo antes de que el primario cayera. Lo que acabas de transferir, de una réplica que ya haya llegado a tu posición. El buscador, de un índice que alimenta el CDC. Y el informe del mes, de un warehouse cargado anoche. Ninguno está bien o mal: cada lectura tiene su frescura, y cuanto más lejos del primario se lee, más barata es la lectura y más vieja y más transformada llega. La tira de arriba ya está entera.

Quedan puertas abiertas. Repartir los datos entre varios primarios cuando lo que satura son las escrituras (sharding). Ponerse de acuerdo sobre quién es el primario sin que la red lo estropee (consenso). Y una caché delante de todo esto, que es el siguiente escalón del espectro por la izquierda: más cerca que el primario, y con sus propios problemas de frescura.

Próximamente Datos a escala, caché y coordinación Particionado y sharding, cachés y su invalidación, elección de líder y consenso: los bloques 3, 4 y 8 del catálogo.

← Todos los episodios · Reporting en el mapa de BCPS Bank