Conectando o PHP ao Replica Set

Nesse post será explicado como usar o driver do MongoDB com PHP conectado a um replica set. Caso não saiba como funciona um replica set, sugiro que leia primeiro o artigo sobre replicação com MongoDB.


##Configurando o replica set local:

Antes de começar, crie os diretórios para os arquivos de banco de dados de cada nó no replica set e inicie-os:

1
2
3
4
mkdir -p /data/rs1-0 /data/rs1-1 /data/rs1-2
mongod --port 27017 --replSet rs1 --dbpath /data/rs1-0 --smallfiles --oplogSize 128 &
mongod --port 27018 --replSet rs1 --dbpath /data/rs1-1 --smallfiles --oplogSize 128 &
mongod --port 27019 --replSet rs1 --dbpath /data/rs1-2 --smallfiles --oplogSize 128 &

Agora precisamos iniciar e configurar o replica set. Abra uma sessão no Mongo shell conectada a um dos membros que acabamos de iniciar e execute o método rs.initiate():

1
rs.initiate()

Será criado um arquivo de configuração padrão para o novo replica set. Verifique que essa configuração tem apenas o primeiro membro. Use o método rs.status() para isso:

1
rs.status()

Para adicionar os outros membros use o método rs.add():

1
2
rs.add('localhost:27018')
rs.add('localhost:27019')

##Conectando o replica set com a aplicação PHP

Para conectar ao replica set é necessário que a URL de conexão contenha pelo menos o nó primário, caso contrário um MongoConnectionException é lançado. Crie o seguinte arquivo PHP e execute:

1
2
3
4
5
6
7
8
9
10
11
12
13
$connStr = sprintf('mongodb://%s:%d,%s:%d,%s:%d/?replicaSet=%s',
  'localhost', 27017,
  'localhost', 27018,
  'localhost', 27019,
  'rs1');

$conn = null;

try {
  $conn = new MongoClient($connStr);
} catch (MongoConnectionException $e) {
  echo $e->getError();
}

Se tudo ocorreu corretamente, a partir de agora sua aplicação estará conectada ao replica set. Agora vamos fazer alguns testes de fogo para entender como o driver se comporta com um replica set.

###inserindo um documento no replica set:

Adicione as seguintes linhas no arquivo PHP e execute-o novamente:

1
2
3
$res = $conn->test->test->insert([
  'nome' => 'MongoDB'
]);

Você acabou de inserir um documento no nó primário, que será replicado para os outros nós a partir do momento em que o oplog do nó primário for copiado pelos outros nós.

###Driver PHP e Write concern

A configuração padrão para o write concern para o driver é w = 1 e j = 0, ou seja, a operação de escrita é do tipo acknownledged e não é necessário aguardar o próximo commit do sistema de journaling ocorrer.

Para aumentar o nível de confiabilidade do nosso replica set é necessário configurar o parâmetro w = 'majority', pois caso o nó primário caia, é necessário que a última entrada do seu oplog tenha sido copiada para pelo menos a maioria dos nós. Podemos configurar nossa query da seguinte forma:

1
2
3
4
5
$res = $conn->test->test->insert([
  'nome' => 'MongoDB'
], [
  'w' => 'majority'
]);

Isso aumenta a resiliância do sistema (fault tolerance), contudo essa configuração ainda não é segura para aplicações que requerem que os dados sejam obrigatóriamente persistidos antes de continuar o fluxo de trabalho. Para configurar a durabilidade, setamos o parâmetro j = 1:

1
2
3
4
5
6
$res = $conn->test->test->insert([
  'nome' => 'MongoDB'
], [
  'w' => 'majority',
  'j' => 1
]);

Essa configuração assegura que a informação tenha sido persistida no nó primário e replicada para a maioria dos outros nós. Usando w = 'majority' e j = 1 em um replica set, podemos atingir alta disponibilidade e durabilidade para o conjunto de dados usado pela aplicação.

Mesmo assim, fique atento para a arquitetura do replica set: se os nós estiverem dentro do mesmo datacenter, pode ter certeza que a sua confiabilidade será abalada por ser susceptível a network partitioning, ou seja, no caso de uma falha de rede no seu datacenter nenhum nó ficará acessível. Isso é péssimo.

###Atenção:

ATENÇÃO! jamais configurar w = n, sendo n > 1, pois caso o número de nós restantes em uma falha seja menor que n, então o driver não permitirá realizar mais escritas. Tente sempre usar w = 1 ou w = 'majority', dependendo do mínimo de disponibilidade necessária à sua aplicação.