⏱️ Lectura: 10 min

Cada vez que una aplicación grande guarda datos en varios servidores, alguien debe decidir en cuál va cada dato. La respuesta ingenua —repartir según el resto de una división— funciona hasta que agregas o quitas un servidor: entonces casi todo se desordena. El hashing consistente es la técnica que evita ese caos.

📑 En este artículo
  1. TL;DR
  2. Qué es el hashing consistente
  3. El problema que resuelve: el hash módulo N
  4. Cómo funciona: el anillo paso a paso
  5. Nodos virtuales: el secreto para repartir parejo
  6. Ejemplo práctico en Python
  7. Casos de uso reales
  8. Ventajas y desventajas
  9. Preguntas frecuentes
    1. ¿En qué se diferencia el hashing consistente del hash módulo N?
    2. ¿Qué son exactamente los nodos virtuales?
    3. ¿Cuántas claves se mueven al añadir un servidor?
    4. ¿Necesito hashing consistente en un proyecto pequeño?
    5. ¿Qué función de hash debo usar?
  10. Referencias

Es la pieza silenciosa que sostiene a bases de datos como Cassandra y DynamoDB, a sistemas de caché como memcached y a buena parte de las redes de distribución de contenido (CDN) del mundo. En esta guía lo explicamos desde cero, con analogías, un diagrama y código funcional.

TL;DR

  • El hashing consistente coloca servidores y claves en un anillo virtual de 0 a 2³²−1 y asigna cada clave al primer nodo en sentido horario.
  • Al añadir o quitar un servidor solo se remapea ~1/n de las claves, no casi todas como en el hash módulo N tradicional.
  • David Karger y su equipo del MIT lo formalizaron en 1997 para repartir carga entre servidores web.
  • Amazon DynamoDB, Cassandra, memcached y muchas CDN lo usan para particionar datos sin un coordinador central.
  • Los nodos virtuales (varias posiciones por servidor) reparten la carga de forma uniforme y evitan puntos calientes.
  • Sin él, escalar un caché de N a N+1 servidores invalida casi el 100% de las entradas y satura la base de datos.

Qué es el hashing consistente

El hashing consistente es una forma de repartir datos (o peticiones) entre un conjunto de servidores de modo que, cuando ese conjunto cambia de tamaño, haya que mover la menor cantidad posible de datos. La idea apareció en 1997 en un artículo de David Karger y su equipo en el MIT, pensada originalmente para repartir carga entre servidores web y, poco después, para las primeras redes de distribución de contenido.

La analogía más útil es la de un reloj. Imagina una esfera circular numerada, no del 1 al 12, sino de 0 hasta un número enorme. Colocamos cada servidor en una posición de esa esfera y también colocamos cada dato. Para saber qué servidor guarda un dato, partimos de su posición y avanzamos en el sentido de las agujas del reloj hasta toparnos con el primer servidor. Ese servidor es el responsable. Cuando un servidor desaparece, solo los datos que apuntaban a él tienen que buscar al siguiente; el resto del reloj ni se entera.

💭 Clave: con hashing consistente, añadir o quitar un servidor reubica en promedio solo 1/n de las claves (donde n es el número de servidores), en lugar de casi todas.

El problema que resuelve: el hash módulo N

Para entender por qué importa, hay que ver primero la solución ingenua. Supón que tienes 4 servidores de caché y quieres repartir millones de claves entre ellos. El método clásico es calcular un número a partir de la clave (un hash) y quedarte con el resto de dividirlo entre 4: servidor = hash(clave) % 4. Es rápido y reparte de forma bastante uniforme.

El problema aparece al escalar. El día que el tráfico crece y añades un quinto servidor, la fórmula pasa a ser % 5. Y como el resto de dividir entre 5 es distinto del de dividir entre 4 para casi cualquier número, prácticamente todas las claves cambian de servidor a la vez. En un caché eso significa que casi el 100% de las entradas quedan invalidadas de golpe: todas las peticiones van a la base de datos al mismo tiempo y la tumban. Es el escenario que en inglés llaman cache stampede, una estampida de caché.

