Quando em produção, um aplicativo deve fornecer uma resposta oportuna ao usuário com o objetivo de melhorar a interação do usuário com seu aplicativo. Às vezes, no entanto, as consultas de banco de dados podem começar a ficar atrasadas, levando uma latência mais longa para uma resposta chegar ao usuário ou, em vez disso, a operação de taxa de transferência foi encerrada devido à ultrapassagem do tempo limite médio definido.
Neste blog vamos aprender como você pode identificar esses problemas no MongoDB, formas de corrigi-los sempre que eles surgirem e quais são as possíveis estratégias a serem adotadas para que isso não aconteça novamente.
Com mais frequência, o que leva a respostas de consulta lentas é a capacidade degradada da CPU que não consegue suportar o conjunto de trabalho subjacente. O conjunto de trabalho neste caso é a quantidade de dados e índices que serão submetidos a uma instância de taxa de transferência, portanto, ativa naquele momento. Isso é especialmente considerado no planejamento de capacidade quando se espera que a quantidade de dados envolvidos aumente ao longo do tempo e o número de usuários envolvidos com sua plataforma.
Identificando um problema de consulta lenta
Existem duas maneiras de identificar consultas lentas no MongoDB.
- Usando o criador de perfil
- Usando o auxiliar db.currentOp()
Usando o criador de perfil do MongoDB
O criador de perfil de banco de dados no MongoDB é um mecanismo para coletar informações detalhadas sobre comandos de banco de dados executados em uma instância mongod em execução, ou seja:operações de taxa de transferência (criar, ler, atualizar e excluir) e os comandos de configuração e administração.
O criador de perfil utiliza uma coleção limitada chamada system.profile onde grava todos os dados. Isso significa que, quando a coleção está cheia em termos de tamanho, os documentos mais antigos são excluídos para dar espaço a novos dados.
O Profiler está desativado por padrão, mas dependendo do nível de criação de perfil, pode-se habilitá-lo em um banco de dados ou por instância. Os níveis de perfil possíveis são:
- 0 - o criador de perfil está desativado, portanto, não coleta nenhum dado.
- 1 - o criador de perfil coleta dados para operações que demoram mais do que o valor de slowms
- 2- o criador de perfil coleta dados de todas as operações.
No entanto, habilitar a criação de perfil gera um impacto no desempenho do banco de dados e do uso do disco, especialmente quando o nível de criação de perfil é definido como 2 . Deve-se considerar quaisquer implicações de desempenho antes de habilitar e configurar o criador de perfil em uma implantação de produção.
Para definir o perfil, usamos o auxiliar db.setProfilingLevel() como:
db.setProfilingLevel(2)
Um documento de amostra que será armazenado na coleção system.profile será:
{ "was" : 0, "slowms" : 100, "sampleRate" : 1.0, "ok" : 1 }
O par de valores-chave “ok”:1 indica que a operação foi bem-sucedida, enquanto slowms é o tempo limite em milissegundos que uma operação deve levar e, por padrão, é 100ms.
Para alterar este valor
db.setProfilingLevel(1, { slowms: 50 })
Para consultar dados na coleção system.profile, execute:
db.system.profile.find().pretty()
Usando db.currentOp()helper
Esta função lista as consultas em execução atuais com informações muito detalhadas, como há quanto tempo elas estão em execução. Em um shell mongo em execução, você executa o comentário, por exemplo:
db.currentOp({“secs_running”:{$gte:5}})
Onde secs_running é a estratégia de filtragem para que apenas as operações que levaram mais de 5 segundos para serem executadas sejam retornadas, reduzindo a saída. Isso geralmente é usado quando a integridade da CPU pode ser avaliada em 100% devido ao impacto adverso no desempenho que pode implicar no banco de dados. Portanto, alterando os valores, você aprenderá quais consultas estão demorando para serem executadas.
Os documentos devolvidos têm como chaves de interesse:
- consulta :o que a consulta envolve
- ativo : se a consulta ainda estiver em andamento.
- ns :nome da coleção em relação à qual a consulta deve ser executada
- secs_running : duração que a consulta levou até agora em segundos
Ao destacar quais consultas estão demorando, você identificou o que está sobrecarregando a CPU.
Interpretando resultados e corrigindo os problemas
Como descrevemos acima, a latência da consulta depende muito da quantidade de dados envolvidos, o que, de outra forma, levará a planos de execução ineficientes. Ou seja, por exemplo, se você não usa índices em sua coleção e deseja atualizar determinados registros, a operação precisa passar por todos os documentos em vez de filtrar apenas aqueles que correspondem à especificação da consulta. Logicamente, isso levará mais tempo, levando a uma consulta lenta. Você pode examinar um plano de execução ineficiente executando: explique('executionStats') que fornece estatísticas sobre o desempenho da consulta. A partir deste ponto, você pode aprender como a consulta está utilizando o índice, além de fornecer uma pista se o índice é ideal.
Se o auxiliar de explicação retornar
{
"queryPlanner" : {
"plannerVersion" : 1,
...
"winningPlan" : {
"stage" : "COLLSCAN",
...
}
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 3,
"executionTimeMillis" : 0,
"totalKeysExamined" : 0,
"totalDocsExamined" : 10,
"executionStages" : {
"stage" : "COLLSCAN",
...
},
...
},
...
}
queryPlanner.winningPlan.stage:O valor da chave COLLSCAN indica que o mongod teve que escanear todo o documento de coleção para identificar os resultados, portanto, torna-se uma operação cara, levando a consultas lentas.
executionStats.totalKeysExamined:0 significa que a coleção não está utilizando a estratégia de indexação
Para uma determinada consulta, o número de documentos envolvidos deve ser próximo de zero. Se o número de documentos for muito grande, existem duas possibilidades:
- Não usar indexação com a coleção
- Usando um índice que não é o ideal.
Para criar um índice para uma coleção, execute o comando:
db.collection.createIndex( { quantity: 1 } )
Onde quantidade é um campo de exemplo que você selecionou para ser ideal para a estratégia de indexação.
Se você quiser saber mais sobre indexação e qual estratégia de indexação usar, consulte este blog
Conclusão
A degradação do desempenho do banco de dados pode ser facilmente retratada com consultas lentas, que é a menor expectativa que desejamos que os usuários da plataforma encontrem. Pode-se identificar consultas lentas no MongoDB habilitando o criador de perfil e configurando-o para algumas especificações ou executando db.currentOp() em uma instância mongod em execução.
Observando os parâmetros de tempo no resultado retornado, podemos identificar quais consultas estão atrasadas. Depois de identificar essas consultas, usamos o auxiliar de explicação nessas consultas para obter mais detalhes, por exemplo, se a consulta estiver usando qualquer índice.
Sem indexação, as operações se tornam caras, pois muitos documentos precisam ser digitalizados antes de aplicar as alterações. Com esse revés, a CPU ficará sobrecarregada, resultando em consultas lentas e picos de CPU crescentes.
O principal erro que leva a consultas lentas é o planejamento de execução ineficiente, que pode ser facilmente resolvido usando um índice com a coleção envolvida.