Be Software Architecture Wise
Be Wise Apps

Read in English · Lire en français · Auf Deutsch lesen

Capítulo 7 de 12 · De intermedio a avanzado

Arquitectura de datos

Los datos sobreviven al código y, en los sistemas distribuidos, son la parte más difícil de hacer bien. Este capítulo trata quién es el propietario de cada dato y por qué una base de datos compartida acopla los servicios, cómo elegir entre bases de datos relacionales y de otros tipos, qué garantizan realmente las transacciones y los niveles de aislamiento, cómo funcionan y fallan la replicación y el particionamiento, CQRS y event sourcing, la caché, cómo hacer evolucionar los esquemas sin tiempo de inactividad, y la analítica, el streaming y el data mesh. Está dirigido a desarrolladores y arquitectos que ya conocen los estilos distribuidos del Capítulo 6 y necesitan tomar decisiones sólidas y defendibles sobre los datos.

Introducción en video al capítulo 7

7 min · narrado en inglés, con subtítulos
Solo escuchar (audio)
Leer la transcripción

Te damos la bienvenida al Capítulo 7, Arquitectura de datos. El código puede reescribirse en meses, pero los datos viven durante décadas. Las cuentas de clientes, los libros mayores, los pedidos y los historiales médicos sobreviven a todos los frameworks y a todos los servicios que los tocan. Mover esos datos es lento, arriesgado y caro. Por eso las decisiones de este capítulo están entre las más significativas que toma un arquitecto: son difíciles de revertir, de amplio alcance y decisivas para la disponibilidad, el rendimiento y la modificabilidad.

Este capítulo está dirigido a desarrolladores y arquitectos que ya conocen los estilos distribuidos del Capítulo 6 y que ahora necesitan tomar decisiones sólidas y defendibles sobre los datos. Se apoya directamente en el Capítulo 6. Dividir el código en servicios es la mitad fácil. En cuanto hay varios servicios, alguien tiene que decidir quién puede cambiar cada dato, cómo lo ven los demás y qué ocurre cuando sus copias no coinciden. También presupone los fundamentos de bases de datos de la sección del Capítulo 0 sobre almacenar datos. Si las tablas, las consultas y las transacciones son nuevas para ti, empieza por ahí. Y conduce al Capítulo 8, que protege estos datos y el sistema en su conjunto.

El capítulo tiene ocho secciones y sigue dos ejemplos recurrentes de principio a fin: una plataforma de reparto de comida, con su hora punta de la cena, las ubicaciones de los repartidores y las cartas, y un banco en línea, donde perder o contar dos veces un solo pago es inaceptable. La sección siete punto uno, sobre la propiedad de los datos, establece la regla más importante: todo hecho importante debe tener un único sistema de registro y un único escritor. Explica por qué una base de datos compartida acopla los servicios, por muy limpiamente que esté separado su código. La sección siete punto dos repasa los almacenes relacionales, documentales, clave-valor, de grafos, de series temporales y de otros tipos. Sostiene que la base de datos relacional sigue siendo la opción por defecto adecuada para los sistemas de registro, y que cada almacén especializado debe ganarse su lugar. La sección siete punto tres va más allá del conocido acrónimo ACID, hasta las anomalías que causa la concurrencia, como las actualizaciones perdidas y el write skew, y hasta lo que garantizan realmente los niveles de aislamiento en las bases de datos más usadas. La sección siete punto cuatro explica cómo las bases de datos copian y dividen los datos entre máquinas, qué efecto tienen el retardo de replicación y el failover sobre la corrección, y cómo elegir una clave de partición a partir de las cifras.

