3.3

Ver en inglés

3.3 Sistemas distribuidos

Panorama y motivación

Un sistema distribuido es aquel cuyos componentes se ejecutan en más de una máquina y coordinan su trabajo a través de una red. En el instante en que una comunicación cruza el límite de un proceso a través de la red, heredan verdades incómodas que simplemente no existen dentro de un solo proceso. La red no es fiable y su latencia varía. Los mensajes pueden perderse, duplicarse, retrasarse o llegar desordenados. Los componentes remotos fallan por cuenta propia. No existe un reloj compartido. Las clásicas falacias de la computación distribuida (la red es fiable, la latencia es nula, el ancho de banda es infinito, la topología no cambia) nombran con precisión exactamente las suposiciones que provocan las caídas. Su labor consiste en diseñar para esa realidad desde el primer día, y no descubrir de golpe lo que un incidente ya no puede remediar.

Para una organización de gran envergadura, la distribución no es opcional. Cualquier sistema que sirva a escala nacional o global, que articule varios departamentos o que exija alta disponibilidad se extiende por numerosas máquinas, centros de datos y, con frecuencia, regiones. Las empresas operan sistemas transaccionales distribuidos, tuberías de eventos y despliegues multirregión. Los organismos públicos gestionan integraciones interinstitucionales en las que cada organismo es dueño de sus propios sistemas y nadie controla el conjunto. En ese escenario, la distancia entre un diseño sólido y uno frágil se manifiesta en caídas que aparecen en los titulares, en pagos de prestaciones que no llegan y en consecuencias regulatorias. Las técnicas de este capítulo (el razonamiento sobre consistencia, la idempotencia, los reintentos con retroceso, los disyuntores de circuito, los sagas y la observabilidad distribuida) son sus defensas estándar.

Lo más difícil de los sistemas distribuidos es que los fallos son parciales y persistentes. Un programa de una sola máquina o funciona o se derrumba. Un sistema distribuido puede estar a medio funcionar: algunas peticiones triunfan, otras agotan el tiempo de espera y otras se pierden en silencio, todo al mismo tiempo. Este capítulo se centra en el razonamiento y los patrones que permiten a un equipo grande construir sistemas que se degradan con elegancia y siguen siendo comprensibles bajo un fallo parcial.

Principios fundamentales

  • La red no es fiable. Diseñe cada interacción remota asumiendo que puede ser lenta, fallar, duplicarse o desordenarse.
  • No se puede tener consistencia perfecta y disponibilidad perfecta durante una partición. Elija de forma deliberada por cada interacción (CAP/PACELC) y recuerde que la latencia es un coste incluso cuando no hay partición.
  • Haga que las operaciones sean idempotentes. Si una operación puede reintentarse con seguridad, la mayor parte del tratamiento de fallos distribuidos se vuelve manejable.
  • Toda llamada remota necesita un tiempo de espera máximo. Las esperas ilimitadas convierten una sola dependencia lenta en una caída generalizada.
  • Prefiera la consistencia eventual cuando el negocio lo permita, pero déjelo explícito. Los usuarios y los auditores deben comprender cuándo pueden ver datos desactualizados.
  • Aísle los fallos. Los compartimentos y los disyuntores de circuito impiden que una componente fallida se extienda a todas las demás.
  • Lo que no se puede ver no se puede depurar. Los flujos distribuidos exigen trazado correlacionado, métricas y registros en cada salto.
  • «La entrega exactamente una vez» es un mito; el procesamiento exactamente una vez es un logro de ingeniería. Diseñe para entrega al menos una vez, con deduplicación.

Recomendaciones

Razonar sobre la consistencia con CAP y PACELC

El teorema CAP establece que durante una partición de red un sistema debe elegir entre consistencia (cada lectura ve la última escritura) y disponibilidad (cada petición recibe una respuesta). PACELC añade una segunda disyuntiva: En caso contrario (cuando no hay partición) se sigue intercambiando Latencia por Consistencia. No estampen la etiqueta al sistema entero. Decídanla por operación. La transferencia de saldo de un banco necesita consistencia fuerte y se negará antes que arriesgar un gasto doble. Un feed social o un contador de visualizaciones de producto puede aceptar datos desactualizados a cambio de disponibilidad y velocidad. Documenten qué modelo de consistencia emplea cada flujo de datos (fuerte, causal, lectura-de-propia-escritura o eventual) para que nadie suponga una garantía que el sistema no ofrece de hecho.

