Dame la intuición detrás de los algoritmos de consenso como Raft: ¿cómo se ponen de acuerdo los nodos distribuidos sobre un único valor?
Ningún nodo individual puede ser el único en decidir — Raft muestra cómo una mayoría de máquinas poco confiables se pone de acuerdo en una sola verdad, incluso cuando los líderes caen y las redes se dividen.
APRENDE HACIENDOPon a prueba tu intuición3 pasos
Dame la intuición detrás de los algoritmos de consenso como Raft: ¿cómo se ponen de acuerdo los nodos distribuidos sobre un único valor?
Usa los ejemplos y la explicación de la lección para comprobar tu idea.
Reflexión personal. No se envía a ningún servicio de IA.#Por qué "simplemente elige un líder" no es toda la respuesta
La forma obvia de hacer que varias máquinas se pongan de acuerdo en algo es elegir a una de ellas como líder y dejar que decida. Eso es fácil. Lo difícil es todo lo que ocurre una vez que aceptas que los líderes se caen, las redes se particionan y los mensajes se retrasan o se pierden — y que el sistema aun así tiene que seguir avanzando sin permitir jamás que dos nodos crean ser ambos el líder legítimo al mismo tiempo y tomen decisiones contradictorias. Esa garantía, bajo esas condiciones de fallo, sin ningún punto único de control que no sea a su vez reemplazable cuando falla, es el problema del consenso. Raft es el algoritmo al que recurren la mayoría de los sistemas para resolverlo, precisamente porque fue diseñado para ser comprensible — su predecesor, Paxos, es al menos igual de potente pero notoriamente difícil de implementar correctamente solo a partir del paper.
#Los tres roles y el "term"
Cada nodo de un clúster Raft está, en todo momento, en exactamente uno de tres estados: Follower (el estado por defecto — pasivo, responde al líder y a los candidatos, nunca inicia nada), Candidate (un estado temporal mientras hace campaña pidiendo votos), o Leader (atiende cada petición del cliente e impulsa la replicación del log). El tiempo se divide en terms — un entero monótonamente creciente que se incrementa cada vez que empieza una nueva elección. Un clúster tiene como máximo un líder por term, y cada mensaje lleva el term actual de quien lo envía, que es como los nodos detectan que están desactualizados y necesitan retirarse o actualizarse.
#Elección de líder
Los followers esperan un heartbeat del líder a un intervalo constante, entregado como una RPC AppendEntries que puede venir vacía. Si un follower no tiene noticias del líder dentro de un timeout de elección aleatorizado — normalmente algo como 150 a 300 milisegundos, con la aleatorización deliberadamente distinta en cada nodo — asume que el líder desapareció, pasa a Candidate, incrementa su term, vota por sí mismo, y envía RPCs RequestVote a todos los demás nodos en paralelo.
Un nodo concede como máximo un voto por term, por orden de llegada, y solo si el log del candidato está al menos tan actualizado como el suyo propio — una verificación de seguridad que evita que un nodo con un log desactualizado llegue a ser líder y borre silenciosamente trabajo ya comprometido (committed). Si un candidato reúne votos de una mayoría del clúster, se convierte inmediatamente en líder para ese term y empieza a enviar heartbeats, lo cual establece su autoridad y a la vez reinicia el temporizador de elección de cada follower.
El timeout aleatorizado es lo que evita que esto se bloquee. Si el timeout de todos los followers fuera idéntico, varios nodos podrían agotarlo simultáneamente, dividiendo el voto de forma que nadie alcanza la mayoría, y repitiendo esto indefinidamente. La aleatorización hace muy probable que un follower agote su timeout notablemente antes que los demás, haga campaña, y gane antes de que un segundo candidato siquiera entre en la contienda. Un voto dividido genuino todavía puede ocurrir ocasionalmente — en ese caso, el term simplemente expira y cada candidato reintenta con un nuevo timeout aleatorio, lo cual lo resuelve con alta probabilidad en el siguiente intento.
#Replicación del log
Una vez que hay un líder en su lugar, cada escritura del cliente pasa por él (un cliente que contacta a un follower es redirigido al líder actual). El líder añade el comando a su propio log como una nueva entrada etiquetada con el term actual y su índice, y luego la envía a cada follower mediante AppendEntries, en paralelo, junto con el term e índice de la entrada inmediatamente anterior.
Un follower acepta la nueva entrada solo si su propio log ya coincide con el del líder en esa posición anterior — la propiedad de coincidencia de logs (log matching property). Si no coincide (el follower está atrasado, o tiene entradas sin comprometer sobrantes de un líder anterior), rechaza el append, y el líder retrocede y reintenta con entradas anteriores hasta encontrar un punto donde los logs coincidan, y luego sobrescribe todo lo posterior a ese punto con su propia versión. Esta es la única forma en que se permite que los logs de los followers diverjan del líder y luego se corrijan — un líder solo puede añadir a su propio log, nunca reescribirlo.
Una entrada queda comprometida (committed) en el momento en que el líder confirma que está almacenada en una mayoría de los nodos, incluido él mismo. En ese punto el líder la aplica a su propia máquina de estados y responde al cliente — la durabilidad ya está garantizada, porque una mayoría la tiene, y ningún líder futuro puede ser elegido sin los votos de esa mayoría, lo cual (por la verificación de log actualizado en la elección) garantiza que la entrada sobreviva en el log de cada líder posterior. El líder entonces le indica a los followers que la entrada está comprometida mediante el campo leaderCommit en el siguiente AppendEntries, para que ellos también la apliquen a sus propias máquinas de estados.
Nota que el cliente ya recibió su OK justo después del ack de la mayoría — no espera a todos los followers, ni espera a que la notificación de commit haga el viaje de vuelta. Eso es exactamente lo que permite que Raft siga avanzando con una minoría de nodos caídos o lentos.
#Las propiedades de seguridad que hacen esto confiable
| Propiedad | Garantía |
|---|---|
| Election Safety | Como máximo se puede elegir un líder en un term dado |
| Leader Append-Only | Un líder nunca sobrescribe ni borra entradas de su propio log — solo añade |
| Log Matching | Si dos logs contienen una entrada con el mismo índice y term, todas las entradas anteriores en ambos logs son idénticas |
| Leader Completeness | Una vez que una entrada está comprometida, el log de cada líder futuro está garantizado a contenerla |
| State Machine Safety | Si algún servidor ha aplicado una entrada de log en un índice dado a su máquina de estados, ningún otro servidor aplicará jamás una entrada distinta para ese mismo índice |
Leader Completeness es la que hace el trabajo real aquí, y está garantizada enteramente dentro de la regla de votación: un nodo se niega a votar por un candidato cuyo log esté por detrás del suyo. Como ganar requiere una mayoría, y una entrada comprometida ya vive en una mayoría, cualquier candidato que pueda ganar debe tener ya esa entrada (o una más reciente que la cubra) — un líder al que le falte una entrada comprometida matemáticamente no puede ganar una elección.
#La aritmética del quórum y qué te hace una partición
Un clúster de 2f + 1 nodos tolera que f de ellos estén caídos o inalcanzables mientras sigue eligiendo líderes y comprometiendo entradas — un clúster de 5 nodos sobrevive 2 fallos, uno de 3 nodos sobrevive 1. Si una partición de red divide un clúster de 5 nodos en un grupo de 3 y un grupo de 2, el grupo de 3 todavía puede alcanzar una mayoría por sí mismo y sigue sirviendo escrituras; el grupo de 2 no puede alcanzar una mayoría, así que no puede elegir ningún líder y no acepta ninguna escritura. Simplemente se detiene hasta que la partición se resuelve, en lugar de aceptar escrituras que más tarde entrarían en conflicto con el lado mayoritario. Es una decisión deliberada de favorecer la consistencia sobre la disponibilidad durante una partición — el lado minoritario queda no disponible, pero nunca se equivoca.
#Dónde has usado esto en la práctica sin saberlo
Raft (o una variante muy cercana) está debajo de etcd — que es justamente lo que usa Kubernetes para almacenar todo el estado del clúster — así como de Consul, la replicación de rangos de CockroachDB, y TiKV. Cada vez que veas un sistema que anuncia "metadata replicada con consistencia fuerte" y failover automático de líder, hay muy buenas probabilidades de que debajo haya un log al estilo Raft.
🧠 Check your understanding
0/3 · 0/3 answered1. ¿Por qué Raft usa un timeout de elección aleatorizado en lugar de uno fijo igual para todos los nodos?
2. ¿Qué debe cumplirse antes de que un líder de Raft considere una entrada de log como "comprometida" (committed)?
3. Un clúster Raft de 5 nodos queda dividido por una partición de red en un grupo de 3 y un grupo de 2. ¿Qué ocurre?