Esta es la primera y más importante idea del capítulo, de la sección siete punto uno. La imagen compara dos formas de dar sus datos a tres servicios. A la izquierda, los servicios de pedidos, cocina y reparto leen y escriben todos en una única base de datos compartida de pedidos, cartas y repartidores. Cualquier servicio puede cambiar cualquier tabla, así que cada tabla es una interfaz pública, y cualquier cambio de esquema requiere un lanzamiento coordinado. A la derecha, cada servicio tiene su propia base de datos. Cada esquema es privado, no hay joins entre bases de datos y los datos cruzan los límites solo mediante llamadas a la API y eventos. Ahora cada propietario puede cambiar su esquema por su cuenta. Esa independencia tiene un precio. Los joins, las transacciones y la integridad referencial entre servicios deben sustituirse por API, eventos, sagas y pipelines de informes, y la sección muestra cómo leer datos de los que no eres propietario.

La segunda mitad del capítulo trata los datos que se derivan de los sistemas de registro y el cambio a lo largo del tiempo. La sección siete punto cinco trata la segregación de responsabilidades entre comandos y consultas, o CQRS, y el event sourcing. Estos separan el modelo que acepta los cambios de los modelos que responden a las consultas, y almacenan un historial de eventos en lugar del estado actual, a un costo real en complejidad. La sección siete punto seis trata la caché: mantener copias cerca de donde se necesitan, desde el navegador hasta la base de datos, incluidas las estampidas que pueden tumbar un sistema cuando caduca una entrada popular. La sección siete punto siete acepta que todo esquema, ya sean tablas de base de datos, cargas útiles de API o eventos, cambiará mientras el sistema está en funcionamiento. Las reglas de compatibilidad y el patrón expandir y contraer permiten ese cambio sin tiempo de inactividad. Por último, la sección siete punto ocho pasa de hacer funcionar el negocio a entenderlo: almacenes de datos, lagos de datos y lakehouses, procesamiento de flujos, y el data mesh, una forma de organizar los datos analíticos en torno a los dominios.

Las secciones forman una cadena, y este diagrama de la sección siete punto dos muestra esa cadena en una plataforma de reparto de comida. Pedidos y Cartas escriben cada uno en su propia base de datos PostgreSQL. Estos son los dos únicos sistemas de registro, y contienen los pedidos, los pagos y las cartas. Todo lo demás es una copia deliberada. Las posiciones de los repartidores están en un almacén clave-valor en memoria y caducan a los treinta segundos. La captura de datos de cambios copia los cambios de las cartas en un motor de búsqueda, con unos pocos segundos de retardo. Y un almacén de datos recibe los pedidos, las cartas y una muestra de los puntos de ruta de los repartidores para la analítica, con horas de antigüedad. Cada copia es más rápida o más cómoda para algún propósito, cada una está desactualizada en cierta medida y cada una puede reconstruirse.

Esa cadena lleva a la única idea que debes llevarte de este capítulo. Para cada dato importante, deberías poder responder tres preguntas. Primera, ¿quién es su único escritor? Segunda, ¿dónde se aplican sus reglas? Y tercera, ¿cuán desactualizada puede estar cada copia? La mayoría de los problemas de datos de los sistemas reales, como pedidos que cambian de estado hacia atrás, informes que no coinciden con el libro mayor, reservas duplicadas y clientes que no pueden ver sus propios cambios, son fallos a la hora de responder deliberadamente a una de esas preguntas. Las técnicas de este capítulo son formas de responderlas bien, y cada una de ellas es un compromiso entre consistencia, disponibilidad, rendimiento, costo y el esfuerzo de operar el sistema.

Al final del capítulo, sabrás asignar la propiedad de los datos, incluidos los casos difíciles en que varios servicios quieren escribir los mismos datos. Sabrás elegir una base de datos para cada conjunto de datos, según su forma, sus patrones de acceso, sus necesidades de consistencia y su escala, y justificar el costo de cada almacén adicional. Sabrás proteger un camino de lectura, modificación y escritura con bloqueos, comprobaciones de versión o transacciones serializables. Y sabrás planificar los cambios de esquema, con reglas de compatibilidad y el patrón expandir y contraer, para que no requieran tiempo de inactividad.