El hashing consistente nace justo para evitar esa estampida: cambiar el número de servidores debe costar barato, no provocar una avalancha.

Cómo funciona: el anillo paso a paso

El truco del hashing consistente es no atar las claves al número de servidores. En su lugar, se proyecta todo sobre un espacio fijo y circular —el famoso anillo—. Veamos los pasos:

  • Definir el anillo — un rango de números fijo, por ejemplo de 0 a 2³²−1. Es fijo: no cambia aunque entren o salgan servidores.
  • Colocar los servidores — se aplica la función de hash al nombre o IP de cada servidor y el resultado es su posición en el anillo.
  • Colocar las claves — se aplica la misma función de hash a cada clave para obtener su posición.
  • Asignar — cada clave pertenece al primer servidor que se encuentre avanzando en sentido horario desde su posición.

La consecuencia es elegante: cuando un servidor se cae, sus claves simplemente continúan hasta el siguiente servidor del anillo, y ninguna otra clave se ve afectada. Cuando entra un servidor nuevo, solo «roba» las claves del tramo de anillo que queda entre él y el servidor anterior. El resto del sistema sigue igual, sin tocar nada.

flowchart LR
  C["Clave (hash=350)"] -->|"primer nodo en sentido horario"| B["Nodo B (pos=500)"]
  A["Nodo A (pos=100)"]
  D["Nodo C (pos=900)"]
Anillo de hashing consistente con nodos y claves distribuidas
Cada clave busca el primer nodo en sentido horario.

Nodos virtuales: el secreto para repartir parejo

El anillo básico tiene un defecto práctico. Con pocos servidores, las posiciones pueden quedar mal repartidas: un servidor termina con un tramo enorme del anillo y otro con un tramo diminuto. El resultado son los llamados puntos calientes (hot spots), nodos que reciben mucha más carga que el resto.

La solución son los nodos virtuales. En lugar de colocar cada servidor una sola vez, lo colocamos muchas veces —por ejemplo 100 o 200 posiciones por servidor— usando hashes de etiquetas como servidor-a:0, servidor-a:1, etcétera. Cada servidor físico queda así representado por cientos de puntos esparcidos por todo el anillo. Cuantos más nodos virtuales, más uniforme es el reparto y más suave la transición cuando se añade o quita un servidor.

💡 Tip: los nodos virtuales también permiten dar más peso a servidores más potentes: basta asignarles más posiciones en el anillo para que reciban proporcionalmente más datos.

Ejemplo práctico en Python

La teoría se entiende mejor con código. Esta implementación mínima de un anillo de hashing consistente usa solo la librería estándar de Python. La lista ordenada de posiciones más una búsqueda binaria (bisect) hace que encontrar el servidor de una clave sea muy rápido, incluso con miles de nodos virtuales:

import hashlib
import bisect

class AnilloHash:
    def __init__(self, nodos=None, replicas=100):
        self.replicas = replicas
        self.anillo = {}
        self.posiciones = []
        for nodo in nodos or []:
            self.agregar(nodo)

    def _hash(self, clave):
        h = hashlib.md5(clave.encode()).hexdigest()
        return int(h, 16)

    def agregar(self, nodo):
        for i in range(self.replicas):
            pos = self._hash(f"{nodo}:{i}")
            self.anillo[pos] = nodo
            bisect.insort(self.posiciones, pos)

    def quitar(self, nodo):
        for i in range(self.replicas):
            pos = self._hash(f"{nodo}:{i}")
            del self.anillo[pos]
            self.posiciones.remove(pos)

    def obtener(self, clave):
        if not self.anillo:
            return None
        pos = self._hash(clave)
        idx = bisect.bisect(self.posiciones, pos) % len(self.posiciones)
        return self.anillo[self.posiciones[idx]]

anillo = AnilloHash(["servidor-a", "servidor-b", "servidor-c"])
print(anillo.obtener("usuario_42"))
print(anillo.obtener("pedido_8891"))