Construir idempotencia, tiempos de espera, reintentos y retroceso como un solo paquete

Traten estas cuatro técnicas como un conjunto indivisible. Asignen a cada operación remota un tiempo de espera máximo, de modo que una dependencia bloqueada no inmovilice un hilo eternamente. Ante el fallo, reintenten, pero solo con operaciones seguras de repetir. Seguro de repetir significa idempotente: atribuyan a cada petición una clave única y que el receptor deduplique, para que un reintento de «cargar tarjeta» no cobre dos veces. Espacen los reintentos con retroceso exponencial (exponential backoff) y aleatorización (jitter), para evitar una tormenta sincronizada de reintentos que convierta un bache breve en una denegación de servicio autoinfligida. Limiten el número de reintentos y el presupuesto temporal total, porque reintentar indefinidamente solo desplaza el fallo. Sin idempotencia, los reintentos son peligrosos. Sin retroceso, son destructivos.

Añadir disyuntores de circuito y compartimentos para frenar las cascadas

Un disyuntor de circuito (circuit breaker) vigila las llamadas a una dependencia y, tras un umbral de fallos, «abre»: responde con fallo rápido durante un período de enfriamiento en lugar de acumular más peticiones sobre un servicio al límite, y luego «medio-abre» para probar la recuperación. Así se frena la cascada en la que un servicio descendente lento agota todos los hilos de los llamantes hasta que el sistema entero se paraliza. Los compartimentos (bulkheads) particionan los recursos (pools de hilos, pools de conexiones) para que la saturación de una dependencia no consuma la capacidad que otras necesitan. Combinen ambos con degradación elegante: cuando una dependencia no crítica no está disponible, devuelvan respuestas en caché o predeterminadas en lugar de fallar la petición entera.

Gestionar transacciones distribuidas con sagas, no con compromiso de dos fases

En general, no se puede sostener una única transacción ACID (atomicidad, consistencia, aislamiento, durabilidad) que abarque varios servicios o bases de datos. El compromiso de dos fases distribuido es lento, bloquea recursos y reduce la disponibilidad. En su lugar, usen el patrón saga. Modelen una transacción de negocio como una secuencia de transacciones locales, cada una publica un evento que dispara la siguiente, y con una acción compensatoria para cada paso que lo deshaga si un paso posterior falla. Las sagas existen en dos modalidades. En la coreografía, los servicios reaccionan a los eventos de los demás, sin un controlador central. En la orquestación, un coordinador central dirige los pasos, lo que facilita el razonamiento y la supervisión. Las sagas abrazan la consistencia eventual: el sistema transita por estados intermedios y luego converge. Diseñen, por tanto, la experiencia de usuario y la huella de auditoría para contemplar los estados «en curso» y «compensado».

Tratar la entrega exacta como al menos una vez más deduplicación

Los corredores de mensajes no pueden garantizar de verdad la entrega exactamente una vez ante los fallos. Lo que ellos y los equipos sí pueden lograr es la entrega al menos una vez con procesamiento idempotente, que produce efectos exactamente una vez. Diseñen los consumidores para que manejen mensajes duplicados con seguridad, usando claves de idempotencia o un registro de mensajes procesados. Conozcan con precisión las garantías de orden y entrega de su corredor. Para el flujo en streaming, usen grupos de consumidores, particiones y gestión de desplazamientos de forma deliberada, y hagan que la reprocesión sea segura, para que puedan reproducir un flujo tras un correctivo sin corromper el estado aguas abajo.

Instrumentar los flujos distribuidos de extremo a extremo

Adopten los tres pilares de la observabilidad, correlacionados en cada frontera de servicio. Propaguen un identificador de trazado y correlación por cada salto, de modo que se pueda seguir una única petición de usuario a través de todos los servicios que atraviesa (trazado distribuido). Emitan métricas estructuradas (percentiles de latencia, tasas de error, saturación, caudal) por servicio y por dependencia. Emitan registros estructurados que lleven el identificador de correlación. Usen todo esto para fijar objetivos de nivel de servicio y para alertar sobre síntomas que los usuarios realmente sienten, como la tasa de error y la latencia, en lugar de solo sobre el estado individual de cada máquina. En un sistema distribuido, la observabilidad no es un herramienta opcional. Es la única forma de comprender el comportamiento bajo fallo parcial.