Como las secciones forman una cadena, lo mejor es leerlas en orden. Pero cada una se sostiene también por sí sola, así que puedes ir directamente a la sección que necesites. Calcula unas tres horas y media para leer el capítulo entero. Al final de cada sección hay preguntas de autoevaluación. Respóndelas mentalmente antes de mirar las respuestas; te muestran rápidamente lo que se te ha quedado. Cuando estés listo, hay una prueba del capítulo opcional, que lleva unos cuarenta y cinco minutos. Tiene veinte preguntas de opción múltiple y dos respuestas escritas. La nota de aprobado es el ochenta por ciento.

Esa es la forma del capítulo. Empieza por la sección siete punto uno, sobre la propiedad de los datos y la base de datos por servicio, donde se expone en detalle la regla de un único escritor para cada hecho. Nos vemos allí.

Descargar el capítulo (PDF)Leer en la app

De un vistazo

Aprenderás a

  • Explicar por qué una base de datos compartida acopla los servicios, y asignar la propiedad de los datos, incluidos los casos en que varios servicios escriben los mismos datos.
  • Elegir una base de datos para cada conjunto de datos según la forma de los datos, los patrones de acceso, las necesidades de consistencia, la escala, las operaciones y las habilidades del equipo, y justificar el costo de cada almacén adicional.
  • Distinguir los niveles de aislamiento y las anomalías que permiten, incluidas las actualizaciones perdidas y el write skew, y proteger un camino de lectura-modificación-escritura con bloqueos, comprobaciones de versión o transacciones serializables.
  • Explicar la replicación líder-seguidor, multilíder y sin líder, las anomalías que causa el retardo de replicación y los riesgos del failover y del split brain.
  • Elegir un esquema de particionamiento y una clave de partición (shard key) a partir de volúmenes y consultas medidos, y explicar el hashing consistente, las claves calientes (hot keys) y los índices secundarios.
  • Decidir cuándo CQRS, event sourcing y la caché compensan sus costos, y evitar sus modos de fallo habituales.
  • Planificar los cambios de esquema con reglas de compatibilidad y el patrón expandir y contraer (expand and contract) para que no requieran tiempo de inactividad.
  • Distinguir las arquitecturas de datos operativas y analíticas: almacenes de datos, lagos de datos, lakehouses, procesamiento de flujos y data mesh.

Antes de empezar

Capítulo 6, en especial las secciones sobre microservicios, arquitectura dirigida por eventos, consistencia, CAP y PACELC, y sagas. La sección del Capítulo 0 sobre almacenar datos cubre los fundamentos de bases de datos que aquí se presuponen.

Tiempo

Unas 3½ horas de lectura; 45 minutos para la prueba.

Términos clave

sistema de registro (system of record) · base de datos por servicio · persistencia políglota · nivel de aislamiento · aislamiento de instantánea (snapshot isolation) · write skew (sesgo de escritura) · retardo de replicación (replication lag) · hashing consistente · CQRS · event sourcing · cache-aside · expandir y contraer (expand and contract) · lakehouse · data mesh

Por qué los datos son la parte difícil

El código puede reescribirse en meses; los datos viven durante décadas. Las cuentas de clientes, los libros mayores, los pedidos y los historiales médicos sobreviven a todos los frameworks y a todos los servicios que los tocan, y moverlos es lento, arriesgado y caro. Por eso las decisiones de este capítulo están entre las más significativas que toma un arquitecto, en el sentido del Capítulo 1: son difíciles de revertir, de amplio alcance y decisivas para atributos de calidad como la disponibilidad, el rendimiento y la modificabilidad.

