Sharding MongoDB: Guia Prático Passo a Passo

Sharding é um processo de dividir a grande escala de conjuntos de dados em um bloco de conjuntos de dados menores em várias instâncias do MongoDB em um ambiente distribuído.

O que é Fragmentação?

O sharding do MongoDB nos fornece uma solução escalável para armazenar uma grande quantidade de dados entre o número de servidores, em vez de armazenar em um único servidor.

Em termos práticos, não é viável armazenar dados em crescimento exponencial em uma única máquina. Consultar uma grande quantidade de dados armazenados em um único servidor pode levar a uma alta utilização de recursos e pode não fornecer um rendimento satisfatório de leitura e gravação.

Basicamente, existem dois tipos de métodos de dimensionamento que existem para realizar o crescimento de dados com o sistema:

O Vertical Scaling trabalha com o aprimoramento do desempenho de servidor único, adicionando processadores mais potentes, atualizando a RAM ou adicionando mais espaço em disco ao sistema. Mas existem as possíveis implicações da aplicação do dimensionamento vertical em casos de uso práticos com tecnologia existente e configurações de hardware.

O dimensionamento horizontal funciona adicionando mais servidores e distribuindo a carga em vários servidores. Como cada máquina estará lidando com o subconjunto de todo o conjunto de dados, ela oferece melhor eficiência e solução econômica em vez de implantar o hardware de ponta. Mas requer manutenção adicional de infraestrutura complexa com um grande número de servidores.

A fragmentação do Mongo DB funciona na técnica de dimensionamento horizontal.

Componentes de fragmentação

Para obter fragmentação no MongoDB, os seguintes componentes são necessários:

Shard é uma instância do Mongo para lidar com um subconjunto de dados originais. Os fragmentos precisam ser implantados no conjunto de réplicas.

Mongos é uma instância do Mongo e atua como uma interface entre um aplicativo cliente e um cluster fragmentado. Ele funciona como um roteador de consulta para shards.

O Config Server é uma instância do Mongo que armazena informações de metadados e detalhes de configuração do cluster. O MongoDB requer que o servidor de configuração seja implantado como um conjunto de réplicas.

Arquitetura de fragmentação

O cluster MongoDB consiste em vários conjuntos de réplicas.

Cada conjunto de réplicas consiste em no mínimo 3 ou mais instâncias do mongo. Um cluster fragmentado pode consistir em várias instâncias de fragmentos do mongo, e cada instância de fragmento funciona em um conjunto de réplicas de fragmentos. O aplicativo interage com o Mongos, que por sua vez se comunica com os shards. Portanto, no Sharding, os aplicativos nunca interagem diretamente com nós de shard. O roteador de consulta distribui os subconjuntos de dados entre os nós de estilhaços com base na chave de estilhaço.

Implementação de fragmentação

Siga as etapas abaixo para fragmentação

Passo 1

  • Inicie o servidor de configuração no conjunto de réplicas e habilite a replicação entre eles.

mongod –configsvr –port 27019 –replSet rs0 –dbpath C:datadata1 –bind_ip localhost

mongod –configsvr –port 27018 –replSet rs0 –dbpath C:datadata2 –bind_ip localhost

mongod –configsvr –port 27017 –replSet rs0 –dbpath C:datadata3 –bind_ip localhost

Passo 2

  • Inicialize o conjunto de réplicas em um dos servidores de configuração.

rs.initiate( { _id : “rs0”, configsvr: true, membros: [   { _id: 0, host: “IP:27017” },   { _id: 1, host: “IP:27018” },   { _id: 2, host: “IP:27019” }    ] })

rs.initiate( { _id : "rs0",  configsvr: true,  members: [   { _id: 0, host: "IP:27017" },   { _id: 1, host: "IP:27018" },   { _id: 2, host: "IP:27019" }    ] })
{
        "ok" : 1,
        "$gleStats" : {
                "lastOpTime" : Timestamp(1593569257, 1),
                "electionId" : ObjectId("000000000000000000000000")
        },
        "lastCommittedOpTime" : Timestamp(0, 0),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593569257, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1593569257, 1)
}

etapa 3

  • Inicie a fragmentação de servidores no conjunto de réplicas e habilite a replicação entre eles.
  6 melhores serviços e ferramentas de monitoramento do Microsoft Azure

mongod –shardsvr –port 27020 –replSet rs1 –dbpath C:datadata4 –bind_ip localhost

mongod –shardsvr –port 27021 –replSet rs1 –dbpath C:datadata5 –bind_ip localhost

mongod –shardsvr –port 27022 –replSet rs1 –dbpath C:datadata6 –bind_ip localhost

O MongoDB inicializa o primeiro servidor de fragmentação como Primário, para mover o uso do servidor de fragmentação primário movePrimary método.

