Aller au contenu

MongDB Sharding


Définition

C'est une méthode de distribution des données sur plusieurs machines (cluster). Elle permet à MongoDB de passer à l'échelle pour accueillir des bases de données massives avec un débit très important.
Elle fait partie des techniques de mise à l'échelle horizontale : Horizontal scaling.

shard : éclat, tesson (fragment)

Principe de fonctionnement

Le cluster est composé de 3 types de serveurs :

  1. mongos : routeur pour l'acheminement des requêtes.
  2. Config Server : enregistre les métadonnées sur et la configuration pour le cluster.
  3. Shard : contient un sous ensemble des données (chunk ou partition) qui peut être déployé comme Replica Set.

La distribution des données sur le cluster est basée sur une clé shard key. La clé peut être un ou plusieurs champs. Elle est utilisée dans l'une des deux stratégies de distribution :

  • Hashed Sharding : un hash de clé détermine quelle dans quelle chunk mettre les données.
  • Ranged Sharding : la clé est affecté à un chunk selon valeur.
Hashed Sharding Ranged Sharding

Réplication et Sharding avec Docker

Le cluster à mettre en place est compsée des noeuds suivants :

  • 2 Mongos (router): routage des requêtes vers les shards.
    • router01
    • router02
  • 3 Config Servers : enregistre les métadonnées de la configuration du cluster
    • configsvr01
    • configsvr02
    • configsvr03
  • 3 Shards (avec un replica set de 3 membres) : détient une partie (shard) des données.
    • shard01-a, shard01-b, shard01-c
    • shard02-a, shard02-b, shard02-c
    • shard03-a, shard03-b, shard03-c

docker-compose sera utilisé pour automatiser la gestion des différents containers (14 dans notre cas). Les fichiers nécessaires à cette manipulation sont mis dans cette archive mongodb-cluster.zip que vous devez télécharger et décompresser.

Vous obtiendrez un dossier contenant :

  • docker-compose.yaml qui contient les paramètres des différents containers :
version: '3'

services:
# Router

  ## router 01
  router01:
    image: mongo:6.0.1
    container_name: router-01
    command: |
      mongos --port 27017 --configdb rs-config-server/configsvr01:27017,configsvr02:27017,configsvr03:27017 --bind_ip_all
    ports:
      - 27117:27017
    volumes:
      - ./scripts:/scripts

  ## router 02
  router02:
    image: mongo:6.0.1
    container_name: router-02
    command: |
      mongos --port 27017 --configdb rs-config-server/configsvr01:27017,configsvr02:27017,configsvr03:27017 --bind_ip_all
    volumes:
      - ./scripts:/scripts
    ports:
      - 27118:27017
    links:
      - router01

# Config Servers

  ## Config server 01
  configsvr01:
    image: mongo:6.0.1
    container_name: mongo-config-01 
    command: |
      mongod --port 27017 --configsvr --replSet rs-config-server
    volumes:
      - ./scripts:/scripts 
    ports:
      - 27119:27017
    links:
      - shard01-a
      - shard02-a
      - shard03-a

  ## Config server 02
  configsvr02:
    image: mongo:6.0.1
    container_name: mongo-config-02 
    command: |
      mongod --port 27017 --configsvr --replSet rs-config-server
    volumes:
      - ./scripts:/scripts
    ports:
      - 27120:27017
    links:
      - configsvr01

  ## Config server 03
  configsvr03:
    image: mongo:6.0.1
    container_name: mongo-config-03 
    command: |
      mongod --port 27017 --configsvr --replSet rs-config-server
    volumes:
      - ./scripts:/scripts
    ports:
      - 27121:27017
    links:
      - configsvr02

# Shards

  ## Shards 01   
  shard01-a:
    image: mongo:6.0.1
    container_name: shard-01-a
    command: |
      mongod --port 27017 --shardsvr --replSet rs-shard-01
    volumes:
      - ./scripts:/scripts
    ports:
      - 27122:27017
    links:
      - shard01-b
      - shard01-c
  shard01-b:
    image: mongo:6.0.1
    container_name: shard-01-b
    command: |
      mongod --port 27017 --shardsvr --replSet rs-shard-01
    volumes:
      - ./scripts:/scripts
    ports:
      - 27123:27017
  shard01-c:
    image: mongo:6.0.1
    container_name: shard-01-c
    command: |
      mongod --port 27017 --shardsvr --replSet rs-shard-01
    volumes:
      - ./scripts:/scripts
    ports:
      - 27124:27017

  ## Shards 02
  shard02-a:
    image: mongo:6.0.1
    container_name: shard-02-a
    command: |
      mongod --port 27017 --shardsvr --replSet rs-shard-02
    volumes:
      - ./scripts:/scripts
    ports:
      - 27125:27017
    links:
      - shard02-b
      - shard02-c
  shard02-b:
    image: mongo:6.0.1
    container_name: shard-02-b
    command: |
      mongod --port 27017 --shardsvr --replSet rs-shard-02
    volumes:
      - ./scripts:/scripts
    ports:
      - 27126:27017
  shard02-c:
    image: mongo:6.0.1
    container_name: shard-02-c
    command: |
      mongod --port 27017 --shardsvr --replSet rs-shard-02
    volumes:
      - ./scripts:/scripts
    ports:
      - 27127:27017

  ## Shards 03
  shard03-a:
    image: mongo:6.0.1
    container_name: shard-03-a
    command: |
      mongod --port 27017 --shardsvr --replSet rs-shard-03
    volumes:
      - ./scripts:/scripts
    ports:
      - 27128:27017
    links:
      - shard03-b
      - shard03-c
  shard03-b:
    image: mongo:6.0.1
    container_name: shard-03-b
    command: |
      mongod --port 27017 --shardsvr --replSet rs-shard-03
    volumes:
      - ./scripts:/scripts
    ports:
      - 27129:27017
  shard03-c:
    image: mongo:6.0.1
    container_name: shard-03-c
    command: |
      mongod --port 27017 --shardsvr --replSet rs-shard-03
    volumes:
      - ./scripts:/scripts
    ports:
      - 27130:27017
  • Un dossier scripts contenant les scripts d'initialisation de replica set et shards, les routeurs et les serveurs de configuration.

