📚 Estudo: CouchDB – Replicação e Cluster

1. Subindo duas instâncias isoladas para testes

Arquivo docker-compose.yml simples com duas instâncias separadas:

version: "3.9"
 
services:
  couchdb1:
    image: couchdb:3
    container_name: couchdb1
    environment:
      - COUCHDB_USER=admin
      - COUCHDB_PASSWORD=admin
    ports:
      - "5984:5984"
    networks:
      - couchdbnet
 
  couchdb2:
    image: couchdb:3
    container_name: couchdb2
    environment:
      - COUCHDB_USER=admin
      - COUCHDB_PASSWORD=admin
    ports:
      - "5985:5984"
    networks:
      - couchdbnet
 
networks:
  couchdbnet:
    driver: bridge

Acesso via API / Fauxton

  • Instância 1: http://localhost:5984/_utils/
  • Instância 2: http://localhost:5985/_utils/ Login: admin / admin.

2. Replicação entre duas instâncias

2.1 Replicação pontual (one-shot)

# Criar base na origem
curl -X PUT http://admin:admin@localhost:5984/minha_base
 
# Inserir documento exemplo
curl -X POST http://admin:admin@localhost:5984/minha_base \
  -H "Content-Type: application/json" \
  -d '{"_id":"doc1","tipo":"exemplo","ok":true}'
 
# Replicar origem -> destino
curl -X POST http://admin:admin@localhost:5984/_replicate \
  -H "Content-Type: application/json" \
  -d '{
    "source": "http://admin:admin@localhost:5984/minha_base",
    "target": "http://admin:admin@localhost:5985/minha_base",
    "create_target": true
  }'

2.2 Replicação contínua (_replicator)

# Criar DB de replicações (se não existir)
curl -X PUT http://admin:admin@localhost:5984/_replicator
 
# Criar replicação contínua
curl -X POST http://admin:admin@localhost:5984/_replicator \
  -H "Content-Type: application/json" \
  -d '{
    "_id": "replica-minha_base-para-5985",
    "source": "http://admin:admin@localhost:5984/minha_base",
    "target": "http://admin:admin@localhost:5985/minha_base",
    "create_target": true,
    "continuous": true,
    "user_ctx": { "name": "admin", "roles": ["_admin"] }
  }'

2.3 Replicação com filtro

Criar filtro:

curl -X PUT http://admin:admin@localhost:5984/minha_base/_design/rep \
  -H "Content-Type: application/json" \
  -d '{
    "filters": {
      "somente_tipo_exemplo": "function(doc, req) { return doc.tipo === \"exemplo\"; }"
    }
  }'

Usar filtro na replicação:

curl -X POST http://admin:admin@localhost:5984/_replicate \
  -H "Content-Type: application/json" \
  -d '{
    "source": "http://admin:admin@localhost:5984/minha_base",
    "target": "http://admin:admin@localhost:5985/minha_base",
    "create_target": true,
    "filter": "rep/somente_tipo_exemplo"
  }'

3. Configurando um Cluster

3.1 docker-compose.yml para cluster

version: "3.9"
 
services:
  couchdb1:
    image: couchdb:3
    container_name: couchdb1
    hostname: couchdb1
    environment:
      - NODENAME=couchdb@couchdb1
      - COUCHDB_USER=admin
      - COUCHDB_PASSWORD=admin
      - COUCHDB_SECRET=super-secret-long-random-string
      - ERL_FLAGS=-setcookie couchdb-cluster-cookie
    ports:
      - "5984:5984"
    volumes:
      - c1data:/opt/couchdb/data
    networks:
      - couchdbnet
 
  couchdb2:
    image: couchdb:3
    container_name: couchdb2
    hostname: couchdb2
    environment:
      - NODENAME=couchdb@couchdb2
      - COUCHDB_USER=admin
      - COUCHDB_PASSWORD=admin
      - COUCHDB_SECRET=super-secret-long-random-string
      - ERL_FLAGS=-setcookie couchdb-cluster-cookie
    ports:
      - "5985:5984"
    volumes:
      - c2data:/opt/couchdb/data
    networks:
      - couchdbnet
 
networks:
  couchdbnet:
    driver: bridge
 
volumes:
  c1data:
  c2data:

Importante:

  • NODENAME diferente por nó, mas mesmo COUCHDB_SECRET e cookie (-setcookie).
  • Ambos na mesma rede couchdbnet.

3.2 Configuração via API

USER=admin
PASS=admin
 
# Checar nós
curl -s http://$USER:$PASS@localhost:5984/ | jq .
curl -s http://$USER:$PASS@localhost:5985/ | jq .
 
# 1) Habilitar cluster no nó 1
curl -s -X POST http://$USER:$PASS@localhost:5984/_cluster_setup \
  -H "Content-Type: application/json" \
  -d '{
    "action":"enable_cluster",
    "bind_address":"0.0.0.0",
    "username":"'"$USER"'",
    "password":"'"$PASS"'",
    "port":5984,
    "node_count":"2",
    "remote_node":"couchdb2",
    "remote_current_user":"'"$USER"'",
    "remote_current_password":"'"$PASS"'"
  }' | jq .
 
# 2) Adicionar nó 2
curl -s -X POST http://$USER:$PASS@localhost:5984/_cluster_setup \
  -H "Content-Type: application/json" \
  -d '{
    "action":"add_node",
    "host":"couchdb2",
    "port":5984,
    "username":"'"$USER"'",
    "password":"'"$PASS"'"
  }' | jq .
 
# 3) Finalizar cluster
curl -s -X POST http://$USER:$PASS@localhost:5984/_cluster_setup \
  -H "Content-Type: application/json" \
  -d '{"action":"finish_cluster"}' | jq .
 
# 4) Verificar membros
curl -s http://$USER:$PASS@localhost:5984/_membership | jq .

3.3 Criando base no cluster

# 8 shards, 2 réplicas
curl -s -X PUT "http://$USER:$PASS@localhost:5984/minha_base" \
  -H "Content-Type: application/json" \
  -d '{"q":8,"n":2}' | jq .
 
# Ver shards
curl -s "http://$USER:$PASS@localhost:5984/minha_base/_shards" | jq .

4. Vantagens do Cluster

  1. Alta disponibilidade: tolerância a falhas com réplicas automáticas.
  2. Escalabilidade horizontal: sharding e distribuição de carga.
  3. Gerenciamento unificado: acesso a todos os nós via um único endpoint.
  4. Resiliência de dados: fator de réplica garante recuperação em caso de perda.
  5. Balanceamento automático: coordenação de leitura/escrita entre nós.
  6. Menos risco de inconsistência: replicação interna e controlada por quorum.

Com isso, você tem:

  • Cenário de duas instâncias isoladas para testar replicação manual.
  • Cenário de cluster real com sharding, replicação automática e quorum.
  • Exemplos práticos de docker-compose, chamadas curl e explicações.