Data

27 fev, 2014

Escalando MongoDB – Replica Sets – Parte 01

Publicidade

Olá, pessoal!

Depois de muito tempo sem postar nada, resolvi compartilhar o que venho estudando sobre MongoDB. São meus primeiros passos e por enquanto não há nada muito profundo, mas como existem poucas referências em nosso idioma, acho que vale a pena escrever o que venho aprendendo.

Nesse artigo vamos montar uma estrutura de Replica Set do MongoDB com três servidores da forma mais simples possível. Vou usar Amazon EC2 para montar essa estrutura, mas você pode usar máquinas virtuais locais de forma fácil, por exemplo com VirtualBox ou Vagrant.

Antes de colocar a mão na massa, acho importante explicar que existem duas formas de escalar o MongoDB. A primeira delas chama-se Replica Set e consiste em replicar os dados entre instâncias de MongoDB, permitindo maior tolerância à falhas. A segunda se chama Sharding e consiste em dividir os dados (e a carga de I/O) entre instâncias de MongoDB ou entre Replica Sets, permitindo maior performance em leitura e escrita.

A criação de um Replica Set pode ser considerado um dos primeiros passos no processo de escala do MongoDB, pois ele garante redundância dos dados e tolerância à falhas, caso uma ou mais instâncias parem de funcionar, graças ao mecanismo de failover.

Bom, vamos ao que interessa!

Passo 1. Instalar o MongoDB

Como o objetivo do artigo não é mostrar a criação de instâncias EC2 nem a instalação do MongoDB, vou colocar aqui dois links para estas tarefas. O importante é que você deve proceder com a instalação normalmente, como um standalone.

IMPORTANTE: Use instancias EC2 de 64 bits devido a limitação do MongoDB. Mais informações neste link.

Passo 2. Criando as réplicas

Depois de ter instalado o MongoDB, precisamos criar mais duas réplicas (ou quantas você achar necessário) deste servidor. Você pode refazer o passo 1 para cada uma das novas instâncias, ou criar uma imagem da instância que preparamos e usá-la como base para as outras instâncias. Ferramentas como VirtualBox e Vagrant também permitem “clonar” VMs.

Passo 3. Configurar Replica Set

Aqui vamos ver o que realmente importa. Em cada um dos servidores acesse o arquivo de configuração que fica em /etc/mongod.conf e adicione a seguinte linha:

replSet = <nome do seu replica set>

É importante colocar o mesmo nome em todas as instâncias que farão parte do Replica Set. Depois disso reinicie o MongoDB.

Quando usamos um Replica Set, um dos servidores assume o papel de servidor primário e os outros servidores são secundários; isso quer dizer que todas as operações de escrita devem ser feitas no servidor primário e os servidores secundários aplicam estas mudanças de forma assíncrona.

Escolha um servidor para ser o primário, acesse o terminal do mongo e digite os seguintes comandos:

> rs.initiate()

Ele vai responder:

{
 "info2" : "no configuration explicitly specified -- making one",
 "me" : "ip-10-172-237-120:27017",
 "info" : "Config now saved locally.  Should come online in about a minute.",
 "ok" : 1
}
Depois disso vamos adicionar as demais instâncias. É recomendado que você crie entradas de DNS para cada servidor a fim de flexibilizar a configuração. Como estou fazendo apenas um exemplo, farei com os IPs mesmo.
rs0:PRIMARY> rs.add('192.168.148.153')
{ "ok" : 1 }

rs0:PRIMARY> rs.add('192.168.73.213')
{ "ok" : 1 }
Veja que o terminal mudou. Eu chamei meu Replica Set de rs0 e ele já aparece como primário. Vamos ver como ficou nossa configuração:
rs0:PRIMARY> rs.conf()
{
 "_id" : "rs0",
 "version" : 3,
 "members" : [
  {
   "_id" : 0,
   "host" : "192.168.237.120:27017"
  },
  {
   "_id" : 1,
   "host" : "192.168.148.153:27017"
  },
  {
   "_id" : 2,
   "host" : "192.168.73.213:27017"
  }
 ]
}

Voilà! Replica Set feito! Vamos brincar um pouco agora:

rs0:PRIMARY> db.teste.insert({'a':1})

rs0:PRIMARY> db.teste.find()
{ "_id" : ObjectId("530416cefb31eb86c9fbe3d4"), "a" : 1 }

rs0:SECONDARY> db.teste.find()
error: { "$err" : "not master and slaveOk=false", "code" : 13435 }
“Pow Rafael, deu pau aqui cara!”

Calma! Esta é uma proteção que existe nas instâncias secundárias devido a eventuais inconsistências que podem existir entre o servidor primário e os secundários. Nesse modelo, todas as escritas devem ser feitas no servidor primário, mas as leituras podem ser feitas nos servidores secundários, que, sob grande carga, podem demorar para aplicar as alterações feitas no servidor primário. A isso se da o nome de replication lag.

Para permitir a leitura basta usar o seguinte comando nos servidores secundários:

rs0:SECONDARY> rs.slaveOk()
rs0:SECONDARY> db.teste.find()
{ "_id" : ObjectId("530416cefb31eb86c9fbe3d4"), "a" : 1 }

Conclusão

Bom, nada do que falamos aqui é muito diferente do que está na documentação oficial. O que tentei fazer foi passar essa informação de forma mais simples e direta, explicando alguns conceitos importantes que me ajudaram a começar a entender as coisas.

Existem diversos outros aspectos importantes relacionados a escala de serviços como MongoDB e se você está trabalhando na nuvem, o número de fatores é maior ainda. Eles vão desde o sistema de arquivos que você está usando (prefira o ext4 por exemplo), passando por opções de RAID até a velocidade de acesso ao disco (no caso da AWS os IOPS). Se você quiser se aprofundar mais, leia os links que deixei de referência.

Se ficou algum dúvida pode me perguntar, eu provavelmente não saberei responder, mas vou tentar! Perguntas, dicas, sugestões, correções e etc são sempre bem vindos!

Referências