Contadores sin puntos calientes

TeselaDB

TeselaDB

Equipo de TeselaDB

25 minIntermedio

Reparte un contador muy escrito en varios documentos y un índice sobre fechas en cubos para que la carga no 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

  • mongosh y un usuario con readWrite sobre la base shop.
  • Un clúster de TeselaDB con varios nodos, para que los rangos se repartan entre ellos.

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:

JavaScript
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:

JavaScript
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:

JavaScript
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

JavaScript
db.pageviews.drop();
db.events.drop();

Siguientes pasos