El Capítulo 6 dividió los sistemas en servicios que se comunican a través de una red. Dividir el código es la mitad fácil. En cuanto hay varios servicios, alguien tiene que decidir quién puede cambiar cada dato, cómo lo ven los demás, qué garantías se mantienen cuando muchos usuarios actúan a la vez y qué ocurre cuando las copias de los datos no coinciden. El capítulo sigue dos ejemplos recurrentes de principio a fin: una plataforma de reparto de comida, con su hora punta de la cena, las ubicaciones de los repartidores y las cartas, y un banco en línea, donde perder o contar dos veces un solo pago es inaceptable.

Ser propietario de los datos, almacenarlos y protegerlos

Las cuatro primeras secciones tratan los datos operativos con los que funcionan los sistemas. Propiedad de los datos establece la regla más importante: todo hecho importante debe tener un único sistema de registro y un único escritor. Explica por qué una base de datos de integración compartida acopla los servicios por muy limpiamente que esté separado su código, cómo resolver los casos en que varios servicios quieren escribir los mismos datos, cómo leer datos de los que no eres propietario y cómo los contratos de datos hacen fiables los datos compartidos.

Elegir una base de datos repasa los almacenes relacionales, documentales, clave-valor, de columnas anchas, de grafos, de series temporales, de búsqueda, vectoriales y de SQL distribuido, y sostiene que la base de datos relacional sigue siendo la opción por defecto adecuada para los sistemas de registro, y que los almacenes especializados se ganan su lugar cumpliendo un requisito que la opción por defecto no puede cumplir. Transacciones y aislamiento va más allá del conocido acrónimo ACID, hasta las anomalías que causa la concurrencia, como las actualizaciones perdidas y el write skew, lo que garantizan realmente los niveles de aislamiento en PostgreSQL, MySQL, Oracle y SQL Server, y cuándo usar bloqueos, comprobaciones de versión o transacciones serializables. Replicación y particionamiento explica cómo las bases de datos copian y dividen los datos entre máquinas, qué efecto tienen el retardo de replicación y el failover sobre la corrección, y cómo elegir una clave de partición a partir de las cifras.

Derivar, almacenar en caché y hacer evolucionar los datos

La segunda mitad trata los datos que se derivan de los sistemas de registro y el cambio a lo largo del tiempo. CQRS y event sourcing separa el modelo que acepta los cambios de los modelos que responden a las consultas, y muestra cómo almacenar un historial de eventos en lugar del estado actual permite la auditoría y las consultas temporales, a un costo real en complejidad. Caché cubre los patrones, los niveles y los modos de fallo de mantener copias cerca de donde se necesitan, desde el navegador hasta la base de datos, incluidas las estampidas que pueden tumbar un sistema cuando caduca una entrada popular.

Evolución de esquemas aborda el hecho de que todo esquema, ya sean tablas de base de datos, cargas útiles (payloads) de API o eventos, cambiará mientras el sistema está en funcionamiento, y muestra cómo las reglas de compatibilidad y el patrón expandir y contraer permiten el cambio sin tiempo de inactividad. Por último, analítica y streaming pasa de hacer funcionar el negocio a entenderlo: almacenes de datos, lagos de datos y lakehouses, procesamiento de flujos, y el data mesh como forma de organizar los datos analíticos en torno a los dominios.

Cómo encajan las secciones

Las secciones forman una cadena. La propiedad decide dónde se escribe cada hecho. La elección de la base de datos y sus garantías transaccionales deciden qué reglas pueden aplicarse a bajo costo dentro de ese propietario. La replicación y el particionamiento deciden cómo sobreviven a los fallos los datos del propietario y cómo crecen más allá de una máquina. Todo lo demás en el capítulo es una copia deliberada: modelos de lectura, cachés, índices de búsqueda, almacenes de datos y flujos. Cada copia es más rápida o más cómoda para algún propósito, y cada una está desactualizada en cierta medida. La evolución de esquemas permite que el propietario y todas sus copias cambien sin romperse entre sí.

El capítulo presupone el vocabulario de sistemas distribuidos del Capítulo 6, en especial los modelos de consistencia, la arquitectura dirigida por eventos y las sagas y el patrón outbox. Da paso al Capítulo 8, que protege estos datos, y al Capítulo 9, que mantiene rápidos y disponibles los sistemas que los contienen.