Fíjate en el detalle del método obtener: usa bisect para encontrar la primera posición igual o mayor que la de la clave y, si se pasa del final de la lista, da la vuelta al anillo con el módulo. Eso es, literalmente, «avanzar en sentido horario hasta el primer nodo».

Código de hashing consistente en una pantalla de editor
Una implementación completa cabe en unas 30 líneas de Python.

Casos de uso reales

El hashing consistente no es un ejercicio académico: está en producción en sistemas que usas todos los días.

  • Amazon DynamoDB y Cassandra — ambos heredan las ideas del artículo Dynamo de Amazon (2007), que popularizó el hashing consistente para particionar datos entre nodos sin un coordinador central.
  • Redes de distribución de contenido (CDN) — empresas como Akamai o Cloudflare usan variantes para decidir qué servidor de borde cachea cada recurso, de modo que un mismo archivo siempre caiga en el mismo nodo.
  • Cachés distribuidos — clientes de memcached y de Redis en clúster reparten claves entre servidores con esta técnica para que escalar no vacíe el caché de golpe.
  • Balanceadores de carga — algunos balanceadores envían a un mismo usuario siempre al mismo backend (afinidad de sesión) usando hashing consistente.

Ventajas y desventajas

Como toda decisión de diseño, el hashing consistente tiene compromisos. Sus ventajas son claras: minimiza el movimiento de datos al escalar, no necesita un coordinador central que sepa dónde está cada clave y reparte la carga de forma predecible. Es además sencillo de implementar y muy rápido de consultar.

Entre sus desventajas: sin nodos virtuales, el reparto puede ser desigual; la calidad depende por completo de una buena función de hash; y no resuelve por sí solo la replicación ni la consistencia de los datos —para eso hacen falta otras técnicas, como replicar cada clave en los siguientes N nodos del anillo—. También, gestionar miles de nodos virtuales añade algo de memoria y complejidad.

⚠️ Ojo: si la función de hash reparte mal (por ejemplo, agrupa claves parecidas), el anillo se desequilibra. Usa funciones como MD5, SHA-1 o MurmurHash, pensadas para distribuir de forma uniforme, no funciones caseras.

📖 Resumen en Telegram: Ver resumen

Preguntas frecuentes

¿En qué se diferencia el hashing consistente del hash módulo N?

El hash módulo N (hash(clave) % N) ata cada clave al número total de servidores, así que cambiar N reubica casi todas las claves. El hashing consistente proyecta claves y servidores sobre un anillo fijo, de modo que al cambiar el número de servidores solo se mueve una fracción pequeña de las claves.

¿Qué son exactamente los nodos virtuales?

Son copias de un mismo servidor físico colocadas en muchas posiciones del anillo. En vez de un punto por servidor, se crean cientos usando etiquetas como servidor-a:0, servidor-a:1, etcétera. Así el reparto es más uniforme y se evitan los puntos calientes.

¿Cuántas claves se mueven al añadir un servidor?

En promedio, alrededor de 1/n del total, donde n es el número de servidores tras el cambio. Con 10 servidores, añadir uno mueve cerca del 10% de las claves, frente a casi el 100% que movería el hash módulo N.

¿Necesito hashing consistente en un proyecto pequeño?

Probablemente no. Si tienes un solo servidor o una base de datos que no particionas manualmente, no aporta nada. Se vuelve útil cuando repartes datos o peticiones entre varios nodos y necesitas escalar sin reorganizarlo todo.

¿Qué función de hash debo usar?

Cualquiera que distribuya de forma uniforme: MD5, SHA-1 o MurmurHash son habituales. No necesitas una función criptográficamente segura para esto; necesitas una rápida y bien repartida. Evita funciones caseras que agrupen claves parecidas y desequilibren el anillo.

Referencias

📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.


Andrés Morales

Desarrollador e investigador en inteligencia artificial. Escribe sobre modelos de lenguaje, frameworks, herramientas para devs y lanzamientos open source. Cubre papers de ML, ecosistema de startups tech y tendencias de programación.

0 Comentarios

Deja un comentario

Marcador de posición del avatar

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.