Compensaciones: ventajas y desventajas

TécnicaVentajasCostes / desventajas
Consistencia fuerteModelo mental simple, sin lecturas desactualizadasMenor disponibilidad durante particiones, mayor latencia, coste de coordinación
Consistencia eventualAlta disponibilidad, baja latencia, escalableLecturas desactualizadas, razonamiento complejo, requiere resolución de conflictos
Reintentos con retrocesoAbsorbe fallos transitorios automáticamenteAmplifica la carga si se usa mal; exige idempotencia y límites
Disyuntores de circuito / compartimentosImpiden fallos en cascada, fallo rápidoComplejidad añadida, ajuste de umbrales, riesgo de activación prematura
Saga (vs. compromiso de dos fases)Escalable, disponible, sin bloqueos distribuidosConsistencia eventual, lógica de compensación, más difícil de razonar

La compensación maestra es entre coordinación e independencia. Toda garantía que se exija entre máquinas (consistencia, orden, entrega exacta) cuesta latencia, disponibilidad o complejidad. Exige que las máquinas alcancen un acuerdo, y el acuerdo sobre una red poco fiable es caro. La destreza consiste en adquirir solo las garantías que el negocio de verdad necesita, operación por operación, y diseñar todo lo demás para una degradación elegante. Excederse en consistencia y los sistemas se vuelven lentos y frágiles. Escatimarla y se obtiene una corrupción silenciosa de datos que sale a la luz como un fallo de auditoría meses después.

