Guia abrangente para otimizar o desempenho do MongoDB
Avalie esse Artigo
O MongoDB é conhecido por seu alto desempenho e escalabilidade, tornando-o uma escolha popular entre os bancos de dados NoSQL. No entanto, para aproveitar ao máximo seu potencial, é essencial ajustar a implantação do MongoDB. Este guia descreve várias estratégias e práticas recomendadas para melhorar o desempenho do MongoDB, abrangendo tudo, desde a identificação de gargalos até a otimização de queries e hardware.
Antes de mergulhar no ajuste de desempenho, é crucial entender sua carga de trabalho. O desempenho do MongoDB pode variar significativamente com base no fato de seu aplicativo ter muita leitura, muitas gravações ou uma mistura balanceada. Utilize ferramentas como o Atlas Profilerdo MongoDB ou o
mongostat
de código aberto para analisar suas operações de banco de dados e obter insights sobre seu volume de trabalho.A indexação eficaz é uma das maneiras mais impactantes de melhorar o desempenho da consulta no MongoDB. Veja as principais práticas:
- Crie índices relevantes: personalize os índices para corresponder aos padrões de consulta do seu aplicativo. Use o método [explain() para entender o comportamento da consulta e otimizar adequadamente.
db.collection.find({ field: value }).explain("executionStats")
Você também pode obter essas informações do MongoDB Compass com saída sofisticada, conforme mostrado abaixo.
- Evite a indexação excessiva: embora os índices melhorem a velocidade da query, eles podem impedir operações de gravação e consumir espaço em disco adicional. Revise e remova regularmente índices não utilizados ou desnecessários.
db.collection.dropIndex("indexName")
- Usar índices compostos: para consultas que envolvem vários campos, os índices compostos podem aumentar significativamente o desempenho.
db.collection.createIndex({ field1: 1, field2: -1 })
Otimizar seus padrões de consulta é crucial para reduzir o tempo de execução e o uso de recursos:
- Projeção: use a projeção para limitar os campos retornados por suas queries, minimizando a transferência de dados e a carga de processamento. Além disso, é melhor excluir ID com 0 (falso) se não for um campo referente ao aplicativo — ou seja, um campo gerado automaticamente pelo MongoDB.
db.collection.find({ field: value }, { field1: 1, field2: 1 })
- Framework deaggregation : aproveite o framework de aggregation do MongoDB para processamento de dados complexos. Certifique-se de que as agregações utilizem campos indexados sempre que possível.
db.collection.aggregate([ { $match: { field: value } }, { $group: { _id: "$field", total: { $sum: "$amount" } } } ])
- Evitar $where: o operador
$where
pode ser lento e consome muitos recursos. Use-o com moderação e somente quando necessário. Em vez disso, o uso de $expr com operadores de agregação que não usam JavaScript (ou seja, operadores não $function e não $accumulator) é mais rápido do que $where porque não executa JavaScript e é preferível, quando possível. No entanto, se você precisar criar expressões personalizadas, $function é preferível a $where.
O hardware no qual o MongoDB é executado desempenho um papel crucial em seu desempenho:
- RAM: o MongoDB depende muito da RAM para armazenar conjuntos de trabalho. Se o seu conjunto de dados exceder a RAM disponível, considere atualizar a memória.
- Armazenamento: utilize SSDs para armazenamento para melhorar a taxa de transferência de E/S e as velocidades de acesso a dados.
- Rede: verifique se a largura de banda e a latência da rede são suficientes, especialmente em implantações distribuídas.
Replicação e sharding O MongoDB oferece suporte à replicação e ao sharding para melhorar a disponibilidade e a escalabilidade:
- Replicação: isso garante redundância de dados e alta disponibilidade. Configure as configurações de read preference para rotear com eficiência as operações de leitura entre réplicas.
rs.initiate()
A seguir estão os métodos de leitura disponíveis com o MongoDB, que você pode configurar no nível do aplicativo.
- ** primário ** : Lê somente do primário
- primaryPreferred: lê do primário, se disponível, caso contrário, de um secundário
- secundário: Lê apenas de um secundário
- secondaryPreferred: lê de um secundário, se disponível, caso contrário, do primário
- mais próximo: Lê do nó mais próximo com base na latência da rede e na integridade operacional
Exemplo: definir read preferences no código do aplicativo (Node.js)
1 const MongoClient = require('mongodb').MongoClient; 2 const uri = "mongodb://host1,host2,host3/?readPreference=secondaryPreferred"; 3 MongoClient.connect(uri, function(err, client) { 4 const db = client.db('test'); 5 // Perform operations 6 });
- Fragmentação: distribui dados em vários servidores e é crucial para gerenciar grandes conjuntos de dados e operações de alto rendimento. Escolha uma chave de fragmento que distribua uniformemente os dados e a carga de consulta.
sh.enableSharding("mydatabase") sh.shardCollection("mydatabase.mycollection", { shardKey: 1 })
Escolher uma chave de shard no MongoDB pode afetar significativamente o desempenho, dependendo se seu volume de trabalho é de leitura ou gravação. Aqui estão algumas diretrizes para selecionar uma chave de shard com base em sua carga de trabalho:
Seleção de chave de shard: escolha uma chave de shard que distribua uniformemente as operações de leitura entre os shards.
Considerações: use um campo de alta cardinalidade que garanta uma distribuição uniforme de leituras. Evite chaves de fragmento que podem causar pontos de acesso onde a maioria das leituras tem como alvo um único fragmento.
Exemplo: use um ID de usuário se as queries relacionadas ao usuário forem comuns.
sh.shardCollection("mydatabase.mycollection", { userID: 1 })
Seleção de chave de shard: escolha uma chave de shard que equilibre a carga de gravação entre shards.
Considerações: Use um campo que mude com frequência e garanta uma distribuição uniforme da gravação. Evite aumentar monotonicamente as chaves (por exemplo, carimbos de data/hora), pois elas podem fazer com que um único fragmento se torne um gargalo.
Exemplo: use uma hashed shard key para distribuir as gravações uniformemente se você não conseguir obter uma chave de shard exclusiva.
sh.shardCollection("mydatabase.mycollection", { hashedField: "hashed" })
Considerações adicionais: Monitorar e ajustar: monitore continuamente o desempenho e ajuste as chaves de shard, se necessário.
Indexação: verifique se os índices estão alinhados com a chave de fragmento para obter o desempenho ideal da consulta. Ao selecionar a chave de fragmento apropriada e considerar a natureza de sua carga de trabalho, você pode otimizar sua implantação do MongoDB para operações de leitura e gravação.
O monitoramento e a manutenção regulares são vitais para o desempenho sustentável:
- Ferramentas de monitoramento: Utilize o MongoDB Atlas, mongostat e mongotop para monitorar o desempenho do banco de dados e o uso de recursos.
mongostat --host <host> mongotop --host <host>
- Manutenção de rotina: compacte regularmente coleções, repare bancos de dados e rebalanceie fragmentos para garantir o desempenho ideal.
db.repairDatabase()
A escolha da preocupação de gravação pode influenciar o desempenho e a durabilidade dos dados.
Uma write concern menor (por exemplo, w: 0) pode melhorar o desempenho reduzindo a latência da operação de escrita. No entanto, arrisca a durabilidade dos dados.
Impacto na latência
Preocupação de gravação inferior (por exemplo, w: 0):
Redução da latência:
- O cliente não espera nenhuma confirmação do servidor.
- A operação é enviada ao servidor e considerada concluída do ponto de vista do cliente.
- Não há latência de ida e volta da rede, pois não há necessidade de o servidor responder.
Compensação:
- Há um risco maior de perda de dados, pois o cliente não recebe nenhuma confirmação de sucesso na gravação.
- Ele é adequado para dados não críticos ou cenários em que é necessária uma alta taxa de transferência de gravação com latência mínima.
Preocupação de gravação maior (por exemplo, w: 1 ou w: "maioria"):
Aumento da latência
- O cliente aguarda a confirmação do servidor.
- Para w: 1, aguarda a confirmação do nó primário.
- Para w: "maioria", aguarda a confirmação da maioria dos nós do conjunto de réplicas.
- A latência de ida e volta da rede e o tempo de processamento do servidor aumentam a latência geral.
- Maior durabilidade e consistência de dados.
- Garante que a operação de gravação seja replicada e reconhecida.
db.collection.insertOne({ field: "value" }, { writeConcern: { w: 1 } })
A escolha da read preference pode influenciar o desempenho e a disponibilidade dos dados.
Desempenho: a distribuição de operações de leitura para nós secundários pode melhorar o desempenho reduzindo a carga no primary. Para distribuir com êxito as operações de leitura para nós secundários e, assim, melhorar o desempenho, é necessário definir a read preference no MongoDB. Aqui estão exemplos de como configurar read preferences:
db.getMongo().setReadPref("secondaryPreferred")
URI de conexão
mongodb://host1,host2,host3/?readPreference=secondaryPreferred
** Exemplo de código do aplicativo (NodeJS) **
1 const MongoClient = require('mongodb').MongoClient; 2 const uri = "mongodb://host1,host2,host3/?readPreference=secondaryPreferred"; 3 MongoClient.connect(uri, function(err, client) { 4 const db = client.db('test'); 5 // Perform operations 6 })
Ao definir a read preference como secondaryPreferred, você direciona as operações de leitura para nós secundários quando elas estão disponíveis, reduzindo a carga no nó primary e melhorando o desempenho geral.
Verificações para identificar os motivos comuns para problemas de desempenho:
- Execute o mongotop e o mongostat e verifique qual namespace está causando o problema.
- Nível do sistema - verifique se há replicação primária. Há algum atraso e como está a oplog window?
- Nível do aplicativo — verifique se há carregamentos em lote no nível do aplicativo.
- Qualquer queries lentas (com currentOp ())?
- Existem índices adequados?
- Cluster fragmentado — a maioria das queries usa a chave de shard?
- WT cache? Algum despejo?
- Você vê contenção de gravação?
- Abrir arquivos ( ulimit -a ) - 65000
- Verifique se o processo mongod por si só causa carga no servidor ou qualquer outro processo.
- top ou htop: Monitore o uso de CPU e memória do mongod e outros processos.
- ps e grep: execute
ps aux | grep mongod
para visualizar o usodo recurso mongod . - iostat: Use
iostat -x 1 10
para verificar as métricas de E/S do disco. - vmstat: execute
vmstat 1 10
para obter instantâneos de desempenho geral do sistema.
A contenção de escrita no MongoDB pode ser identificada pelos seguintes indicadores:
Altas porcentagens de bloqueio: Use o mongostat para monitorar as porcentagens de bloqueio. Valores altos indicam contenção. Operações de gravação lenta: verifique se há operações de gravação lentas usando db.currentOp() que podem indicar contenção. Conflitos de gravação frequentes: revise os logs de mensagens sobre conflitos ou rejeições de gravação.
Aumento da latência: observe o aumento da latência em operações ou aplicativos de escrita pesada.
Exemplo de comando para monitorar porcentagens de bloqueio:
mongostat --host <hostname>
Projetar o esquema adequadamente, como usar índices apropriados e evitar pontos de acesso com gravações distribuídas, pode ajudar a reduzir a contenção de gravação.
Obter o desempenho ideal do MongoDB envolve uma abordagem abrangente, incluindo otimização de queries, indexação adequada, recursos de hardware suficientes e monitoramento contínuo. Ao implementar as estratégias descritas neste guia, você pode melhorar significativamente a eficiência e a capacidade de resposta do MongoDB deployment, garantindo que ele atenda às solicitações de seus aplicativos.
Principais comentários nos fóruns
Srinativas_MutyalaSrinativas Mutyalaúltimo trimestre
Olá comunidade !!!
Estou buscando suas sugestões/ feedback sobre este artigo.