1⃣ Démarrer la pile de containers

docker-compose up -d

2⃣ Initialiser les serveurs de configuration

docker-compose exec configsvr01 sh -c "mongosh < /scripts/configserver.js"

3⃣ Initialiser les shards

docker-compose exec shard01-a sh -c "mongosh < /scripts/replicaset_1.js"
docker-compose exec shard02-a sh -c "mongosh < /scripts/replicaset_2.js"
docker-compose exec shard03-a sh -c "mongosh < /scripts/replicaset_3.js"

4⃣ Attendre l'élection des primary puis initialiser les routeurs

docker-compose exec router01 sh -c "mongosh < /scripts/router.js"
5⃣ Vérifier le cluster :

  • Vérifier la réplication

    docker-compose exec shard01-a mongosh
    
    et ensuite rs.status()

  • Vérifier les shards

    docker-compose exec router01 mongosh
    
    et ensuite sh.status()

6⃣ Distribuer une base de données

  • Créer une nouvelle base et nouvelle collection. Puis créer un index sur _id.

> use testDB;
> sh.enableSharding("testDB");
> db.createCollection("test");
> db.test.createIndex({"_id":"hashed"});
> sh.shardCollection("testDB.test",{"_id":"hashed"});
- Importer un dataset et vérifier l'état du Sharding.

mongoimport -d testDB -c test --port 27017 restaurants.json
mongosh --port 27017 --eval "sh.status()"
Attention

Les requêtes sont destinées au routeur.

  • Inspecter les propriétés et déterminer :
    • La clé de sharding
    • Le nombre de shunks par shard

7⃣ Vérifier la distribution des documents sur les shards : sur le router, exécuter les commandes :

use testDB
db.test.getShardDistribution()

Voici un exemple de sortie :

[direct: mongos] test> use testDB
switched to db testDB
[direct: mongos] testDB> db.test.getShard
db.test.getShardVersion       db.test.getShardDistribution

[direct: mongos] testDB> db.test.getShardDistribution()
Shard rs-shard-02 at rs-shard-02/shard02-a:27017,shard02-b:27017,shard02-c:27017
{
  data: '3.66MiB',
  docs: 8501,
  chunks: 2,
  'estimated data per chunk': '1.83MiB',
  'estimated docs per chunk': 4250
}
---
Shard rs-shard-03 at rs-shard-03/shard03-a:27017,shard03-b:27017,shard03-c:27017
{
  data: '3.64MiB',
  docs: 8414,
  chunks: 2,
  'estimated data per chunk': '1.82MiB',
  'estimated docs per chunk': 4207
}
---
Shard rs-shard-01 at rs-shard-01/shard01-a:27017,shard01-b:27017,shard01-c:27017
{
  data: '3.65MiB',
  docs: 8442,
  chunks: 2,
  'estimated data per chunk': '1.82MiB',
  'estimated docs per chunk': 4221
}
---
Totals
{
  data: '10.95MiB',
  docs: 25357,
  chunks: 6,
  'Shard rs-shard-02': [
    '33.46 % data',
    '33.52 % docs in cluster',
    '452B avg obj size on shard'
  ],
  'Shard rs-shard-03': [
    '33.22 % data',
    '33.18 % docs in cluster',
    '453B avg obj size on shard'
  ],
  'Shard rs-shard-01': [
    '33.31 % data',
    '33.29 % docs in cluster',
    '453B avg obj size on shard'
  ]
}

Isolation et cohérence

Dans ce quit, nous configurons les niveaux de cohérence avec les paramètres readConcern et writeConcern.

1⃣ Se connecter à un routeur

docker-compose exec -it router01 mongosh

2⃣ readConcern

use testDB;
db.test.find({}).readConcern("majority");

3⃣ writeConcern

try {
  db.test.updateMany(
    { "name" : "Windy's" },
    { $inc: { "violations" : 3}, $set: { "Closed" : true } },
    { w: "majority", wtimeout: 100 }
  );
} catch (e) {
  print(e);
}