Cuestiones para el debate con el equipo

  1. ¿Se entregan los patrones de resiliencia como valores predeterminados de plataforma compartida, o cada equipo reinventa tiempos de espera y reintentos por su cuenta? El capítulo considera idempotencia, tiempos de espera, reintentos acotados, disyuntores de circuito y trazado como los elementos más económicos y fiables cuando se construyen una sola vez en librerías y valores predeterminados de plataforma compartidos. En una organización grande, dejar que cada equipo los implemente a mano garantiza la inconsistencia: algunos caminos reintentan operaciones no idempotentes, otros no tienen tiempo de espera y otros no emiten identificador de correlación. Traigan como prueba la auditoría de una muestra de servicios y cuenten cuántos establecen un tiempo de espera explícito en cada llamada remota y propagan un identificador de trazado de extremo a extremo. Si ese número es bajo, la solución es una inversión en plataforma, no un memorándum de formación. Los valores predeterminados estandarizados también hacen que la resiliencia sea testeable y auditable, algo que los reguladores del sector financiero y del ámbito público exigen cada vez más que se demuestre.

  2. ¿Componen los tiempos de espera y los presupuestos de reintento a lo largo de toda la cadena de llamadas, o bien una petición profunda se reinicia a sí misma hasta provocar una caída? Una única petición suele cruzar muchos saltos, y si cada capa reintenta de forma independiente tres veces con su propio tiempo de espera, el fallo más interno se multiplica y el llamante exterior espera mucho más allá de cualquier límite tolerable. Fijen un presupuesto temporal total para la petición visible al usuario y divídanlo por la cadena, de modo que un servicio interior sepa cuánto tiempo le queda y falle rápido en lugar de reintentar hasta crear una tormenta. Traigan su grafo de dependencias y un trazado real, sumen la combinación peor de tiempo de espera y reintentos y compárenla con lo que el usuario estará realmente dispuesto a esperar. El retroceso exponencial con aleatorización y un tope de intentos totales impide que un bache breve se convierta en una denegación de servicio autoinfligida. Las cadenas síncronas profundas y de muchas llamadas son la enemiga aquí, de modo que la respuesta puede orientar hacia flujos asíncronos o menos saltos.

  3. ¿Cuándo inyectaron por última vez los fallos que su diseño pretende soportar, y qué se rompió que no esperaban? Los patrones de resiliencia son hipótesis hasta que se hace fallar el sistema a propósito: se mata una instancia, se añade latencia a una dependencia, se descarta una fracción de mensajes, se reenvía un lote dos veces. En un sistema distribuido, los fallos interesantes son parciales y persistentes, de modo que un disyuntor de circuito o una compensación de saga que parece correcto en el código puede fallar bajo un tiempo de espera que quizás sí completó. Traigan los resultados de un simulacro de fallo real o una jornada de inyección, no un documento de diseño, y anoten qué alertas se dispararon, cuánto tardó el trazado en localizar el fallo y si se formó alguna tormenta de reintentos. En sectores regulados, la evidencia de que se ha probado el fallo es parte de la demostración de resiliencia operativa ante los auditores. Si nunca se ha ejecutado, el primer experimento debe realizarse en un entorno de prueba con un radio de afectación acotado y un interruptor de detención.

  4. Para cada flujo de datos principal, ¿puede el equipo propietario nombrar el modelo de consistencia que ofrece y encaja con lo que el negocio realmente necesita? CAP y PACELC imponen una elección deliberada por operación, y en una organización grande la tendencia por defecto es la deriva: un flujo que empezó con consistencia eventual para un contador de bajo riesgo se reutiliza para aprobar pagos o conceder accesos, y nadie reexamina la garantía. Las consideraciones en conflicto son reales, pues la consistencia fuerte cuesta disponibilidad durante una partición y latencia incluso cuando no la hay, mientras que la consistencia eventual compra velocidad al precio de lecturas desactualizadas y resolución de conflictos que hay que diseñar. Traigan un catálogo de sus flujos de datos más importantes, cada uno etiquetado con su modelo actual (fuerte, causal, lectura-de-propia-escritura o eventual) y la consecuencia de negocio de una lectura desactualizada o perdida, y busquen discrepancias donde la garantía sea más fuerte o más débil de lo que el riesgo justifica. En finanzas empresariales y en sistemas públicos de prestaciones o identidad, una lectura con consistencia eventual tras una decisión autoritativa es el tipo de defecto silencioso que sale a la luz como hallazgo de auditoría o como una denegación injusta meses después, de modo que la propia revisión es una evidencia que los auditores pedirán ver.

  5. ¿Cómo se comportan las transacciones de negocio multiservicio a media ejecución, y quién responde de las compensaciones que las deshacen? Reemplazar el compromiso de dos fases por sagas significa que el sistema transita por estados intermedios visibles, y un paso puede triunfar mientras un paso posterior falla y dispara una acción compensatoria que lo revierte. Para un equipo grande, esto plantea cuestiones difíciles de responsabilidad: la cadena autorizar-debitar-creditar-registrar en el libro mayor suele cruzar varios equipos, y una compensación que un equipo olvida implementar deja dinero o registros permanentemente inconsistentes. Pésen la coreografía, donde los servicios reaccionan a los eventos de los demás sin un controlador central y el flujo es difícil de seguir, frente a la orquestación, donde un coordinador dirige y supervisa los pasos a costa de un componente que hay que operar. Traigan el diagrama de estados de su saga más importante, la lista de acciones compensatorias y sus responsables, y la evidencia de que los estados «en curso» y «compensado» se tratan tanto en la experiencia de usuario como en la huella de auditoría. En banca y gestión de casos del sector público, los reguladores esperan que se pueda reconstruir exactamente lo que ocurrió con una transacción que falló a mitad de camino, de modo que un estado intermedio no modelado es un vacío de cumplimiento, no solo un bug.

  6. ¿Sus consumidores de mensajes sobreviven a la entrega duplicada y desordenada, y pueden demostrarlo antes de que el corredor lo obligue? La entrega exacta es un mito, así que su garantía real es la de al menos una vez, y un consumidor que asume que cada mensaje llega una sola vez y en orden va a procesar dobles el día que el corredor reenvíe un lote tras un failover. En muchos equipos el riesgo se multiplica, porque un solo consumidor no idempotente en un flujo compartido puede corromper el estado aguas abajo del que otros equipos dependen, y el fallo es invisible hasta una reproducción o una partición que reordena eventos. La compensación es el coste de ingeniería de claves de idempotencia, un registro de mensajes procesados y un manejo explícito de desplazamientos y particiones, frente al coste de una corrupción silenciosa. Traigan la lista de consumidores en sus flujos críticos, anoten cuáles deduplican y cuáles solo confían, y traigan el resultado de una prueba de reenvío o reproducción real, no la promesa de que debería funcionar. Para el intercambio de datos interinstitucional en el sector público y para las tuberías de eventos empresariales, la capacidad de reproducir un flujo con seguridad tras un correctivo, sin generar casos duplicados ni cobros repetidos, es a la vez una necesidad operativa y algo que los auditores querrán que se demuestre.