Passo 4

  • Inicialize o conjunto de réplicas em um dos servidores fragmentados.

rs.initiate( { _id : “rs0”, membros: [   { _id: 0, host: “IP:27020” },   { _id: 1, host: “IP:27021” },   { _id: 2, host: “IP:27022” }    ] })

rs.initiate( { _id : "rs0",  members: [   { _id: 0, host: "IP:27020" },   { _id: 1, host: "IP:27021" },   { _id: 2, host: "IP:27022" }    ] })
{
        "ok" : 1,
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593569748, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1593569748, 1)
}

Etapa 5

  • Inicie as mangas para o cluster fragmentado

mongos –porta 40000 –configdb rs0/localhost:27019,localhost:27018, localhost:27017

Etapa 6

  • Conecte o servidor de rotas do mongo

mongo –porta 40000

  • Agora, adicione servidores de fragmentação.

sh.addShard( “rs1/localhost:27020,localhost:27021,localhost:27022”)

sh.addShard( "rs1/localhost:27020,localhost:27021,localhost:27022")
{
        "shardAdded" : "rs1",
        "ok" : 1,
        "operationTime" : Timestamp(1593570212, 2),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593570212, 2),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Etapa 7

  • No shell do mongo, habilite o sharding no banco de dados e nas coleções.
  • Ativar fragmentação no banco de dados

sh.enableSharding(“geekFlareDB”)

