Ir al contenido
wannacode

Cómo elegir una base de datos

En resumen: Elige una base de datos según tus datos y las preguntas que les haces: una base relacional guarda la verdad, y otro tipo se añade a su lado solo donde ella es débil.

Problema

Muchos tipos de bases de datos sobre la mesa

El módulo ha mostrado clave-valor, documentos, flujos de eventos, grafos, columnas y series temporales, búsqueda de texto, vectores y clústeres. Cada una de estas bases de datos es excelente en algo. El nuevo proyecto de la tienda pregunta: ¿cuál elegimos?

El camino equivocado es empezar por la base de datos («usamos MongoDB porque es moderna»). El camino correcto es empezar por los datos y por las preguntas que les harás, y añadir una base de datos nueva solo cuando haya una pregunta que la principal no responde bien.

La idea

Cinco preguntas

  1. ¿Qué forma tienen los datos? Filas con las mismas columnas, documentos enteros con partes anidadas, conexiones entre cosas, registros a lo largo del tiempo, texto libre.
  2. ¿Qué preguntas? Una cosa por clave, un informe sobre todo, «quién está conectado con quién», «qué palabras», «qué es parecido».
  3. ¿Qué importancia tiene la consistencia? El dinero y el stock necesitan transacciones y leer la última escritura. Un contador de «me gusta» puede ir con un segundo de retraso.
  4. ¿Qué tamaño tienen los datos y la carga? Miles o miles de millones de filas, diez o cien mil consultas por segundo. La mayoría de los proyectos son mucho más pequeños de lo que creen.
  5. ¿Quién se va a ocupar? Cada base de datos necesita copias, monitorización, actualizaciones y alguien que sepa qué hacer cuando se cae.
La pregunta Tipo de base de datos
Dinero, pedidos, stock, todo lo que tiene que estar bien relacional (PostgreSQL, MySQL)
Lo mismo por clave miles de veces, sesiones, carritos clave-valor (Redis)
Objetos enteros con estructuras distintas documental (MongoDB) o JSONB
Muchos sistemas se enteran del mismo evento flujo de eventos (Kafka)
Recomendaciones, redes, fraude a través de varios pasos de grafos (Neo4j)
Informes sobre millones de filas, sensores, métricas columnar, series temporales (ClickHouse, TimescaleDB)
Un cuadro de búsqueda, palabras en un texto búsqueda de texto completo (Elasticsearch)
«Parecido en significado», un chatbot sobre documentos vectorial (pgvector, Qdrant)

La idea

Empieza con PostgreSQL

Para la mayoría de los proyectos nuevos, el comienzo sensato es una sola base de datos relacional. PostgreSQL por sí sola cubre buena parte del módulo: columnas JSONB para documentos, tsvector para la búsqueda de texto, pgvector para vectores, TimescaleDB para series temporales, réplicas de lectura y la partición de tablas por tiempo. No es la mejor en cada una de ellas, pero es suficientemente buena, y una base de datos es mucho más fácil de mantener que cinco.

Una base de datos aparte compensa cuando hay una pregunta concreta que la principal responde despacio o con dificultad, y lo has medido: la caché, porque la misma consulta se ejecuta 2000 veces por minuto; el buscador, porque la búsqueda es la tarea principal del sitio; el almacén de datos, porque los informes frenan la caja.

Más precisamente, para curiosos

Esto se llama persistencia políglota: distintas bases de datos para distintas partes del sistema. Funciona bien cuando una de ellas es claramente la fuente de la verdad y las otras son copias que se pueden reconstruir. Funciona mal cuando dos bases de datos guardan partes distintas de la misma verdad y nadie sabe cuál tiene razón.

Míralo

La tienda cuando crece

Así podría verse la tienda al cabo de unos años, con cada parte añadida cuando hizo falta:

  • PostgreSQL guarda los clientes, los productos, los pedidos y los pagos. Esta es la verdad. Tiene una réplica síncrona y una asíncrona.
  • Redis guarda la caché del catálogo, las sesiones y los carritos.
  • Kafka lleva los eventos «pedido realizado», «pagado», «enviado» al almacén, a las facturas y al correo electrónico.
  • Elasticsearch guarda una copia de los productos y las reseñas para el cuadro de búsqueda. Se llena a partir de los eventos.
  • ClickHouse es el almacén de datos para los informes. Se llena cada noche o desde el flujo.
  • pgvector en la misma PostgreSQL da «productos parecidos».

Todas las copias vienen de PostgreSQL. Si se rompe el índice de Elasticsearch, se reconstruye desde la base de datos. Al revés no se puede.

Problema

Las dos escrituras

El pedido se escribe en PostgreSQL, y después el programa envía un evento a Kafka. Si el programa se cae entre las dos cosas, el pedido está en la base de datos, pero falta el evento: el almacén nunca prepara el paquete. Si es al revés (primero el evento, después la base de datos), el almacén puede preparar un paquete para un pedido que luego fracasó.

Los dos sistemas no tienen una transacción común. La solución es una tabla outbox: el evento se escribe en una tabla de la misma base de datos, en la misma transacción que el pedido. O se escriben los dos, o ninguno.

SQLbase de datos: tienda

published_at es NULL: el evento aún no se ha enviado. Un programa aparte (un relay) lee los no enviados en orden, los envía al flujo y solo entonces los marca:

SQLbase de datos: tienda

Y si algo falla antes del COMMIT, no hay ni cambio ni evento:

SQLbase de datos: tienda
Más precisamente, para curiosos

El relay puede caerse después de haber enviado el evento pero antes de marcarlo. Entonces, al reiniciarse, lo envía otra vez. Por eso los consumidores del evento tienen que ser idempotentes, como las facturas en la lección sobre flujos. En lugar de un programa que lea la tabla, se suele usar Debezium: lee el registro de cambios de PostgreSQL (el WAL) y envía cada fila nueva de la outbox a Kafka. Esto se llama captura de cambios de datos (change data capture, CDC).

Pruébalo

Cancelar un pedido

El cliente cancela el pedido 42. En una transacción cambia su estado a cancelled y escribe un evento en la outbox para el tema orders con la clave order-42 y el contenido {"order":42,"event":"cancelled"}.

SQLbase de datos: tienda

Ejercicio

Cinco proyectos

Para cada proyecto: ¿qué base de datos es el cimiento, o qué añades a su lado?

1. Un banco guarda cuentas y las transferencias entre ellas. La suma de todas las cuentas nunca puede desajustarse. ¿Cuál es el cimiento?
2. Una aplicación de reparto muestra dónde está el mensajero. Cada mensajero envía sus coordenadas cada 5 segundos, y el gráfico muestra la última hora. ¿Qué encaja mejor con estos datos?
3. Un sitio de anuncios clasificados quiere «anuncios parecidos» por texto y fotos, no por palabras iguales. ¿Qué añades junto a la base de datos principal?
4. Una plataforma de aprendizaje guarda cursos con estructuras distintas: capítulos, lecciones, vídeos, pruebas, todo anidado y diferente en cada curso. Un curso entero se lee y se escribe de una vez. ¿Qué encaja de forma más natural?
5. Una tienda con 300 pedidos al día, un programador y PostgreSQL. El jefe ha leído que los grandes usan sharding. ¿Qué haces?

Test

Ponte a prueba

1. El programa escribe el pedido en PostgreSQL y después envía un evento a Kafka. ¿Qué pasa si se cae entre las dos cosas?
2. ¿Qué es cierto de cada base de datos nueva en un proyecto?
3. La caché en Redis, el índice en Elasticsearch y el almacén de datos tienen una copia de los pedidos. ¿Dónde está la verdad?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·