La idea que debes llevarte

Para cada dato importante, deberías poder responder tres preguntas: ¿quién es su único escritor?, ¿dónde se aplican sus reglas? y ¿cuán desactualizada puede estar cada copia? La mayoría de los problemas de datos de los sistemas reales, como pedidos que cambian de estado hacia atrás, informes que no coinciden con el libro mayor, reservas duplicadas y clientes que no pueden ver sus propios cambios, son fallos a la hora de responder deliberadamente a una de esas preguntas. Las técnicas de este capítulo son formas de responderlas bien, y cada una de ellas es un compromiso entre consistencia, disponibilidad, rendimiento, costo y el esfuerzo de operar el sistema.

Las 8 secciones

7.1 · Intermedio · 24 minPropiedad de los datosQuién puede cambiar cada dato, por qué una base de datos compartida acopla los servicios, cómo resolver la propiedad conjunta, y cómo leer datos que no te pertenecen, elaborar informes sobre ellos y establecer contratos para usarlos.Leer →7.2 · Intermedio · 25 minElegir una base de datosEn qué es buena y en qué es mala cada familia de bases de datos, desde las relacionales hasta las vectoriales y el SQL distribuido, y cómo elegir según la forma de los datos, los patrones de acceso, la consistencia, la escala, la operación y las habilidades del equipo.Leer →7.3 · Avanzado · 28 minTransaccionesQué garantiza realmente ACID, las anomalías que permiten los niveles de aislamiento, cómo funcionan MVCC y el aislamiento de instantánea (snapshot isolation), por qué engañan los nombres de los niveles y cuándo usar bloqueos, comprobaciones de versión o transacciones serializables.Leer →7.4 · Avanzado · 30 minReplicación y particionamientoCómo copian los datos las bases de datos para lograr disponibilidad y escalar las lecturas, qué efectos tienen el retardo de replicación y el failover en la corrección, y cómo el particionamiento por rango o por hash, el hashing consistente y los índices secundarios dan forma a un diseño con sharding.Leer →7.5 · Avanzado · 26 minCQRS y event sourcingSeparar el modelo que modifica los datos de los modelos que los leen, almacenar el estado como una secuencia de eventos de solo anexado (append-only) y los costos reales: consistencia eventual, versionado de eventos y datos personales.Leer →7.6 · Intermedio · 24 minCachéPor qué las cachés aceleran los sistemas y qué cuestan: cache-aside, read-through, write-through, write-behind y refresh-ahead, TTL e invalidación, estampidas (stampedes), niveles de caché, cabeceras HTTP y desalojo (eviction).Leer →7.7 · Intermedio · 25 minEvolución de esquemasCambiar los esquemas de bases de datos, API y eventos mientras el sistema sigue funcionando: compatibilidad hacia atrás, hacia adelante y completa, expandir y contraer, herramientas de migración, backfills de gran volumen y registros de esquemas para Avro y Protocol Buffers.Leer →7.8 · Avanzado · 27 minAnalítica y streamingCómo se diseña la arquitectura de los datos analíticos: OLTP frente a OLAP, almacenes de datos (data warehouses) y esquemas en estrella, ETL y ELT, data lakes y lakehouses, procesamiento de flujos con tiempo del evento y marcas de agua (watermarks), Lambda y Kappa, y data mesh.Leer →

Prueba del capítulo

Comprueba lo que has entendido del capítulo 7

Opcional: 20 preguntas de opción múltiple y 2 respuestas escritas breves, elegidas de nuevo cada vez de un banco de 72 preguntas. Nota de aprobado: 80%. Superar todas las pruebas de capítulo y después la evaluación final da derecho al Certificado de Finalización Be Wise.

Haz la prueba del capítulo 7 en la app

Lecturas recomendadas