sh.enableSharding("geekFlareDB")
{
        "ok" : 1,
        "operationTime" : Timestamp(1591630612, 1),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1591630612, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Etapa 8

  • Para fragmentar a chave de fragmentação da coleção (descrita posteriormente neste artigo) é necessário.

Sintaxe: sh.shardCollection(“dbName.collectionName”, { “key” : 1 } )

sh.shardCollection("geekFlareDB.geekFlareCollection", { "key" : 1 } )
{
        "collectionsharded" : "geekFlareDB.geekFlareCollection",
        "collectionUUID" : UUID("0d024925-e46c-472a-bf1a-13a8967e97c1"),
        "ok" : 1,
        "operationTime" : Timestamp(1593570389, 3),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593570389, 3),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Observe se a coleção não existir, crie da seguinte maneira.

db.createCollection("geekFlareCollection")
{
        "ok" : 1,
        "operationTime" : Timestamp(1593570344, 4),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593570344, 5),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Etapa 9

Insira dados na coleção. Os logs do Mongo começarão a crescer, indicando que um balanceador está em ação e tentando balancear os dados entre os fragmentos.

Etapa 10

A última etapa é verificar o status da fragmentação. O status pode ser verificado executando o comando abaixo no nó de rota do Mongos.

Status de fragmentação

Verifique o status do sharding executando o comando abaixo no nó de rota do mongo.

sh.status()

mongos> sh.status()
--- Sharding Status ---
  sharding version: {
        "_id" : 1,
        "minCompatibleVersion" : 5,
        "currentVersion" : 6,
        "clusterId" : ObjectId("5ede66c22c3262378c706d21")
  }
  shards:
        {  "_id" : "rs1",  "host" : "rs1/localhost:27020,localhost:27021,localhost:27022",  "state" : 1 }
  active mongoses:
        "4.2.7" : 1
  autosplit:
        Currently enabled: yes
  balancer:
        Currently enabled:  yes
        Currently running:  no
        Failed balancer rounds in last 5 attempts:  5
        Last reported error:  Could not find host matching read preference { mode: "primary" } for set rs1
        Time of Reported error:  Tue Jun 09 2020 15:25:03 GMT+0530 (India Standard Time)
        Migration Results for the last 24 hours:
                No recent migrations
  databases:
        {  "_id" : "config",  "primary" : "config",  "partitioned" : true }
                config.system.sessions
                        shard key: { "_id" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                rs1     1024
                        too many chunks to print, use verbose if you want to force print
        {  "_id" : "geekFlareDB",  "primary" : "rs1",  "partitioned" : true,  "version" : {  "uuid" : UUID("a770da01-1900-401e-9f34-35ce595a5d54"),  "lastMod" : 1 } }
                geekFlareDB.geekFlareCol
                        shard key: { "key" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                rs1     1
                        { "key" : { "$minKey" : 1 } } -->> { "key" : { "$maxKey" : 1 } } on : rs1 Timestamp(1, 0)
                geekFlareDB.geekFlareCollection
                        shard key: { "product" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                rs1     1
                        { "product" : { "$minKey" : 1 } } -->> { "product" : { "$maxKey" : 1 } } on : rs1 Timestamp(1, 0)
        {  "_id" : "test",  "primary" : "rs1",  "partitioned" : false,  "version" : {  "uuid" : UUID("fbc00f03-b5b5-4d13-9d09-259d7fdb7289"),  "lastMod" : 1 } }

mongos>

Distribuição de dados

O roteador Mongos distribui a carga entre os shards com base na chave do shard e para distribuir os dados uniformemente; balanceador entra em ação.

  Como obter um agendador de reuniões do Google

O componente chave para distribuir dados entre os shards são

  • Um balanceador desempenha um papel no balanceamento do subconjunto de dados entre os nós fragmentados. O balanceador é executado quando o servidor Mongos começa a distribuir cargas entre os shards. Uma vez iniciado, o Balancer distribuiu os dados de forma mais uniforme. Para verificar o estado do balanceador, execute sh.status() ou sh.getBalancerState() oush.isBalancerRunning().
mongos> sh.isBalancerRunning()
true
mongos>

OU

mongos> sh.getBalancerState()
true
mongos>

Após inserir os dados, notamos alguma atividade no daemon do Mongos informando que ele está movendo alguns chunks para os shards específicos e assim por diante, ou seja, o balanceador estará em ação tentando balancear os dados entre os shards. A execução do balanceador pode levar a problemas de desempenho; portanto, sugere-se executar o balanceador dentro de um determinado janela do balanceador.

mongos> sh.status()
--- Sharding Status ---
  sharding version: {
        "_id" : 1,
        "minCompatibleVersion" : 5,
        "currentVersion" : 6,
        "clusterId" : ObjectId("5efbeff98a8bbb2d27231674")
  }
  shards:
        {  "_id" : "rs1",  "host" : "rs1/127.0.0.1:27020,127.0.0.1:27021,127.0.0.1:27022",  "state" : 1 }
        {  "_id" : "rs2",  "host" : "rs2/127.0.0.1:27023,127.0.0.1:27024,127.0.0.1:27025",  "state" : 1 }
  active mongoses:
        "4.2.7" : 1
  autosplit:
        Currently enabled: yes
  balancer:
        Currently enabled:  yes
        Currently running:  yes
        Failed balancer rounds in last 5 attempts:  5
        Last reported error:  Could not find host matching read preference { mode: "primary" } for set rs2
        Time of Reported error:  Wed Jul 01 2020 14:39:59 GMT+0530 (India Standard Time)
        Migration Results for the last 24 hours:
                1024 : Success
  databases:
        {  "_id" : "config",  "primary" : "config",  "partitioned" : true }
                config.system.sessions
                        shard key: { "_id" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                rs2     1024
                        too many chunks to print, use verbose if you want to force print
        {  "_id" : "geekFlareDB",  "primary" : "rs2",  "partitioned" : true,  "version" : {  "uuid" : UUID("a8b8dc5c-85b0-4481-bda1-00e53f6f35cd"),  "lastMod" : 1 } }
                geekFlareDB.geekFlareCollection
                        shard key: { "key" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                rs2     1
                        { "key" : { "$minKey" : 1 } } -->> { "key" : { "$maxKey" : 1 } } on : rs2 Timestamp(1, 0)
        {  "_id" : "test",  "primary" : "rs2",  "partitioned" : false,  "version" : {  "uuid" : UUID("a28d7504-1596-460e-9e09-0bdc6450028f"),  "lastMod" : 1 } }

mongos>
  • A chave de fragmentação determina a lógica para distribuir documentos de coleção de fragmentos entre os fragmentos. A chave de fragmentação pode ser um campo indexado ou um campo composto indexado que deve estar presente em todos os documentos da coleção a ser inserida. Os dados serão particionados em partes e cada parte será associada à chave de fragmentação baseada em intervalo. Com base no intervalo de consulta, o roteador decidirá qual fragmento armazenará o fragmento.

A Shard Key pode ser selecionada considerando cinco propriedades:

  • Cardinalidade
  • Distribuição de gravação
  • Ler distribuição
  • Ler segmentação
  • Ler localidade

Uma chave de fragmentação ideal faz com que o MongoDB distribua uniformemente a carga entre todos os fragmentos. Escolher uma boa chave de fragmentação é extremamente importante.

Imagem: MongoDB

Removendo o nó do estilhaço

Antes de remover os estilhaços do cluster, o usuário deve garantir a migração segura dos dados para os estilhaços restantes. O MongoDB cuida da drenagem segura de dados para outros nós de estilhaços antes da remoção do nó de estilhaço necessário.

Execute o comando abaixo para remover o fragmento necessário.

Passo 1

Primeiro, precisamos determinar o nome do host do shard a ser removido. O comando abaixo listará todos os shards presentes no cluster junto com o estado do shard.

db.adminCommand( { listShards: 1 } )

mongos> db.adminCommand( { listShards: 1 } )
{
        "shards" : [
                {
                        "_id" : "rs1",
                        "host" : "rs1/127.0.0.1:27020,127.0.0.1:27021,127.0.0.1:27022",
                        "state" : 1
                },
                {
                        "_id" : "rs2",
                        "host" : "rs2/127.0.0.1:27023,127.0.0.1:27024,127.0.0.1:27025",
                        "state" : 1
                }
        ],
        "ok" : 1,
        "operationTime" : Timestamp(1593572866, 15),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593572866, 15),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Passo 2

Emita o comando abaixo para remover o estilhaço necessário do cluster. Uma vez emitido, o balanceador cuida da remoção de pedaços do nó de estilhaços de drenagem e, em seguida, equilibra a distribuição dos pedaços restantes entre os nós de fragmentos restantes.

db.adminCommand( { removeShard: “shardedReplicaNodes” } )

mongos> db.adminCommand( { removeShard: "rs1/127.0.0.1:27020,127.0.0.1:27021,127.0.0.1:27022" } )
{
        "msg" : "draining started successfully",
        "state" : "started",
        "shard" : "rs1",
        "note" : "you need to drop or movePrimary these databases",
        "dbsToMove" : [ ],
        "ok" : 1,
        "operationTime" : Timestamp(1593572385, 2),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593572385, 2),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

etapa 3

Para verificar o status do fragmento de drenagem, emita o mesmo comando novamente.

db.adminCommand( { removeShard: “rs1/127.0.0.1:27020,127.0.0.1:27021,127.0.0.1:27022” } )

Precisamos esperar até que a drenagem dos dados seja concluída. Os campos msg e state mostrarão se a drenagem de dados foi concluída ou não, como segue

"msg" : "draining ongoing",
"state" : "ongoing",

Também podemos verificar o status com o comando sh.status(). Uma vez removido, o nó fragmentado não será refletido na saída. Mas se a drenagem estiver em andamento, o nó fragmentado virá com o status de drenagem como verdadeiro.

Passo 4

Continue verificando o status de drenagem com o mesmo comando acima, até que o fragmento necessário seja removido completamente.
Uma vez concluído, a saída do comando refletirá a mensagem e o estado como concluído.

"msg" : "removeshard completed successfully",
"state" : "completed",
"shard" : "rs1",
"ok" : 1,

Etapa 5

Por fim, precisamos verificar os fragmentos restantes no cluster. Para verificar o status digite sh.status() ou db.adminCommand( { listShards: 1 } )

mongos> db.adminCommand( { listShards: 1 } )
{
        "shards" : [
                {
                        "_id" : "rs2",
                        "host" : "rs2/127.0.0.1:27023,127.0.0.1:27024,127.0.0.1:27025",
                        "state" : 1
                }
        ],
        "ok" : 1,
        "operationTime" : Timestamp(1593575215, 3),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593575215, 3),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Aqui, podemos ver que o fragmento removido não está mais presente na lista de fragmentos.

Benefícios da fragmentação sobre a replicação

  • Na replicação, o nó primário trata de todas as operações de gravação, enquanto os servidores secundários são necessários para manter cópias de backup ou atender a operações somente leitura. Mas ao fragmentar junto com conjuntos de réplicas, a carga é distribuída entre vários servidores.
  • Um único conjunto de réplicas é limitado a 12 nós, mas não há restrição quanto ao número de estilhaços.
  • A replicação requer hardware de ponta ou dimensionamento vertical para lidar com grandes conjuntos de dados, o que é muito caro em comparação com a adição de servidores adicionais na fragmentação.
  • Na replicação, o desempenho de leitura pode ser aprimorado com a adição de mais servidores escravos/secundários, enquanto, na fragmentação, o desempenho de leitura e gravação será aprimorado com a adição de mais nós de fragmentos.

Limitação de fragmentação

  • O cluster Sharded não oferece suporte à indexação exclusiva nos estilhaços até que o índice exclusivo seja prefixado com a chave de estilhaço completa.
  • Todas as operações de atualização para coleção fragmentada em um ou vários documentos devem conter a chave fragmentada ou o campo _id na consulta.
  • As coleções podem ser fragmentadas se seu tamanho não exceder o limite especificado. Esse limite pode ser estimado com base no tamanho médio de todas as chaves de fragmentação e no tamanho configurado dos blocos.
  • A fragmentação compreende limites operacionais no tamanho máximo da coleção ou no número de divisões.
  • Escolher as chaves de fragmentação erradas pode levar a implicações de desempenho.

Conclusão

O MongoDB oferece sharding integrado para implementar um grande banco de dados sem comprometer o desempenho. Espero que o acima ajude você a configurar o sharding do MongoDB. Em seguida, você pode querer se familiarizar com alguns dos comandos mais usados ​​do MongoDB.