Artículo

Sistemas Distribuidos

La consistencia eventual es una decisión de producto

La consistencia suele archivarse como 'detalle del backend', pero el desfase se filtra directo en la interfaz y en las reglas del negocio. Decidir cuánto desfase es aceptable es una decisión de producto: así se trata como tal.

Hay un momento en casi todo diseño de sistemas en el que alguien dice «lo haremos eventualmente consistente» y todos asienten, y la reunión sigue. Suena a detalle técnico: una propiedad de la base de datos, una casilla en la arquitectura. Se archiva como backend, lo deciden los ingenieros, y nunca se menciona a quienes son dueños del producto.

Ese es el error. Porque en el momento en que un sistema es eventualmente consistente, un usuario puede ver datos desfasados, y cuánto desfase, por cuánto tiempo y qué se le permite hacer mientras están desfasados no son preguntas de base de datos. Son preguntas sobre la experiencia y el negocio. La consistencia eventual no se queda en el backend. Se filtra hasta la pantalla.

El problema: la consistencia es invisible hasta que deja de serlo

Definición

Consistencia eventual

Una garantía de que, si no se hacen nuevas actualizaciones, todas las réplicas de un dato eventualmente convergerán al mismo valor. Lo que explícitamente no promete es cuándo. Entre una escritura y esa convergencia, distintos lectores pueden ver legítimamente valores distintos, y ninguno está equivocado.

Los sistemas distribuidos vuelven inevitable esta disyuntiva. El teorema CAP es la versión sin rodeos: cuando la red se particiona —y a escala lo hará—, eliges entre mantenerte consistente (rechazar lecturas y escrituras hasta poder ponerte de acuerdo) o mantenerte disponible (seguir sirviendo, y reconciliar después). La mayoría de los sistemas que necesitan mantenerse en pie eligen la disponibilidad, lo que significa elegir la consistencia eventual. Cualquier arquitectura orientada a eventos hereda la misma propiedad por construcción: un consumidor reacciona un instante después de que el productor emite, así que siempre hay una ventana en la que la escritura ya ocurrió pero la reacción no.

El problema es que esa ventana es invisible en el código y vívida en la pantalla. Un usuario actualiza su perfil, la escritura tiene éxito, la página recarga desde una réplica que no se ha puesto al día, y su cambio desapareció, salvo que no es así: solo llegó tarde. Para el ingeniero esto es «desfase de replicación esperado». Para el usuario es un error, y lo reportará como tal.

Por qué importa: el mismo desfase, dos veredictos

Considera dos sistemas, ambos eventualmente consistentes, ambos con unos segundos de desfase.

El primero es un feed de redes sociales. Publicas, y durante dos segundos un amigo en otra región no lo ve. A nadie le importa. Nadie lo nota siquiera. El dominio tiene una tolerancia enorme al desfase: un feed ligeramente viejo es indistinguible de uno fresco, y el costo de equivocarse es cero.

El segundo es el saldo de una cuenta bancaria. Tienes $50. Dos retiros de $40 llegan a dos réplicas que no se han reconciliado. Cada una ve $50, cada una aprueba, y ahora la cuenta está en descubierto por $30. La misma propiedad técnica —unos segundos de divergencia— es un encogimiento de hombros en un dominio y un incidente financiero en el otro.

La base de datos no distingue entre un «me gusta» y un dólar. Solo el producto lo hace. Por eso el producto tiene que estar en la sala cuando decides cuán consistente ser.

Fíjate en qué difiere de verdad entre esos dos casos. No es la tecnología. Es el costo de actuar sobre datos desfasados, y ese costo es una propiedad del negocio, no de la infraestructura. Un ingeniero que elige un modelo de consistencia en aislamiento está, sin darse cuenta, tomando una decisión sobre riesgo financiero aceptable, o confusión de usuario aceptable, que no está en posición de tomar solo.

El modelo mental: un presupuesto de desfase

El replanteo útil es dejar de preguntar «¿consistente o no?» —un binario que oculta la decisión real— y empezar a preguntar «¿cuánto desfase es aceptable, y dónde?».

Piénsalo como un presupuesto de desfase: para cada dato que un usuario puede ver, una respuesta explícita a ¿cuán desactualizado se permite que esté antes de que sea un problema?. El presupuesto de un feed puede ser de segundos, y generoso. El presupuesto de un saldo mostrado puede ser cero para el número en sí, mientras que una lista de transacciones puede desfasarse un minuto. Un contador de «asientos restantes» en una página de reservas puede tolerar estar ligeramente alto, siempre que la reserva real se verifique contra una escritura fuertemente consistente en el momento de la compra.

DIAGRAMA

