Contadores sin puntos calientes
25 minIntermedio

Cuando un contador recibe muchas escrituras, repartirlo en varios documentos y su índice de fechas en cubos evita que toda la carga caiga en un rango.
TeselaDB guarda los documentos y las entradas de índice ordenados por su clave y los reparte en rangos. Un contador que todas las peticiones incrementan es un solo documento, en un solo rango y con un solo líder. Un índice sobre una fecha de creación manda todas sus entradas nuevas al final de su intervalo.
Lo que vas a construir
Un contador de visitas repartido en ocho documentos, que se lee con una agregación, y un índice sobre la fecha de los eventos con sus entradas repartidas en cubos hash.
Requisitos
- Docker y
mongosh, para arrancar TeselaDB en tu máquina y mirar los datos.
Prepara el entorno
docker run -d --name teseladb -p 27017:27017 viuzi/teseladb:latest \
start --dbpath /data --insecure --insecure-allow-remote --bind_ip 0.0.0.0
export TESELADB_URI="mongodb://127.0.0.1:27017/shop"
mongosh "$TESELADB_URI" --quiet --eval 'db.runCommand({ ping: 1 }).ok'
mongosh "$TESELADB_URI"El contenedor arranca un nodo de TeselaDB sin TLS ni usuarios, que basta para seguir la guía en tu máquina. Cuando mongosh responde 1, el nodo ya acepta conexiones. TESELADB_URI apunta a ese nodo y a la base shop; en un clúster de producción la cadena lleva TLS y usuario, como cuenta Conectar tu aplicación. Con un solo nodo los rangos se dividen igual que en un clúster. Con varios, además, se reparten. La última línea abre mongosh sobre esa base, y en esa misma consola escribes todos los pasos de la guía, desde el contador repartido hasta la agregación que suma sus ocho documentos.
1. Reparte el contador
Cada incremento elige al azar uno de los ocho documentos de la página. Así las escrituras van a claves distintas y no chocan en una sola:
const SHARDS = 8;
for (let i = 0; i < 100; i++) {
const shard = Math.floor(Math.random() * SHARDS);
db.pageviews.updateOne({ _id: { page: "home", shard } }, { $inc: { count: 1 } }, { upsert: true });
}2. Reparte el índice sobre la fecha
Con teselaBuckets, las entradas del índice se reparten en 16 cubos hash. El planificador junta los cubos al leer, así
que las consultas por fecha no cambian:
db.events.createIndex({ createdAt: 1 }, { teselaBuckets: 16 });Probarlo
El total de la página es la suma de sus ocho documentos. Una agregación que filtra la página y suma el campo count
de cada uno de ellos devuelve los 100 incrementos que escribió el bucle del paso 1:
db.pageviews.aggregate([
{ $match: { "_id.page": "home" } },
{ $group: { _id: "$_id.page", views: { $sum: "$count" } } },
]);[ { _id: 'home', views: 100 } ]Con carga real, teseladb admin ranges --collection shop.pageviews muestra los documentos del contador en varios
rangos cuando la colección crece y se divide.
Limpiar
db.pageviews.drop();
db.events.drop();Al final borra también el contenedor con la última orden: el nodo guarda los datos dentro, sin volumen, así que con él desaparece todo lo que escribiste durante la guía y el puerto 27017 queda libre:
docker rm -f teseladbSiguientes pasos
- Claves y puntos calientes, con por qué una clave que siempre crece concentra la carga.
- Detectar puntos calientes, para ver qué rangos reciben más escrituras.