Dados da primavera desbloqueados: técnicas de otimização de desempenho com o MongoDB
Ricardo Mello5 min read • Published Dec 04, 2024 • Updated Dec 04, 2024
APLICATIVO COMPLETO
Avalie esse Artigo
Sim, já vi! Assim como no segundo artigo, você está aqui porque usou o tópico inicial, certo? Para recapitular: no primeiro artigo, abordamos como começar a usar o MongoDB e o Spring Data, explorando a diferença entre MongoTemplate e MongoRepository e quando usar um ou outro. Na segunda parte, demos um passo adiante ao explorar queries avançadas e aprender conceitos poderosos que a Spring oferece. Por fim (mas não menos importante), vamos ver como otimizar nosso aplicação por meio de estratégias como preferências de leitura e índices.
- Comece a usar o MongoDB Atlas gratuitamente! Se você ainda não tiver uma conta, o MongoDB oferece um cluster Atlas gratuito para sempre.
- IDE de sua escolha
Melhorar o desempenho no MongoDB é crucial para garantir o acesso rápido e eficiente aos dados e melhorar a experiência do usuário. Ao otimizar estratégias, podemos reduzir a latência, aumentar a taxa de transferência e escalar melhor os aplicativos à medida que eles crescem.
Você provavelmente já deve ter escutado incontáveis vezes que os índices são essenciais para alcançar alta performance em suas queries, não é mesmo? No entanto, é importante lembrar que os índices vêm com certas regras, e mesmo índices não utilizados podem impacto negativamente seu banco de dados de dados. Em collections com uma alta frequência de gravações em comparação com as leituras, a manutenção de índices pode ser um desafio, porque cada gravação exige atualizá-las.
Você pode estar se perguntado:Okay, but how do I know when to create an index or not?“” Bem, geralmente criamos índices quando nosso aplicação executa queries com frequência no mesmo campo. Em nosso aplicação, vamos revisar a
TransactionRepository
classe e dar uma olhada no métodofindByTransactionType(tipostring de string):1 2 public interface TransactionRepository extends MongoRepository<Transaction, String> { 3 4 List<Transaction> findByTransactionType(String type); 5 // Other methods .. 6 }
Este método é responsável por recuperar transações por tipo. Para entender o custo dessa query, podemos executar o comando explain():
1 db.transactions.find({"transactionType": "Debit"}).explain()
Ou, no nosso caso, executaremos uma query diretamente usando o Spring. Em CustomerService, crie o seguinte método:
1 public String explain() { 2 3 MongoCollection<Document> collection = mongoOperations.getCollection("transactions"); 4 5 Document query = new Document("transactionType", "Debit"); 6 Document explanation = collection.find(query).explain(); 7 8 logger.info(explanation.toJson()); 9 return explanation.toJson(); 10 }
O
explain()
comando fornece o plano de execução da query, detalhando como o MongoDB processa a query. No nosso caso, como não temos um índice, ele retorna um COLLSCAN (verificação de collection).Para otimizar isso, vamos criar um índice para essa query. Tradicionalmente, criamos o índice da seguinte maneira:
1 db.transactions.createIndex({"transactionType": 1})
No entanto, como estamos explorando as opções do Spring, criaremos o índice de uma maneira diferente. Para fazer isso, basta navegar até a
Transaction
classe (que representa nossa coleção) e anotar o campo desejado com a @Indexed
anotação:1 import lombok.Data; 2 import org.springframework.data.annotation.Id; 3 import org.springframework.data.mongodb.core.index.Indexed; 4 import org.springframework.data.mongodb.core.mapping.Document; 5 6 7 8 public class Transaction { 9 10 11 private String transactionType; 12 13 // Other fields 14 }
Para que isso funcione, precisamos habilitar a criação automática de índice nas propriedades do aplicação adicionando a seguinte configuração:
1 spring: 2 data: 3 mongodb: 4 auto-index-creation: true
Aviso: Embora essa seja uma maneira conveniente de criar índices durante o desenvolvimento, é importante ter cuidado em ambientes de produção. A criação de índices automáticos pode fazer com que a inicialização do aplicação seja pausada enquanto o índice está sendo criado, o que pode causar atrasos ou problemas de disponibilidade se não for tratado com cuidado. Para cenários de produção, considere a criação de índices explicitamente durante um processo controlado fora do ciclo de vida do aplicação .
Continuando com nossa análise de índices, agora temos índices compostos. Como o nome sugere, esses índices combinam mais de um campo para fins de query. Vamos presumir que temos uma query que pesquisa tanto o tipo de transação quanto a moeda:
1 2 public interface TransactionRepository extends MongoRepository<Transaction, String> { 3 4 List<Transaction> findByTransactionTypeAndCurrency(String type, String currency); 5 6 // Other methods 7 }
Para otimizar essa query, poderíamos criar o índice composto da seguinte maneira:
1 2 3 public class Transaction { 4 // fields 5 }
A
@Indexed
interface inclui um unique()
método, que é definido como false
por padrão. Isso significa que qualquer campo anotado com @Indexed
não imporá exclusividade por padrão. No entanto, podemos especificar que queremos que o campo seja exclusivo.Imagine que, em nossa
Transaction
classe , tenhamos um campo chamado authCode, responsável por garantir que cada transação seja única. Podemos anotar a classe da seguinte maneira:1 public class Transaction { 2 3 private String authCode; 4 }
Essa anotação garante que a
transactions
coleção não terá nenhum valor deauthCode duplicado. Se um código duplicado for fornecido, o MongoDB lançará a seguinte exceção:1 com.mongodb.MongoWriteException - E11000 duplicate key error collection
Suponha que temos uma função em nosso aplicação que executa uma query para localizar todas as transações com mais de 40 dias com status de "COMPLETED " ou "SUCCESS " e executa um comando de exclusão. Neste caso, teriamos duas etapas:
- Filtre todas as transações neste estado.
- Execute uma operação de exclusão nesses itens.
Isso pode ser caro para o seu aplicação. Uma alternativa é usar o índice TTL, que expira automaticamente os documentos após um determinado período de tempo. Podemos dizer ao nosso aplicação:
"Ei, gostaria que você exclua todos os registros que foram criados há mais de 40 dias e estão no status "SUCCESS " ou "COMPLETED ""
1 public class Transaction { 2 3 4 5 6 7 8 9 10 11 12 13 private LocalDateTime createdAt; 14 15 }
Dessa forma, o aplicação expirará (excluirá) as transações que atenderem a esse filtro.
O uso de
ReadPreference
pode melhorar a latência e o desempenho ao direcionar as leituras para réplicas secundárias mais próximas, reduzir a carga no nó primário e otimizar a distribuição de dados em sistemas distribuídos geograficamente.Conforme mostrado na imagem acima, por padrão, todas as operações de gravação ocorrem no nó primário, enquanto as operações de leitura podem ser direcionadas para nós secundários. Existem vários modos de preferência de leitura , como:
Vamos Go voltar à nossa
TransactionRepository
classe e marcar o métodofindByTransactionType para executar a pesquisa usando o modosecondaryPreferred :1 2 public interface TransactionRepository extends MongoRepository<Transaction, String> { 3 4 List<Transaction> findByTransactionType(String type); 5 }
Outra alternativa é aplicar o modo a todo o aplicação por meio das configurações de conexão. No
MongoConfig
, você pode configurar o modo de preferência de leitura globalmente. Veja como você pode fazer isso:1 2 public class MongoConfig { 3 4 public MongoClient mongoClient() { 5 MongoClientSettings settings = MongoClientSettings.builder() 6 .applyConnectionString(new ConnectionString(connectionString)) 7 .readPreference(ReadPreference.nearest()) 8 .build(); 9 return MongoClients.create(settings); 10 }
Nesta terceira e última parte da série Spring Data Unlocked , aprenderam como criar índices diretamente pelo aplicação, ajustar as preferências de leitura com o ReadPreference e otimizar o desempenho de nossas queries. O código completo do aplicação está disponível no repositório mongodb-developer.
Para obter mais informações sobre como melhorar o desempenho da query com índices, acesse a documentação sobre índices.
Principais comentários nos fóruns
Ainda não há comentários sobre este artigo.