{"id":2922,"date":"2014-10-24T09:13:00","date_gmt":"2014-10-24T12:13:00","guid":{"rendered":"http:\/\/blog.dialhost.com.br\/?p=2922"},"modified":"2014-10-24T09:13:00","modified_gmt":"2014-10-24T12:13:00","slug":"tunning-de-solucao-java-web","status":"publish","type":"post","link":"https:\/\/www.dialhost.com.br\/blog\/tunning-de-solucao-java-web\/","title":{"rendered":"Tunning de solu\u00e7\u00e3o Java Web"},"content":{"rendered":"<figure id=\"attachment_2923\" aria-describedby=\"caption-attachment-2923\" style=\"width: 700px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/blog.dialhost.com.br\/wp-content\/uploads\/2014\/10\/solution.jpg\"><img loading=\"lazy\" class=\"size-full wp-image-2923\" src=\"http:\/\/blog.dialhost.com.br\/wp-content\/uploads\/2014\/10\/solution.jpg\" alt=\"solu\u00e7\u00e3o \" width=\"700\" height=\"260\" \/><\/a><figcaption id=\"caption-attachment-2923\" class=\"wp-caption-text\">Imagem ilustrativa<\/figcaption><\/figure>\n<p>Segue abaixo um relato resumido de uma das minhas consultorias para uma empresa que tinha uma solu\u00e7\u00e3o web feita em Java que estava apresentando travamento e tempo de resposta ruim. O objetivo com esse artigo \u00e9 apresentar os problemas encontrados na solu\u00e7\u00e3o e as medidas adotadas de otimiza\u00e7\u00e3o, de forma com que outros profissionais possam aprender com os fatos e ou reutilizar as estrat\u00e9gias encontradas.<\/p>\n<p><strong>1. Otimiza\u00e7\u00e3o de acesso ao SGDB<\/strong><\/p>\n<p>Fizemos uma triagem da quantidade de acessos que o sistema faz ao sgdb quando um usu\u00e1rio acessa os principais processos. O resultado foi 117 round-trips. Ap\u00f3s estudos e otimiza\u00e7\u00f5es, reduzimos para 41 nos mesmos processos. Foi uma redu\u00e7\u00e3o de 65%! Dado que o n\u00famero de acessos di\u00e1rio dessa solu\u00e7\u00e3o \u00e9 de +- 7 mil \u2013 isso que dizer que reduzimos por dia (117 \u2013 41 = 76 * 7.000) 532 mil acesso ao sgdb. Essa otimiza\u00e7\u00e3o, al\u00e9m de aumentar o tempo de resposta, reduziu drasticamente o n\u00famero de conex\u00f5es do DataSource e a quantidade de parse de framework ORM, o que resultou em menos gastos com HEAP.<\/p>\n<p><strong>2. Otimiza\u00e7\u00e3o de auditoria<\/strong><\/p>\n<p>O sistema usa uma tabela de logg que registra toda a auditoria de seus processos no qual tem uma coluna auto increment\u00e1vel manual com uma chave composta, que por sua vez resulta em algumas consequ\u00eancias negativas:<\/p>\n<p>Para evitar inconsist\u00eancias de concorr\u00eancia nos MAXID + 1 para inserir registro, o sistema sincroniza a concorr\u00eancia em todos os processos, deixando a execu\u00e7\u00e3o da solu\u00e7\u00e3o em modo \u201cMONO\u201d usu\u00e1rios.<br \/>\nPara cada novo registro de logg, o sistema \u00e9 obrigado a fazer + 1 acesso ao sgdb para pegar o pr\u00f3ximo MAXID + 1 a ser gravado.<br \/>\nAp\u00f3s estudos e otimiza\u00e7\u00f5es, resolvemos ambos os problemas criando um nova tabela de logg contendo a mesma estrutura, s\u00f3 que utilizando o conceito de UUID como chave prim\u00e1ria. O resultado foi que para cada novo registro de auditoria n\u00e3o \u00e9 mais necess\u00e1rio acessar o sgdb para buscar o pr\u00f3ximo MAXID + 1, uma vez que o UUID \u00e9 gerado pela pr\u00f3pria solu\u00e7\u00e3o. Usando a mesma m\u00e9dia de acesso di\u00e1rio j\u00e1 indicada acima, reduzimos + 7 mil acessos ao sgdb por dia. A partir dessa medida, foi poss\u00edvel retirar todas as sincroniza\u00e7\u00f5es das opera\u00e7\u00f5es de auditoria, fazendo com que eles pudessem ser executados de forma agora 100% concorrentes.<\/p>\n<p><strong>3. Auditoria ass\u00edncrona<\/strong><\/p>\n<p>O sistema faz registros de loggs com caracter\u00edsticas somente de acesso, n\u00e3o sendo processos idempotentes. Do ponto de vista arquitetural, n\u00e3o faz sentido o usu\u00e1rio final esperar estes registros de loggs acontecer enquanto navega na solu\u00e7\u00e3o. Com isso,\u00a0 foi elaborada uma nova arquitetura de logg ass\u00edncrona espec\u00edfica para estes processos, no qual o sistema faz uso de threads separadas que v\u00e3o registrando os loggs, sem fazer o usu\u00e1rio pagar o tempo de espera na resposta da sua requisi\u00e7\u00e3o HTTP.<\/p>\n<p><strong>4. \u00cdndices de acesso<\/strong><\/p>\n<p>Depois de averigua\u00e7\u00f5es, foi constatado que as tabelas do sistema est\u00e3o sem nenhum \u00edndice, fazendo com que o sgdb busque os registros origin\u00e1rios das consultas do sistema (WHERE) 100% sequencial. Com base em todas as consultas existentes, foi criado uma API de \u00edndices que promova melhor performance nas consultas das tabelas, conforme descrito no livro oficial do provedor do sgdb. Foram criados exatamente 63 \u00edndices.<\/p>\n<p><strong>5. Evitando bloqueios pessimistas<\/strong><\/p>\n<p>O sistema faz acesso constante a um banco de dados de uma outra solu\u00e7\u00e3o legada da d\u00e9cada de 90, que por sua vez, utiliza-se do conceito de <a href=\"http:\/\/en.wikipedia.org\/wiki\/Lock_(database)\" target=\"_blank\" rel=\"noopener noreferrer\">bloqueio pessimista<\/a> para assegurar a consist\u00eancia nas concorr\u00eancias de seus processos. Em virtude disso, esse sistema sofre intensivo bloqueio, n\u00e3o conseguindo acessar as tabelas dessa outra solu\u00e7\u00e3o e ocasionando diversas paradas di\u00e1rias sentidas constantemente pelos usu\u00e1rios finais. Para contornar isso, aplicamos o n\u00edvel de isolamento das consultas do sistema para READ_UNCOMMITED que faz leituras das tabela independente dos bloqueios existentes. Os \u00fanicos lugares que tivemos que manter o n\u00edvel READ_COMMITED \u00e9 nas opera\u00e7\u00f5es de processos de neg\u00f3cios. Como hoje o sistema \u00e9 praticamente 70% de consultas e 30% de opera\u00e7\u00f5es de neg\u00f3cios transacionais, o usu\u00e1rio final com essa nova otimiza\u00e7\u00e3o n\u00e3o ficar\u00e1 mais\u00a0 impedido de acessar e consultar informa\u00e7\u00f5es quando existir bloqueios pessimistas. Isso reduzir\u00e1 drasticamente a maioria das reclama\u00e7\u00f5es.<\/p>\n<p><strong>6. Otimiza\u00e7\u00e3o de filtro NO-CACHE<\/strong><\/p>\n<p>Depois de averigua\u00e7\u00f5es, foi constatado que a solu\u00e7\u00e3o faz uso de um filtro servlet para decorar recursos web como \u201cno-cache\u201d HTTP. Nesse controle, encontramos o uso de opera\u00e7\u00e3o de substring() e contains() da classejava.lang.String. Para otimizar, foi utilizado o recurso de express\u00e3o regular, juntamente com a classe java.lang.Match que funciona bem mais r\u00e1pido na procura de padr\u00f5es de texto. Com base na mesma m\u00e9dia de acesso di\u00e1rio j\u00e1 indicada acima e que em cada requisi\u00e7\u00e3o HTTP o filtro \u00e9 executado +- 6 vezes, essa otimiza\u00e7\u00e3o deixou a tempo de resposta bem melhor.<\/p>\n<p>7. Mensurando as otimiza\u00e7\u00f5es<\/p>\n<p>Para podermos quantificar as melhorias das otimiza\u00e7\u00f5es, foi feita uma amostra de teste usando nas seguintes configura\u00e7\u00f5es SEVIDOR LINUX, JAVA7, TOMCAT 6 com 1GB HEAD, ferramenta de testes JMETER e usando um sgdb remoto de homologa\u00e7\u00e3o, executando os principais cen\u00e1rios de processos utilizados pelos usu\u00e1rios. Segue um resumo das estat\u00edsticas do resultado:<\/p>\n<p>Vers\u00e3o do sistema atual, rodamos os testes usando a vers\u00e3o atual da sistema:<\/p>\n<ul>\n<li>1 usu\u00e1rio demorou 6 segundos para executar todo o script de testes.<\/li>\n<li>500 usu\u00e1rios simult\u00e2neos demoraram 6:10 minutos para executar todo o script de testes.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>Vers\u00e3o do sistema otimizada, rodamos o mesmos testes e usando uma vers\u00e3o com todas a otimiza\u00e7\u00f5es:<\/p>\n<ul>\n<li>1 usu\u00e1rio demorou 4 segundos para executar todo o script de testes \u201333% MAIS R\u00c1PIDO!<\/li>\n<li>500 usu\u00e1rios simult\u00e2neos demoraram 2 :38 minutos para executar todo o script de testes \u2013 66% MAIS R\u00c1PIDO!<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>Depois de dois meses de muito trabalho, conclui-se que o resultado final foi positivo e muito expressivo. Vale destacar aqui que as otimiza\u00e7\u00f5es s\u00f3 foram poss\u00edveis de serem aplicadas uma vez que a solu\u00e7\u00e3o estava devidamente arquiteturada em camadas, seguindo corretamente a filosofia do <a href=\"http:\/\/en.wikipedia.org\/wiki\/Domain-driven_design\" target=\"_blank\" rel=\"noopener noreferrer\">DDD<\/a>, e porque utilizada gerenciamento de transa\u00e7\u00f5es autom\u00e1ticas via AOP com o framework <a href=\"http:\/\/spring.io\/\" target=\"_blank\" rel=\"noopener noreferrer\">Spring Transaction.<\/a> Caso contr\u00e1rio, ficar\u00edamos impedidos de fazer qualquer tipo de altera\u00e7\u00f5es, levando a empresa contratante ao caminho tortuoso da reescrita total da solu\u00e7\u00e3o.<\/p>\n<p>Para os interessados nesse tipo de assunto, <a href=\"http:\/\/fernandofranzini.wordpress.com\/2014\/09\/29\/tunning-de-aplicacoes-web\/\" target=\"_blank\" rel=\"noopener noreferrer\">veja minha regrinha de bolo de otimiza\u00e7\u00e3o<\/a> que qualquer um pode reusar como ponto inicial para esse tipo de atividade.<\/p>\n<p>At\u00e9 a pr\u00f3xima!<\/p>\n<p>&#8212;&#8211;<\/p>\n<p>Artigo de Fernando Franzini, originalmente publicado no <a href=\"http:\/\/imasters.com.br\/linguagens\/java\/tunning-de-solucao-java-web\/\" target=\"_blank\" rel=\"noopener noreferrer\">iMasters<\/a>.\t\t\t\t<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\t\t\t\tVeja como foi feita a otimiza\u00e7\u00e3o de uma solu\u00e7\u00e3o web feita em Java que estava apresentando travamento e tempo de resposta ruim.\t\t\t\t<\/p>\n","protected":false},"author":1,"featured_media":2924,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[3],"tags":[76,99,132,158],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v15.0 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Tunning de solu\u00e7\u00e3o Java Web - Blog DialHost<\/title>\n<meta name=\"description\" content=\"Veja como foi feita a otimiza\u00e7\u00e3o de uma solu\u00e7\u00e3o web feita em Java que estava apresentando travamento e tempo de resposta ruim.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.dialhost.com.br\/blog\/tunning-de-solucao-java-web\/\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Tunning de solu\u00e7\u00e3o Java Web - Blog DialHost\" \/>\n<meta property=\"og:description\" content=\"Veja como foi feita a otimiza\u00e7\u00e3o de uma solu\u00e7\u00e3o web feita em Java que estava apresentando travamento e tempo de resposta ruim.\" \/>\n<meta property=\"og:url\" content=\"\/blog\/tunning-de-solucao-java-web\/\" \/>\n<meta property=\"og:site_name\" content=\"Blog DialHost\" \/>\n<meta property=\"article:publisher\" content=\"http:\/\/www.facebook.com\/DialHost\" \/>\n<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/DialHost\" \/>\n<meta property=\"article:published_time\" content=\"2014-10-24T12:13:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.dialhost.com.br\/blog\/wp-content\/uploads\/2019\/04\/og-image.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@dialhost\" \/>\n<meta name=\"twitter:site\" content=\"@dialhost\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/#organization\",\"name\":\"DialHost Internet\",\"url\":\"https:\/\/www.dialhost.com.br\/blog\/\",\"sameAs\":[\"http:\/\/www.facebook.com\/DialHost\",\"https:\/\/www.instagram.com\/dialhost_oficial\/\",\"https:\/\/www.linkedin.com\/company\/dialhost-internet\",\"https:\/\/www.youtube.com\/channel\/UCAiqiX8IiqTSfA8wQhpzgXQ\",\"https:\/\/twitter.com\/dialhost\"],\"logo\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/#logo\",\"inLanguage\":\"pt-BR\",\"url\":\"https:\/\/www.dialhost.com.br\/blog\/wp-content\/uploads\/2019\/03\/marca-dialhost.png\",\"width\":81,\"height\":81,\"caption\":\"DialHost Internet\"},\"image\":{\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/#logo\"}},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/#website\",\"url\":\"https:\/\/www.dialhost.com.br\/blog\/\",\"name\":\"Blog DialHost\",\"description\":\"Os melhores conte\\u00fados sobre Desenvolvimento Web, Marketing e Neg\\u00f3cios\",\"publisher\":{\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"https:\/\/www.dialhost.com.br\/blog\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"pt-BR\"},{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/tunning-de-solucao-java-web\/#primaryimage\",\"inLanguage\":\"pt-BR\",\"url\":\"\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/tunning-de-solucao-java-web\/#webpage\",\"url\":\"https:\/\/www.dialhost.com.br\/blog\/tunning-de-solucao-java-web\/\",\"name\":\"Tunning de solu\\u00e7\\u00e3o Java Web - Blog DialHost\",\"isPartOf\":{\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/tunning-de-solucao-java-web\/#primaryimage\"},\"datePublished\":\"2014-10-24T12:13:00+00:00\",\"dateModified\":\"2014-10-24T12:13:00+00:00\",\"description\":\"Veja como foi feita a otimiza\\u00e7\\u00e3o de uma solu\\u00e7\\u00e3o web feita em Java que estava apresentando travamento e tempo de resposta ruim.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/tunning-de-solucao-java-web\/#breadcrumb\"},\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.dialhost.com.br\/blog\/tunning-de-solucao-java-web\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/tunning-de-solucao-java-web\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"item\":{\"@type\":\"WebPage\",\"@id\":\"\/blog\/\",\"url\":\"\/blog\/\",\"name\":\"In\\u00edcio\"}},{\"@type\":\"ListItem\",\"position\":2,\"item\":{\"@type\":\"WebPage\",\"@id\":\"\/blog\/tunning-de-solucao-java-web\/\",\"url\":\"\/blog\/tunning-de-solucao-java-web\/\",\"name\":\"Tunning de solu\\u00e7\\u00e3o Java Web\"}}]},{\"@type\":\"Article\",\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/tunning-de-solucao-java-web\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/tunning-de-solucao-java-web\/#webpage\"},\"author\":{\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/#\/schema\/person\/a0b10cbe35449dea173a06d4664f9fcc\"},\"headline\":\"Tunning de solu\\u00e7\\u00e3o Java Web\",\"datePublished\":\"2014-10-24T12:13:00+00:00\",\"dateModified\":\"2014-10-24T12:13:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/tunning-de-solucao-java-web\/#webpage\"},\"publisher\":{\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/tunning-de-solucao-java-web\/#primaryimage\"},\"keywords\":\"desenvolvimento,feed de parceiros,java,noticias\",\"articleSection\":\"Dicas e Not\\u00edcias\",\"inLanguage\":\"pt-BR\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/#\/schema\/person\/a0b10cbe35449dea173a06d4664f9fcc\",\"name\":\"DialHost Internet\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/www.dialhost.com.br\/blog\/#personlogo\",\"inLanguage\":\"pt-BR\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/05feec2f99aef1c42b09aeaa637ee66f?s=96&r=g\",\"caption\":\"DialHost Internet\"},\"description\":\"H\\u00e1 mais de 18 anos proporcionando um servi\\u00e7o de hospedagem de sites voltado 100% na Experi\\u00eancia e Sucesso do Cliente, prezando a qualidade, transpar\\u00eancia e seguran\\u00e7a.\",\"sameAs\":[\"https:\/\/www.facebook.com\/DialHost\",\"https:\/\/www.instagram.com\/dialhost_oficial\/\",\"https:\/\/www.linkedin.com\/company\/dialhost-internet\",\"https:\/\/twitter.com\/dialhost\",\"https:\/\/www.youtube.com\/channel\/UCAiqiX8IiqTSfA8wQhpzgXQ\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","_links":{"self":[{"href":"https:\/\/www.dialhost.com.br\/blog\/wp-json\/wp\/v2\/posts\/2922"}],"collection":[{"href":"https:\/\/www.dialhost.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dialhost.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dialhost.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dialhost.com.br\/blog\/wp-json\/wp\/v2\/comments?post=2922"}],"version-history":[{"count":0,"href":"https:\/\/www.dialhost.com.br\/blog\/wp-json\/wp\/v2\/posts\/2922\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.dialhost.com.br\/blog\/wp-json\/wp\/v2\/media\/2924"}],"wp:attachment":[{"href":"https:\/\/www.dialhost.com.br\/blog\/wp-json\/wp\/v2\/media?parent=2922"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dialhost.com.br\/blog\/wp-json\/wp\/v2\/categories?post=2922"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dialhost.com.br\/blog\/wp-json\/wp\/v2\/tags?post=2922"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}