Arquitetura SINFO 1.1
André Rabelo
Raphael Medeiros
Agenda
● Problemas
● O que foi feito?
● Comportamento da solução aplicada
● Impactos
● Mudanças necessárias por parte dos desenvolvedores
● Status atual
● Dúvidas?
Problemas
● Pool de conexões
○ Estouro do pool
■ Muitas conexões sendo requisitadas ao mesmo tempo, onde, toda a quantidade disponível no
pool é utilizada
○ Lentidão
■ Quando o pool esta com todas as conexões disponíveis ocupadas, as novas requisições irão
ficar a espera de que alguma conexão seja liberada
○ Travamento dos sistemas
■ O pool não possui mais conexões disponíveis, o sistema permanece tentando obter conexões,
já com uma grande quantidade de requisições em espera por conexões, o sistema começa a
falhar, não retornando resposta aos usuários e por sua vez travando o servidor de aplicação
O que foi feito?
● Mais de 5 abordagens diferentes
○ Tentativa (testes de carga) e Erro (travamento dos sistemas, não devolução do recurso)
● Criação de um Holder (DatabaseResourcesHolder)
○ Controlar conexões
○ Controlar sessões do hibernate
○ Fechamento dos recursos (conexões e sessões do hibernate)
■ ViewFilter
■ MobileFilter
■ TarefaSchedule
● Connection Proxy para não permitir o fechamento das conexões fora do Holder
● A solução é perfeita?
○ Relatórios do Jasper/iReport abrindo conexões através de métodos Helper
Comportamento da solução aplicada
● Pool de 10 conexões no máximo
○ SIPAC
○ Comum
○ LogDB
● 15 threads sendo executadas
○ 4 usuários
● 20 iterações
○ 3 URL’s visitadas
■ /login/
■ /login.do
■ /telaInicial.do
Comportamento da solução aplicada
Comportamento da solução aplicada
Comportamento da solução aplicada
Comportamento da solução aplicada
● Houve estouro do Pool?
○ Sim, o teste aplicado foi para este fim, fazer o pool trabalhar no limite, assim, sem possibilidade de
liberar conexões sempre que requisitado
● Houve lentidão?
○ Sim, no gráfico anterior reparamos que o pico máximo foi de 180.000 milissegundos (3 minutos),
mas, o sistema não deixou de responder e devolver recursos ao pool
● Houve travamento do sistema?
○ Não, em nenhum momento o sistema deixou de responder, mesmo com todos os recursos do pool
alocados, o sistema não chegou a travar e continuou respondendo e devolvendo os recursos não
mais utilizados ao pool
Comportamento da solução aplicada
● Então quais os benefícios?
○ Não houve travamento nos testes aplicados
○ Reaproveitamento das conexões com banco de dados
○ Reaproveitamento das sessões do Hibernate
○ “Garantimos” a devolução da conexão ao Pool de conexões
● Como podemos melhorar?
○ Otimizações de consultas
○ Uso correto de mapeamentos
○ Boas práticas no geral
Impactos
● Objetivos
○ Controle de abertura de conexões e sessões do hibernate
○ Melhoria no desempenho dos sistemas
○ “Garantia” de devolução do recurso (conexão) ao pool
● Consequências
○ Transação, Conexão e Sessão do Hibernate
○ Método ‘dao.refresh’ e ‘JdbcTemplate’
○ Mapeamentos SET no hibernate
○ Abertura de conexões em relatórios através de métodos *Helper
○ Métodos *NoFlush
Mudanças necessárias por parte dos desenvolvedores
● Entendimento melhor de cada escopo envolvido na camada de persistência
● Uso correto de mapeamentos do hibernate (Set/List)
● Uso adequado do método ‘dao.refresh’
○ Dentro de uma sessão do hibernate
○ Informação alterada com uso do “createSQLQuery”
● Identificar e corrigir relatórios que abrem conexões por métodos *Helper
○ Buscar métodos (get na maioria das vezes) nas coleções que são passadas aos relatórios que fazem
chamadas a métodos *Helper os quais abrem conexões com o banco de dados e executam consultas
● Utilização correta de métodos *NoFlush
○ Usar métodos ‘executeAndFlushClosingResources’
Entendimento melhor de cada escopo envolvido na
camada de persistência
Uso adequado do método ‘dao.refresh’ e ‘JdbcTemplate’
● Há várias situações nos sistemas em que uma entidade possui informações
atualizadas via os métodos ‘update,’ ‘updateField’ e ‘updateFields’, os quais,
executam um procedimento SQL nativo para atualizar estas informações
diretamente no banco de dados.
Uso adequado do método ‘dao.refresh’ e ‘JdbcTemplate’
● Muitas das vezes o desenvolvedor acaba de atualizar estas informações e em
seguida as consulta usando o 'findByPrimaryKey', prática a qual, com as novas
modificações na arquitetura, devem gerar erros pois estas informações não serão
realmente consultadas ao banco de dados e sim a sessão do hibernate.
Uso adequado do método ‘dao.refresh’ e ‘JdbcTemplate’
● Então para corrigir estes casos, indica-se o uso do método 'refresh', o qual faz uma
atualização dos dados em sessão no hibernate em relação ao banco de dados,
assim trazendo a informação mais atual para a sessão.
Uso adequado do método ‘dao.refresh’ e ‘JdbcTemplate’
● Indica-se o uso do método 'findByPrimaryKey', quando for utilizado o
JdbcTemplate para sincronização dos dados em sessão no hibernate em relação ao
banco de dados, assim trazendo a informação mais atual para a sessão.
Uso adequado do método ‘dao.refresh’ e ‘JdbcTemplate’
● Isto é uma prática para resolver os casos apenas trocando o método, mas uma
melhor abordagem do código poderia resolver a situação e tornar o fluxo mais
eficiente.
● Qual o objetivo de consultar novamente no banco de dados uma informação que
conhecemos, esta a qual, acabamos de atualizar?
Uso correto de mapeamentos do hibernate (Set/List)
Uso correto de mapeamentos do hibernate (Set/List)
Uso correto de mapeamentos do hibernate (Set/List)
Uso correto de mapeamentos do hibernate (Set/List)
● Ao executar operações dentro de um processador(contexto transacional) o
hibernate força uma sincronização das entidades na Session, causando o
ClassCastException.
Uso correto de mapeamentos do hibernate (Set/List)
Uso correto de mapeamentos do hibernate (Set/List)
Uso correto de mapeamentos do hibernate (Set/List)
● Uso do Set (Interface) e suas Implementações
○ O Set quando instanciado como TreeSet não permite outra instanciação, apenas a primeira deve ser
mantida;
○ Nos casos em que as coleções devem ser limpas para receber novos valores então o programador
deve usar: set.clear(); set.addAll(new TreeSet<?>(Collection));
● Mapeamentos no Hibernate
○ Mapeamentos que usam <set> devem possuir seus atributos definidos como Set, Collection não
deve ser utilizado pois possibilita que o programador utilize a instancia de um ArrayList quando o
Hibernate espera que seja um Set;
Identificar e corrigir relatórios que abrem conexões por
métodos *Helper
● Existem situações onde coleções que possuem métodos de acesso a atributos
fazem chamadas a classes ‘Helpers’, onde muitas delas, fazem chamadas a classes
de acesso a dados ‘DAOs’, chamadas que na maioria das vezes abrem conexões
com o banco de dados para que a informação necessária seja retornada.
Identificar e corrigir relatórios que abrem conexões por
métodos *Helper
Identificar e corrigir relatórios que abrem conexões por
métodos *Helper
Identificar e corrigir relatórios que abrem conexões por
métodos *Helper
● Invocado no relatório HistoricoComponentesMatriculadosGraduacao.jasper.
Identificar e corrigir relatórios que abrem conexões por
métodos *Helper
● No caso acima, o relatório no Jasper receberia uma coleção de históricos, onde
estes, por sua vez, são iterados, e para cada histórico, sua coleção de
“matriculasDiscente” também é iterada, quando o valor de
“getComponenteHATotal()” for recuperado, este irá chamar um Helper, o qual
chamará uma DAO, que abrirá uma conexão com o banco de dados. Neste caso,
com as alterações feitas na arquitetura, esta conexão será aberta em uma thread a
qual não temos o controle, impossibilitando o fechamento desta conexão, assim,
possibilitando problemas com o pool de conexões.
Identificar e corrigir relatórios que abrem conexões por
métodos *Helper
● Para que este problema seja resolvido, é necessário que TODOS os dados os quais
o relatório necessite, sejam consultados antes do processamento do relatório, e
assim, a coleção de históricos enviada ao relatório já vá com todos os seus dados
populados. Estes casos exigem que, uma refatoração seja feita na consulta onde os
dados são populados, antes do processamento do relatório pelo Jasper.
Utilização correta de métodos *NoFlush
● Processamento de inserções e atualizações de N registros por vez (em “lote”)
● Otimização: commit feito no final do processamento com o método
GenericDAOImpl.close().
● Usar métodos ‘AbstractController.executeAndFlushClosingResources(...)’
Utilização correta de métodos *NoFlush
Utilização correta de métodos *NoFlush
Utilização correta de métodos *NoFlush
Utilização correta de métodos *NoFlush
Status atual
● Enviado ao TRUNK do SVN para avaliação dos desenvolvedores
● Recebendo feedbacks sobre problemas identificados
● Será enviada para produção com o SIGRH ou SIPAC
Dúvidas?
● https://goo.gl/WTZGAM (Wiki SINFO - Soluções em Metodologias e Arquitetura Tecnológica)
● Raphael Medeiros
○ Skype: raphael.j.medeiros
● André Rabelo
○ Skype: andre.rabelo.pereira
?

