¿Cuáles son las principales estrategias de sharding, y cómo eliges una shard key?
El sharding escala escrituras dividiendo los datos entre nodos — pero la decisión que moldea cada consulta y cada dolor de cabeza futuro es la clave por la que particionas.
APRENDE HACIENDOPon a prueba tu intuición3 pasos
¿Cuáles son las principales estrategias de sharding, y cómo eliges una shard key?
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é particionar (shard) en primer lugar
La replicación resuelve el escalado de lecturas y la disponibilidad, pero no resuelve el escalado de escrituras — cada seguidor igual tiene que aplicar cada escritura que hace el líder, así que todo el dataset (y su carga de escritura) sigue teniendo que caber en un solo líder. El sharding (particionamiento horizontal) divide los datos mismos entre múltiples nodos de base de datos independientes, cada uno con un subconjunto de las filas, de modo que tanto el almacenamiento como el throughput de escritura escalan agregando máquinas.
La parte difícil nunca fue dividir mecánicamente una tabla — es elegir una shard key (clave de partición) que determina en qué shard vive cada fila, porque esa única decisión moldea cada patrón de consulta, cada hotspot y cada operación futura de resharding durante toda la vida del sistema.
#Las estrategias principales
El sharding por rango asigna rangos contiguos de la shard key a cada shard — por ejemplo, usuarios con ID 1–1.000.000 en el shard A, 1.000.001–2.000.000 en el shard B. Esto hace baratas las consultas por rango (WHERE created_at BETWEEN ...), porque una consulta de rango normalmente solo toca uno o dos shards. El modo de falla es el hotspot: si la shard key es algo monótonamente creciente como un ID autoincremental o un timestamp, todas las escrituras nuevas caen en el único shard "más reciente" mientras los shards más viejos quedan inactivos.
El sharding por hash pasa la shard key por una función de hash y usa el resultado (típicamente hash(key) mod N, o un bucket derivado de eso) para elegir el shard. Esto distribuye las escrituras de forma pareja y elimina el problema de hotspot, a costa de que las consultas por rango se vuelvan un scatter-gather sobre todos los shards, porque las claves consecutivas quedan dispersas al azar.
El sharding por directorio (lookup) mantiene una tabla de mapeo explícita (clave → shard) en un servicio separado, dando control total sobre la ubicación — incluyendo aislar deliberadamente a inquilinos (tenants) ruidosos específicos — a costa de un lookup extra en cada petición y de que ese servicio de lookup se convierta en su propio problema de disponibilidad y escalado.
El sharding geográfico/por atributo ubica los datos según un atributo de negocio — región, tenant, o plan del cliente — de modo que los datos de un usuario europeo viven en un shard de la UE por razones de latencia y regulación (residencia de datos), independientemente de hashes o rangos.
| Estrategia | Consultas por rango | Distribución de escrituras | Costo de rebalanceo | Uso típico |
|---|---|---|---|---|
| Por rango | Barata (uno/pocos shards) | Propensa a hotspot con claves monótonas | Moderado (dividir un rango) | Series de tiempo, escaneos ordenados |
| Por hash | Cara (scatter-gather) | Pareja | Alto sin hashing consistente | OLTP general a gran escala |
| Por directorio | Depende del diseño del directorio | Totalmente controlable | Bajo (actualizar el mapa) | Aislamiento multi-tenant |
| Geográfica/por atributo | Barata dentro de una región | Pareja si las regiones están balanceadas | Bajo (el atributo rara vez cambia) | Residencia de datos, latencia |
#Elegir una shard key: la checklist
- Cardinalidad alta — una shard key con solo 3 valores posibles (como un flag booleano) nunca puede distribuir datos en más de 3 shards, sin importar cómo la hashees.
- Distribución pareja de acceso — la cardinalidad no alcanza; un
customer_idcomo shard key está bien en cardinalidad, pero si un cliente enterprise genera el 40% de todo el tráfico, el shard de ese cliente se vuelve un hotspot sin importar el hashing (una "clave caliente", no un "shard caliente", pero se manifiesta igual). - Alineación con las consultas — elige una clave por la que ya filtran la mayoría de tus consultas. Si el 90% de las consultas son
WHERE user_id = ?, particiona poruser_id, así esas consultas golpean exactamente un shard en vez de dispersarse hacia todos. - Evitar claves monótonas cuando también necesitas rangos — si necesitas escrituras parejas Y escaneos por rango, considera hashear un prefijo mientras mantienes un sufijo ordenable, o agrupar por un atributo más grueso (día, región) combinado con un hash.
- Costo de resharding — planifica el crecimiento antes de necesitarlo; pasar de
hash(key) mod 4ahash(key) mod 8reordena casi todas las claves, mientras que el hashing consistente solo mueve aproximadamente1/Nde las claves al agregar un shard.
#Hashing consistente, en código
import bisectimport hashlibclass AnilloHashConsistente:def __init__(self, shards, nodos_virtuales=150):self.anillo = {}self.claves_ordenadas = []for shard in shards:for v in range(nodos_virtuales):h = self._hash(f"{shard}:{v}")self.anillo[h] = shardself.claves_ordenadas.append(h)self.claves_ordenadas.sort()def _hash(self, key: str) -> int:return int(hashlib.md5(key.encode()).hexdigest(), 16)def obtener_shard(self, key: str) -> str:h = self._hash(key)idx = bisect.bisect(self.claves_ordenadas, h) % len(self.claves_ordenadas)return self.anillo[self.claves_ordenadas[idx]]anillo = AnilloHashConsistente(["shard-a", "shard-b", "shard-c"])print(anillo.obtener_shard("user:48213")) # -> shard determinista para esta clave
Cada shard recibe muchos nodos virtuales en el anillo de hash (no solo un punto), lo que mantiene la carga balanceada entre shards aunque el hashing sea aleatorio — sin nodos virtuales, un shard podría quedarse por azar con una porción desproporcionada del anillo. Agregar un cuarto shard solo le "roba" nodos virtuales (y sus claves) a sus vecinos inmediatos en el anillo, en lugar de reordenar todo el espacio de claves como haría un mod N.
🧠 Check your understanding
0/1 · 0/1 answered1. Particionas una tabla por un ID de pedido autoincremental usando sharding puro por rango. ¿Cuál es el problema más probable en producción?