Perspectiva por sector

Startup. Con dos o tres piezas móviles y sin equipo de plataforma, resistan la tentación de construir maquinaria distribuida que no pueden mantener. Adquieran la resiliencia donde ya la ofrece el SDK de su proveedor de pagos o mensajería, y dediquen su atención escasa a los dos patrones que previenen daños irreversibles: una clave de idempotencia en cada llamada que mueve dinero o altera cuentas, y un tiempo de espera con reintento acotado para que una conexión inestable nunca actúe dos veces. Mantengan el número de saltos de red bajo, porque cada dependencia síncrona que añaden es una pieza más que puede fallar antes de que haya alguien de guardia que lo note.

Pequeña empresa. Probablemente no tengan un especialista en sistemas distribuidos y el presupuesto es ajustado, de modo que traten esto como una pregunta de comprar frente a construir: prefieran colas gestionadas, bases de datos gestionadas y plataformas que manejen reintentos, orden y deduplicación por ustedes, en lugar de infraestructura que deban operar. Enmarquen el riesgo en términos llanos, identificando qué operaciones harían daño a un cliente si se ejecutaran dos veces o devolvieran datos desactualizados, y activen las funciones de idempotencia y entrega al menos una vez que sus proveedores ya ofrecen. Eviten unir servicios a través de una base de datos compartida para simular una transacción, pues eso reproduce en silencio el problema distribuido más difícil sin ninguna de las herramientas para gestionarlo.

Gran empresa. El problema central es la coherencia entre muchos equipos, así que entreguen idempotencia, tiempos de espera, reintentos acotados, disyuntores de circuito y trazado correlacionado como valores predeterminados de plataforma compartidos, en lugar de dejar que cada grupo los implemente por su cuenta. Estandaricen cómo se declaran los modelos de consistencia y las garantías de entrega por flujo, ejecuten inyección de fallos y jornadas de simulacro con periodicidad regular, y asegúren que los presupuestos temporales totales componen a lo largo de cadenas de llamadas profundas, de modo que un servicio no pueda reintentar la plataforma entera hasta una caída. Gestionen la resiliencia como una capacidad medible con objetivos de nivel de servicio en síntomas visibles al usuario, porque a esa escala un único tiempo de espera en falta puede escalar hasta una caída en titulares.

Sector público. Los sistemas interinstitucionales implican que nadie es dueño del conjunto, así que diseñen para fronteras que no controlan: colas durables con entrega al menos una vez, deduplicación sobre un identificador de mensaje estable e identificadores de correlación que atraviesen las líneas institucionales para dar a los auditores un trazado de extremo a extremo. Las normas de contratación y transparencia obligan a documentar el modelo de consistencia y la garantía de entrega de cada integración, y a mantener las decisiones autoritativas (identidad, elegibilidad, prestaciones) en lecturas de consistencia fuerte en lugar de en endpoints en caché. Traten la evidencia de fallo probado y el historial de transacciones reconstruible como entregables, pues la resiliencia operativa y la rendición de cuentas ante el público son obligaciones contractuales y legales, no detalles internos.

Ejemplos

Startup. Una pequeña empresa de tecnología financiera acaba de poner en marcha dos piezas que se comunican por red: su aplicación y un proveedor externo de pagos. A ese tamaño ya hace que cada solicitud de cobro lleve una clave de idempotencia y envuelve la llamada en un reintento con retroceso, de modo que una respuesta perdida en una conexión inestable nunca doble-cobra al cliente. Omitirlo parece barato el primer día, pero el primer cobro duplicado que llega a un usuario real cuesta una crisis de atención al cliente, un reembolso y una grieta en la confianza que una empresa joven no puede permitirse.

Gran empresa. Una plataforma global de transporte compartido procesa los pagos de los trayectos a través de una saga: autorizar tarjeta, debitar del pasajero, acreditar al conductor, registrar en el libro mayor; cada paso es una transacción local con una reversión compensatoria. Cada paso lleva una clave de idempotencia, para que los reintentos tras un tiempo de espera de red nunca doblen el cobro. Las llamadas al servicio de puntuación de fraudes pasan por un disyuntor de circuito; cuando se degrada en hora punta, el disyuntor se abre y los trayectos caen en una puntuación conservadora en lugar de bloquear cada viaje. Cuando un cliente disputa un trayecto, el trazado distribuido permite a los ingenieros seguirlo a través de una docena de servicios en cuestión de segundos.