El presupuesto de desfase: el desfase crece desde que se acepta la escritura hasta que las vistas convergen, las lecturas caen en puntos distintos, y la decisión de producto es dónde cae el límite del presupuesto — dentro está bien, más allá (un precio al pagar) es un error.PRESUPUESTO DE DESFASE¿CUÁNTO DESFASE ES ACEPTABLE?⇄ EL PRODUCTO DECIDELÍMITE DEL PRESUPUESTOESCRITURA ACEPTADAVISTAS CONVERGENSALDO · FUERTEFEEDPERFILBÚSQUEDAPRECIO AL PAGAR
El desfase crece desde que se acepta una escritura hasta que todas las vistas convergen. Cada lectura cae en un punto distinto, y la decisión de producto es dónde cae el límite del presupuesto: dentro está bien, más allá —un precio mostrado al pagar— se vuelve un error.

Este replanteo convierte una propiedad arquitectónica abstracta en una conversación concreta de producto. «¿Cuán desfasado puede estar este número?» es una pregunta que un product owner sí puede responder, porque es una pregunta sobre sus usuarios y su riesgo, no sobre protocolos de replicación.

Guía práctica: tener la conversación

El objetivo es sacar la decisión a la superficie, ante quienes son dueños del costo, en un lenguaje que puedan razonar. Unos pocos movimientos lo hacen real.

Traduce el desfase a eventos visibles para el usuario. No digas «la réplica de lectura desfasa hasta cinco segundos respecto de la primaria». Di «después de que un usuario guarda, otro usuario podría ver el valor viejo hasta por cinco segundos, y esto es exactamente dónde aparece». Ahora es un escenario de producto, no una métrica de base de datos.

Pregunta qué pasa cuando está mal. Para cada lectura expuesta al desfase, pregunta al product owner: si un usuario actúa sobre datos de hace unos segundos, ¿cuál es el peor resultado? Una confusión leve es un presupuesto que puedes gastar. Gastar dinero dos veces no lo es. La respuesta te dice qué lecturas necesitan consistencia fuerte y cuáles no.

Haz la ventana honesta en la interfaz. Buena parte del dolor de la consistencia eventual no es el desfase en sí, sino fingir que no está ahí. «Guardado — sincronizando…», una actualización optimista que le muestra al usuario su propio cambio de inmediato, un discreto «actualizado hace un momento»: estas son decisiones de producto que vuelven aceptable el desfase por ser sinceras al respecto. El arreglo más confiable para las lecturas desfasadas a menudo no es más consistencia; es una interfaz que nunca mintió sobre ser instantánea.

Protege las escrituras, relaja las lecturas. La resolución común: exige consistencia fuerte en el momento de la escritura trascendente (el retiro, la reserva, la transferencia) donde la corrección es innegociable, y deja que las lecturas de alrededor sean eventualmente consistentes donde son baratas. El patrón outbox es una forma de sostener esa línea: permite a un servicio confirmar un cambio y anunciarlo de forma confiable en el mismo aliento, de modo que la propagación eventual hacia todos los demás sea al menos digna de confianza y sin pérdidas, aunque no sea instantánea.

Compensaciones

Elegir consistencia fuerte donde no la necesitas tiene su propio costo: latencia, disponibilidad reducida y un sistema que dice «no» durante las particiones en lugar de mantenerse en pie. La consistencia eventual es el valor por defecto correcto para la mayoría de las lecturas precisamente porque la mayoría de las lecturas son baratas de tener ligeramente mal. La habilidad no es elegir un modelo para todo el sistema, sino gastar tu presupuesto de consistencia donde compra algo y guardártelo en todo lo demás.

Y hay un costo de disciplina en hacer esto bien: significa que cada lectura que puede mostrar datos desfasados recibe una respuesta deliberada en lugar de una accidental. Eso es más reflexión por adelantado. También es la diferencia entre un sistema cuyo desfase fue diseñado y uno cuyo desfase es un flujo recurrente de tickets de «¿esto es un error?».

Ideas clave

  • La consistencia eventual se filtra en la UX y en las reglas del negocio: lo que un usuario ve y lo que se le permite hacer con datos desfasados son preguntas de producto, no detalles del backend.
  • El mismo desfase técnico es inofensivo en un dominio (un feed) y un incidente serio en otro (un saldo). La diferencia es el costo de actuar sobre datos desfasados, que solo el producto conoce.
  • Reemplaza el binario «consistente o no» por un presupuesto de desfase: por dato, ¿cuán desactualizado es aceptable antes de que sea un problema?
  • Ten la conversación en términos visibles para el usuario: traduce el desfase a escenarios, pregunta qué pasa cuando una lectura está mal, y sé honesto sobre la ventana en la interfaz.
  • Protege fuerte las escrituras trascendentes; relaja las lecturas. Gasta consistencia donde equivocarse es caro, y guárdatela en todo lo demás.

La consistencia eventual no es un ajuste que los ingenieros activan de camino a producción. Es una declaración sobre cuánta equivocación puede absorber el producto, y dónde. Decídela a propósito, con quienes son dueños del costo, o el sistema la decidirá por ti, un usuario confundido a la vez.

// seguir explorando

Seguir explorando