Melhorando a performance da sua aplicação

Melhorando a performance da sua aplicação

A performance de uma aplicação é fundamental para garantir uma boa experiência do usuário e o sucesso do produto. Em um ambiente cada vez mais competitivo, otimizar a velocidade e a eficiência do seu software pode fazer uma grande diferença. Neste artigo, vamos explorar conceitos para melhorar o desempenho da sua aplicação independente do framework ou linguagem que estiver usando.

Connection Pool:

Criar uma nova conexão com o banco de dados é uma tarefa custosa, que envolve operações de rede, autenticação, alocação de recursos etc. Isso pode se tornar um problema quando sua aplicação tem alta demanda. Podemos resolver esse problema criando um connection pool. Nele, as conexões são reutilizadas, evitando que seja necessário criar uma nova a cada requisição ao banco de dados. Com isso, você diminui o tempo de resposta e economiza recursos. É importante ressaltar que a maioria dos frameworks já vem com um pool por padrão; porém, é de suma importância que você o configure de acordo com os requisitos da sua aplicação.

ORM Queries:

No dia a dia, é comum utilizarmos algum ORM (Object-Relational Mapping), como, por exemplo, Sequelize, TypeORM, dentre outros, para realizarmos nossas operações com o banco de dados. Porém, é muito importante monitorarmos e fazermos testes de performance para detectar qualquer query que esteja demorando mais do que o esperado. Isso ocorre porque o ORM troca eficiência por conveniência; nem sempre ele gera queries eficientes, e, caso ocorra de fazer uma consulta que contenha muitos dados relacionados, ele pode gerar uma query mal otimizada, o que trará latência às suas requisições. Para isso, você pode substituir por uma query em raw, onde você mesmo a escreve, ou tentar utilizar features como lazy loading.

“Denormalize” o seu banco, remova relacionamentos desnecessários:

É comum normalizarmos dados e dividirmos em tabelas diferentes. O problema é que isso afeta muito a performance, pois o banco precisará fazer mais um join para recuperar aquele dado. Uma forma de melhorar isso é denormalizando tabelas, ou seja, removendo relacionamentos desnecessários. Um exemplo disso pode ser encontrado nesta imagem:

Nesta imagem, podemos ver que existe uma tabela chamada “Estados” que é desnecessária. Podemos reduzir a quantidade de joins na nossa query simplesmente trazendo a informação do estado para dentro do cadastro.

Crie índices estratégicos:

Índices permitem que o banco de dados encontre e recupere registros de maneira mais eficiente, especialmente em consultas que envolvem filtros ou ordenação. Eles diminuem o tempo necessário para localizar e acessar os dados, o que é crucial em sistemas com grandes volumes de dados ou alta frequência de consultas. Porém, evite criar índices demais, pois isso prejudica a escrita no disco.

Caching:

É extremamente necessário usar caching se você quiser aumentar a performance da sua aplicação. Para a leitura do banco de dados, é interessante adotar um padrão de cache-aside com Redis ou algo do tipo, no qual a aplicação primeiro procura no Redis. Caso a informação não esteja disponível (cache miss), a aplicação procura no banco de dados e escreve no Redis com um TTL (Time To Live) definido.

Fila para escritas no DB:

Caso sua aplicação tenha uma alta demanda, também é interessante adicionar um sistema de fila para a escrita no banco de dados. A aplicação envia para a fila — seja no Redis, RabbitMQ ou outro sistema de fila — e um worker recebe essa informação e grava no banco. Isso pode adicionar um pouco de atraso na escrita, mas garante que a operação ocorra em casos de pico e evita timeouts.

Full-text search:

Caso sua aplicação faça Full-text Search (como na busca de produtos em um e-commerce), é recomendado utilizar algum serviço de terceiros para ganhar performance, como o Elasticsearch. Ao mesmo tempo em que você escreve no seu banco de dados, deve escrever no Elasticsearch. Assim, quando for fazer a busca, ela será muito mais rápida.

Replicação de banco de dados:

A replicação de banco de dados é uma técnica usada para aumentar a redundância e melhorar a performance. Ela envolve a cópia de dados de um banco de dados (o master ou primary) para um ou mais bancos de dados secundários (os slaves ou réplicas). Existem alguns tipos de replicação, como Master-Slave, Master-Master, etc. Cabe a você decidir o melhor approach para o cenário da sua aplicação.

Implemente Rate-limit e Throttling na sua API:

Rate limiting serve para controlar e limitar o número de requisições em um período de tempo, prevenindo sobrecarga e impedindo que o usuário envie muitas requisições em um curto intervalo. Já o throttling ajusta a velocidade de processamento das requisições com base na carga do sistema, garantindo estabilidade e performance durante picos de tráfego.

Adicione um load balancing:

Para aumentar a performance, a disponibilidade e a escalabilidade da sua aplicação, é altamente recomendável adicionar um load balancer à sua infraestrutura. Load balancing é o processo de distribuir o tráfego de rede ou a carga de trabalho entre múltiplos servidores ou recursos para garantir que nenhum único servidor fique sobrecarregado.

Considere adicionar Cursor Pagination:

Normalmente, em nossas aplicações, utilizamos a paginação por offset, na qual enviamos um valor de offset e um limit para o backend, e ele nos retorna os dados paginados, como se estivéssemos folheando páginas de um livro. A paginação por cursor é um método que facilita a navegação por grandes volumes de dados sem comprometer a performance. Em vez de depender da página atual e do número de itens por página para acessar os dados, essa técnica utiliza um cursor, que é uma referência à posição do último item retornado na consulta anterior. Isso permite que você recupere os dados em partes menores, diminuindo a carga no banco de dados e no servidor.

Utilize um CDN no Frontend:

Utilizar uma CDN (Content Delivery Network) no frontend do seu site acelera a entrega de conteúdo ao distribuir arquivos estáticos, como imagens e scripts, por meio de uma rede global de servidores. Isso reduz a latência ao entregar o conteúdo a partir do servidor mais próximo do usuário, melhorando significativamente o tempo de carregamento das páginas. Além disso, uma CDN ajuda a garantir alta disponibilidade, pois, se algum nó apresentar problemas, o tráfego é redirecionado para outro nó.

Faça um planejamento de como escalar sua aplicação:

É importante definir como você irá escalar a sua aplicação, seja por escala horizontal ou vertical. De maneira geral, a escala vertical é mais simples e pode ser ideal para aplicações que não exigem escalabilidade massiva ou complexidade adicional. Já a escala horizontal oferece maior flexibilidade e resiliência, sendo ideal para sistemas que precisam lidar com grandes volumes de dados e tráfego, garantindo alta disponibilidade e capacidade de crescimento contínuo. Escolha o que melhor se adapta à sua aplicação.

Considerações finais:

Neste artigo, exploramos as principais estratégias para otimizar a performance da sua aplicação. Ao implementar essas técnicas de maneira adequada, você certamente notará uma melhoria significativa no desempenho da sua aplicação.