Sector público. Un servicio nacional de identidad lo utilizan muchos organismos para verificaciones. Ofrece una lectura de consistencia fuerte para las comprobaciones de estado autoritativas (no se puede aprobar una prestación sobre datos de identidad desactualizados), además de un endpoint en caché con consistencia eventual para consultas de alto volumen y baja criticidad. El intercambio de datos interinstitucional se ejecuta sobre una cola de mensajes durable con entrega al menos una vez, y cada organismo deduplica sobre un identificador de mensaje, de modo que un registro reenviado no genera un caso duplicado. Los identificadores de correlación fluyen a través de las fronteras institucionales, dando a los auditores un trazado de extremo a extremo de cómo los datos de un ciudadano se desplazaron entre departamentos.

Justificación de negocio: motivaciones, retorno y coste total de propiedad

La disciplina en sistemas distribuidos se compra barato y su ausencia se paga catastróficamente. El coste de adopción es tiempo de ingeniería para construir idempotencia, tiempos de espera, reintentos, disyuntores de circuito y trazado en librerías y valores predeterminados de plataforma compartidos. Es una inversión modesta y mayoritariamente puntual que luego beneficia a cada equipo. El coste de no adoptarla se mide en caídas mayores: un único tiempo de espera en falta que se escala a una caída total de la plataforma, un camino de pago no idempotente que dobla el cobro a miles de clientes, o una transacción distribuida sin saga que deja datos permanentemente inconsistentes. Cada uno de estos casos es un incidente de primera página con coste directo en ingresos, remediación y reputación, y, en sectores regulados, en sanciones.

Enmarquen el caso ante la dirección en torno a la disponibilidad y el radio de afectación. Los patrones de resiliencia reducen directamente tanto la frecuencia como la duración de los incidentes graves, las métricas que los ejecutivos ya siguen como tiempo de actividad y tiempo medio de recuperación. La observabilidad distribuida es la palanca individual de mayor alcance sobre el tiempo medio de recuperación: los equipos con trazado correlacionado resuelven incidentes transversales en una fracción del tiempo. Como estas capacidades se entregan mejor como valores predeterminados de plataforma, su coste marginal por equipo es bajo y su rendimiento organizacional compuesto crece. El argumento de coste total es sencillo: construir la resiliencia desde el principio cuesta una fracción del coste de añadirla a posteriori, tras la caída que la hace ineludible.

Antipatrones y riesgos

  • Sin tiempos de espera. Una sola dependencia bloqueada agota todos los hilos y derriba el sistema entero.
  • Reintentar operaciones no idempotentes. Efectos duplicados: cobros dobles, registros duplicados, correos enviados dos veces.
  • Tormentas de reintentos. Reintentos sincronizados sin retroceso ni aleatorización que amplifican un bache menor hasta convertirlo en una caída.
  • Asumir entrega exactamente una vez. Construir consumidores que se rompen con los mensajes duplicados que el corredor acabará entregando.
  • Transacciones distribuidas vía base de datos compartida. Acoplar servicios a través de una sola base de datos para simular ACID, recreando un monolito distribuido.
  • Ignorar el fallo parcial. Código que asume que una llamada remota o triunfa por completo o falla por completo, sin tratamiento para el «se agotó el tiempo, pero quizás se completó».
  • Sin identificadores de correlación. Depurar un incidente transversal buscando en registros ajenos en diez máquinas.
  • Cadenas síncronas de muchas llamadas. Grafos de dependencias síncronas profundos donde cualquier salto lento frena la petición entera.

