DEV Community

Matheus Henrique
Matheus Henrique

Posted on

Melhorando o desempenho de aplicações Spring Boot - Parte II

Na primeira parte deste artigo, aprendemos a como estar melhorando o desempenho das nossas aplicações, substituindo o Tomcat pelo Undertow, que é um servidor web de alta performance, além de habilitar e configurar a compressão de dados, para reduzir o tamanho das respostas HTTP que trafegam pela rede.

Agora, iremos falar sobre como melhorar o desempenho de aplicação Spring Boot na parte de persistência, mas antes precisamos entender o que é JPA, Hibernate e Hikari.

JPA

JPA ou Java Persistence API, que posteriormente foi renomeada para Jakarta Persistence, é um padrão da linguagem Java que descreve uma interface comum para frameworks de persistência de dados.

A especificação JPA define o mapeamento relacional de objetos internamente, em vez de depender das implementações de mapeamento específicas do fornecedor.

Hibernate

O Hibernate é um dos frameworks de ORM que faz a implementação concreta da especificação JPA, ou seja, se nessa especificação é descrito que é preciso de métodos para persistir, remover, atualizar e buscar dados, quem vai de fato construir esses comportamentos é o Hibernate, assim como o EclipseLink, que é outro ORM.

Hikari

Hikari é um framework de connection pooling, que é responsável pelo gerenciamento de conexões com o banco de dados, mantendo-as abertas para que possam ser reutilizadas, ou seja, é um cache de conexões para solicitações futuras, tornando o acesso ao banco de dados mais rápido e reduzindo o número de novas conexões a serem criadas.

Configurando Hikari, JPA e o Hibernate

Uma configuração que podemos estar realizando para melhorar o desempenho é a seguinte:

Usando application.yml:

spring:
  hikari:
    auto-commit: false
    connection-timeout: 250
    max-lifetime: 600000
    maximum-pool-size: 20
    minimum-idle: 10
    pool-name: master

  jpa:
    open-in-view: false
    show-sql: true
    hibernate:
      ddl-auto: none
    properties:
      hibernate.connection.provider_disables_autocommit: true
      hibernate.generate_statistics: true
Enter fullscreen mode Exit fullscreen mode

Usando application.properties:

spring.datasource.hikari.auto-commit=false
spring.datasource.hikari.connection-timeout=50
spring.datasource.hikari.max-lifetime=600000
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=10
spring.datasource.hikari.pool-name=master

spring.datasource.jpa.open-in-view=false
spring.datasource.jpa.show-sql=true

spring.datasource.jpa.hibernate.ddl-auto=none
spring.jpa.properties.hibernate.generate_statistics=true
spring.jpa.properties.hibernate.connection.provider_disables_autocommit=true
Enter fullscreen mode Exit fullscreen mode

Agora vamos a um breve um resumo das opções:

Hikari

  • spring.datasource.hikari.auto-commit: Se for false, toda conexão que for retornada pelo connection pool virá com auto-commit desabilitado.

  • spring.datasource.hikari.connection-timeout: Tempo, em milissegundos, que o cliente aguardará por uma conexão do pool. É preferível configurar um tempo curto para falhar rapidamente e retornar uma mensagem de erro, em vez de manter o cliente esperando indefinidamente.

  • spring.datasource.hikari.max-lifetime: Tempo máximo que uma conexão pode permanecer ativa. Configurar esse parâmetro é crucial para evitar falhas por conexões problemáticas e aumentar a segurança, já que conexões ativas por muito tempo são mais vulneráveis a ataques.

  • spring.datasource.hikari.maximum-pool-size: Tamanho máximo do pool, incluindo conexões ociosas e em uso, determinando o número máximo de conexões ativas com o banco de dados. Se o pool atingir esse limite e não houver conexões ociosas, chamadas para getConnection() serão bloqueadas por até connectionTimeout milissegundos antes de falharem.

    • Encontrar um valor adequado é importante, pois muitas pessoas acham que vão ter um ótimo desempenho definindo 50, 70 ou até 100. O ideal é ter 20 no máximo, que é a quantidade de threads em paralelo utilizando as conexões.
    • Quanto maior o valor, mais difícil vai ser para banco de dados gerenciar essas conexões e muito provavelmente não conseguiremos ter throughput suficiente para utilizar todas essas conexões.
    • É importante entender que do ponto de vista do RDBMS (Relational Database Management System) é difícil manter uma conexão aberta com ele mesmo, imagine n quantidade de conexões.
  • spring.datasource.hikari.minimum-idle: Número mínimo de conexões que o pool mantém quando a demanda é baixa. O pool pode reduzir as conexões até 10 e recriá-las conforme necessário. No entanto, para desempenho máximo e melhor resposta a picos de demanda, é recomendado não definir esse valor, permitindo que o Hikari funcione como um pool de tamanho fixo. Padrão: igual ao spring.datasource.hikari.maximum-pool-size.

  • spring.datasource.hikari.pool-name: Nome definido pelo usuário para o pool de conexão e aparece principalmente em consoles de gerenciamento de registro e JMX para identificar pools e suas configurações.

JPA

  • spring.datasource.jpa.open-in-view: Quando o OSIV (Open Session In View) está ativado, uma sessão é mantida durante toda a requisição, mesmo sem a anotação @Transactional. Isso pode causar problemas de desempenho, como a falta de respostas da aplicação, pois a sessão mantém a conexão com o banco de dados até o fim da requisição.

  • spring.datasource.jpa.show-sql: Exibe o logging do SQL que está sendo executado em nossa aplicação. Geralmente deixamos ativado em desenvolvimento, mas desativado em produção.

  • spring.datasource.jpa.hibernate.ddl-auto: Configura o comportamento do Hibernate em relação ao schema do banco de dados. Ela pode ter os seguintes valores:

    • none: Não faz nada. Gerenciamos manualmente o schema do banco.
    • validate: Valida o schema do banco de dados, mas não faz alterações. Isso é útil para garantir que o schema atual esteja de acordo com as entidades que mapeamos.
    • update: Atualiza o schema do banco de dados para refletir mudanças nas entidades.
    • create: Cria o schema do banco de dados. Se o schema já existir, ele vai remover e criar novamente.
    • create-drop: Cria o schema do banco de dados e, ao finalizar a aplicação, remove o schema. Útil para testes, onde desejamos um banco de dados limpo a cada teste.
  • spring.jpa.properties.hibernate.generate_statistics: Serve para coletar informações detalhadas sobre o Hibernate, como tempos de execução de consultas, número de consultas executadas, e outras métricas.

  • spring.jpa.properties.hibernate.connection.provider_disables_autocommit: Informa ao Hibernate que desabilitamos o auto-commit dos providers (PostgreSQL, MySQL, etc). Isso impacta no desempenho, porque o Hibernate precisará obter uma conexão do pool para saber se o auto-commit está ou não está habilitado, para toda transação que ele fizer.

Com isso, fechamos a segunda parte do artigo. Nem todas as configurações presentes foram sobre desempenho, mas as que realmente impactam são as configurações do Hikari como auto-commit e pool size, as do JPA e Hibernate como OSIV (Open Session In View) e informar que desabilitamos o auto-commit dos providers.

Na próxima parte vamos falar sobre exceções e como elas podem ser configuradas, para poupar recursos da JVM (Java Virtual Machine).

Referências:

Top comments (0)