Arquitetura SINFO 1.1

  • 1.
    Arquitetura SINFO 1.1 AndréRabelo Raphael Medeiros
  • 2.
    Agenda ● Problemas ● Oque foi feito? ● Comportamento da solução aplicada ● Impactos ● Mudanças necessárias por parte dos desenvolvedores ● Status atual ● Dúvidas?
  • 3.
    Problemas ● Pool deconexões ○ Estouro do pool ■ Muitas conexões sendo requisitadas ao mesmo tempo, onde, toda a quantidade disponível no pool é utilizada ○ Lentidão ■ Quando o pool esta com todas as conexões disponíveis ocupadas, as novas requisições irão ficar a espera de que alguma conexão seja liberada ○ Travamento dos sistemas ■ O pool não possui mais conexões disponíveis, o sistema permanece tentando obter conexões, já com uma grande quantidade de requisições em espera por conexões, o sistema começa a falhar, não retornando resposta aos usuários e por sua vez travando o servidor de aplicação
  • 4.
    O que foifeito? ● Mais de 5 abordagens diferentes ○ Tentativa (testes de carga) e Erro (travamento dos sistemas, não devolução do recurso) ● Criação de um Holder (DatabaseResourcesHolder) ○ Controlar conexões ○ Controlar sessões do hibernate ○ Fechamento dos recursos (conexões e sessões do hibernate) ■ ViewFilter ■ MobileFilter ■ TarefaSchedule ● Connection Proxy para não permitir o fechamento das conexões fora do Holder ● A solução é perfeita? ○ Relatórios do Jasper/iReport abrindo conexões através de métodos Helper
  • 5.
    Comportamento da soluçãoaplicada ● Pool de 10 conexões no máximo ○ SIPAC ○ Comum ○ LogDB ● 15 threads sendo executadas ○ 4 usuários ● 20 iterações ○ 3 URL’s visitadas ■ /login/ ■ /login.do ■ /telaInicial.do
  • 6.
  • 7.
  • 8.
  • 9.
    Comportamento da soluçãoaplicada ● Houve estouro do Pool? ○ Sim, o teste aplicado foi para este fim, fazer o pool trabalhar no limite, assim, sem possibilidade de liberar conexões sempre que requisitado ● Houve lentidão? ○ Sim, no gráfico anterior reparamos que o pico máximo foi de 180.000 milissegundos (3 minutos), mas, o sistema não deixou de responder e devolver recursos ao pool ● Houve travamento do sistema? ○ Não, em nenhum momento o sistema deixou de responder, mesmo com todos os recursos do pool alocados, o sistema não chegou a travar e continuou respondendo e devolvendo os recursos não mais utilizados ao pool
  • 10.
    Comportamento da soluçãoaplicada ● Então quais os benefícios? ○ Não houve travamento nos testes aplicados ○ Reaproveitamento das conexões com banco de dados ○ Reaproveitamento das sessões do Hibernate ○ “Garantimos” a devolução da conexão ao Pool de conexões ● Como podemos melhorar? ○ Otimizações de consultas ○ Uso correto de mapeamentos ○ Boas práticas no geral
  • 11.
    Impactos ● Objetivos ○ Controlede abertura de conexões e sessões do hibernate ○ Melhoria no desempenho dos sistemas ○ “Garantia” de devolução do recurso (conexão) ao pool ● Consequências ○ Transação, Conexão e Sessão do Hibernate ○ Método ‘dao.refresh’ e ‘JdbcTemplate’ ○ Mapeamentos SET no hibernate ○ Abertura de conexões em relatórios através de métodos *Helper ○ Métodos *NoFlush
  • 12.
    Mudanças necessárias porparte dos desenvolvedores ● Entendimento melhor de cada escopo envolvido na camada de persistência ● Uso correto de mapeamentos do hibernate (Set/List) ● Uso adequado do método ‘dao.refresh’ ○ Dentro de uma sessão do hibernate ○ Informação alterada com uso do “createSQLQuery” ● Identificar e corrigir relatórios que abrem conexões por métodos *Helper ○ Buscar métodos (get na maioria das vezes) nas coleções que são passadas aos relatórios que fazem chamadas a métodos *Helper os quais abrem conexões com o banco de dados e executam consultas ● Utilização correta de métodos *NoFlush ○ Usar métodos ‘executeAndFlushClosingResources’
  • 13.
    Entendimento melhor decada escopo envolvido na camada de persistência
  • 14.
    Uso adequado dométodo ‘dao.refresh’ e ‘JdbcTemplate’ ● Há várias situações nos sistemas em que uma entidade possui informações atualizadas via os métodos ‘update,’ ‘updateField’ e ‘updateFields’, os quais, executam um procedimento SQL nativo para atualizar estas informações diretamente no banco de dados.
  • 15.
    Uso adequado dométodo ‘dao.refresh’ e ‘JdbcTemplate’ ● Muitas das vezes o desenvolvedor acaba de atualizar estas informações e em seguida as consulta usando o 'findByPrimaryKey', prática a qual, com as novas modificações na arquitetura, devem gerar erros pois estas informações não serão realmente consultadas ao banco de dados e sim a sessão do hibernate.
  • 16.
    Uso adequado dométodo ‘dao.refresh’ e ‘JdbcTemplate’ ● Então para corrigir estes casos, indica-se o uso do método 'refresh', o qual faz uma atualização dos dados em sessão no hibernate em relação ao banco de dados, assim trazendo a informação mais atual para a sessão.
  • 17.
    Uso adequado dométodo ‘dao.refresh’ e ‘JdbcTemplate’ ● Indica-se o uso do método 'findByPrimaryKey', quando for utilizado o JdbcTemplate para sincronização dos dados em sessão no hibernate em relação ao banco de dados, assim trazendo a informação mais atual para a sessão.
  • 18.
    Uso adequado dométodo ‘dao.refresh’ e ‘JdbcTemplate’ ● Isto é uma prática para resolver os casos apenas trocando o método, mas uma melhor abordagem do código poderia resolver a situação e tornar o fluxo mais eficiente. ● Qual o objetivo de consultar novamente no banco de dados uma informação que conhecemos, esta a qual, acabamos de atualizar?
  • 19.
    Uso correto demapeamentos do hibernate (Set/List)
  • 20.
    Uso correto demapeamentos do hibernate (Set/List)
  • 21.
    Uso correto demapeamentos do hibernate (Set/List)
  • 22.
    Uso correto demapeamentos do hibernate (Set/List) ● Ao executar operações dentro de um processador(contexto transacional) o hibernate força uma sincronização das entidades na Session, causando o ClassCastException.
  • 23.
    Uso correto demapeamentos do hibernate (Set/List)
  • 24.
    Uso correto demapeamentos do hibernate (Set/List)
  • 25.
    Uso correto demapeamentos do hibernate (Set/List) ● Uso do Set (Interface) e suas Implementações ○ O Set quando instanciado como TreeSet não permite outra instanciação, apenas a primeira deve ser mantida; ○ Nos casos em que as coleções devem ser limpas para receber novos valores então o programador deve usar: set.clear(); set.addAll(new TreeSet<?>(Collection)); ● Mapeamentos no Hibernate ○ Mapeamentos que usam <set> devem possuir seus atributos definidos como Set, Collection não deve ser utilizado pois possibilita que o programador utilize a instancia de um ArrayList quando o Hibernate espera que seja um Set;
  • 26.
    Identificar e corrigirrelatórios que abrem conexões por métodos *Helper ● Existem situações onde coleções que possuem métodos de acesso a atributos fazem chamadas a classes ‘Helpers’, onde muitas delas, fazem chamadas a classes de acesso a dados ‘DAOs’, chamadas que na maioria das vezes abrem conexões com o banco de dados para que a informação necessária seja retornada.
  • 27.
    Identificar e corrigirrelatórios que abrem conexões por métodos *Helper
  • 28.
    Identificar e corrigirrelatórios que abrem conexões por métodos *Helper
  • 29.
    Identificar e corrigirrelatórios que abrem conexões por métodos *Helper ● Invocado no relatório HistoricoComponentesMatriculadosGraduacao.jasper.
  • 30.
    Identificar e corrigirrelatórios que abrem conexões por métodos *Helper ● No caso acima, o relatório no Jasper receberia uma coleção de históricos, onde estes, por sua vez, são iterados, e para cada histórico, sua coleção de “matriculasDiscente” também é iterada, quando o valor de “getComponenteHATotal()” for recuperado, este irá chamar um Helper, o qual chamará uma DAO, que abrirá uma conexão com o banco de dados. Neste caso, com as alterações feitas na arquitetura, esta conexão será aberta em uma thread a qual não temos o controle, impossibilitando o fechamento desta conexão, assim, possibilitando problemas com o pool de conexões.
  • 31.
    Identificar e corrigirrelatórios que abrem conexões por métodos *Helper ● Para que este problema seja resolvido, é necessário que TODOS os dados os quais o relatório necessite, sejam consultados antes do processamento do relatório, e assim, a coleção de históricos enviada ao relatório já vá com todos os seus dados populados. Estes casos exigem que, uma refatoração seja feita na consulta onde os dados são populados, antes do processamento do relatório pelo Jasper.
  • 32.
    Utilização correta demétodos *NoFlush ● Processamento de inserções e atualizações de N registros por vez (em “lote”) ● Otimização: commit feito no final do processamento com o método GenericDAOImpl.close(). ● Usar métodos ‘AbstractController.executeAndFlushClosingResources(...)’
  • 33.
    Utilização correta demétodos *NoFlush
  • 34.
    Utilização correta demétodos *NoFlush
  • 35.
    Utilização correta demétodos *NoFlush
  • 36.
    Utilização correta demétodos *NoFlush
  • 37.
    Status atual ● Enviadoao TRUNK do SVN para avaliação dos desenvolvedores ● Recebendo feedbacks sobre problemas identificados ● Será enviada para produção com o SIGRH ou SIPAC
  • 38.
    Dúvidas? ● https://goo.gl/WTZGAM (WikiSINFO - Soluções em Metodologias e Arquitetura Tecnológica) ● Raphael Medeiros ○ Skype: raphael.j.medeiros ● André Rabelo ○ Skype: andre.rabelo.pereira ?