Modelo de madurez

  • Nivel 1: Iniciar. Las llamadas remotas se tratan como locales. Los tiempos de espera son inexistentes o ingenuos, los reintentos están ausentes o son temerarios, y los fallos se propagan por todo el sistema. No existe una visión compartida de la consistencia o la entrega, y depurar un incidente transversal consiste en rascar registros en cada máquina por separado, y a posteriori.
  • Nivel 2: Desarrollar. Algunos equipos añaden tiempos de espera y reintentos básicos y algo de idempotencia, pero las prácticas son inconsistentes de un servicio a otro. Los registros están centralizados pero no correlacionados, de modo que seguir una petición entre saltos es manual. Las transacciones distribuidas se confía en que funcionen sin modelarlas, y las garantías de consistencia viven en la cabeza de ingenieros individuales.
  • Nivel 3: Estándarizar. La idempotencia, los reintentos acotados, el retroceso con aleatorización, los disyuntores de circuito y los compartimentos son estándar en toda la organización a través de librerías compartidas. Las sagas con acciones compensatorias gestionan transacciones multiservicio, el trazado distribuido con identificadores de correlación está en marcha, y cada flujo de datos principal documenta su modelo de consistencia y su garantía de entrega. Las reglas están escritas y se aplican a escala de organización en lugar de dejarse a la discreción de cada equipo.
  • Nivel 4: Gestionar. La resiliencia se mide frente a líneas base, no solo se declara presente. Se siguen la tasa de error, los percentiles de latencia, la saturación y el caudal por servicio y por dependencia; se observan las proporciones de reintento y las tasas de apertura de disyuntores, y se fijan objetivos de nivel de servicio en síntomas visibles al usuario. Los presupuestos temporales totales se verifican que componen a lo largo de las cadenas de llamadas, el tiempo medio de recuperación de incidentes transversales es una métrica monitorizada, y los resultados de inyección de fallos y jornadas de simulacro alimentan los números que condicionan cada cambio.
  • Nivel 5: Orquestar. La resiliencia es el valor predeterminado de plataforma en mejora continua, integrado en toda la organización y adaptativo a las condiciones. La inyección de fallos se ejecuta con regularidad en producción con radio de afectación acotado, los sistemas se degradan con elegancia por diseño, y las elecciones de consistencia y entrega se revisan a medida que cambian la carga y el peso del negocio. Las métricas del nivel 4 impulsan respuestas automáticas y una evolución arquitectónica sostenida, de modo que el parque de sistemas distribuidos se vuelve más robusto con cada incidente en lugar de simplemente sobrevivirlo.

Ideas para el debate

  1. ¿Cuáles de sus operaciones críticas son genuinamente idempotentes hoy, y cuáles lo son en silencio?
  2. Para cada flujo de datos principal, ¿puede su equipo nombrar de memoria el modelo de consistencia y la garantía de entrega?
  3. ¿Dónde un disyuntor de circuito habría evitado su última caída en cascada?
  4. ¿Cuánto tiempo tarda actualmente en trazar una única petición fallida a través de todos los servicios que toca?
  5. ¿Cuáles de sus «transacciones distribuidas» dependen en realidad de la suerte y cuáles son sagas auténticas con compensaciones?
  6. Si su corredor de mensajes reenviara cada mensaje dos veces durante una hora, ¿qué se rompería?

Ideas clave

  • Asuma que la red es poco fiable y que los fallos son parciales; diseñe cada interacción remota para lentitud, pérdida, duplicación y desorden.
  • Decida consistencia frente a disponibilidad por operación usando CAP/PACELC; documente el modelo que cada flujo ofrece.
  • La idempotencia, los tiempos de espera, los reintentos acotados y el retroceso con aleatorización son un solo paquete; nunca adopten reintentos sin los otros tres.
  • Los disyuntores de circuito y los compartimentos contienen los fallos; las sagas con compensaciones sustituyen las transacciones distribuidas inviables.
  • Traten la entrega como al menos una vez y hagan el procesamiento idempotente para lograr efectos exactamente una vez.
  • El trazado correlacionado, las métricas y los registros son la única forma de comprender y operar flujos distribuidos.

Referencias y lecturas complementarias

  • Martin Kleppmann, Designing Data-Intensive Applications
  • Andrew Tanenbaum y Maarten van Steen, Distributed Systems: Principles and Paradigms
  • Michael Nygard, Release It!: Design and Deploy Production-Ready Software
  • Sam Newman, Building Microservices
  • Chris Richardson, Microservices Patterns (sagas, mensajería transaccional)
  • Eric Brewer, «CAP Twelve Years Later» y Daniel Abadi sobre PACELC
  • Leslie Lamport, «Time, Clocks, and the Ordering of Events in a Distributed System»
  • Cindy Sridharan, Distributed Systems Observability
  • La noción de antifragilidad de Nassim Nicholas Taleb (según la literatura de ingeniería de resiliencia)