{"id":81089,"date":"2020-05-11T01:42:24","date_gmt":"2020-05-10T23:42:24","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/tipovye-oshibki-v-prilozheniyah-kotorye-vedut-k-bloat-v-postgresql-andrej-salnikov"},"modified":"2020-05-11T01:42:24","modified_gmt":"2020-05-10T23:42:24","slug":"tipovye-oshibki-v-prilozheniyah-kotorye-vedut-k-bloat-v-postgresql-andrej-salnikov","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/tipovye-oshibki-v-prilozheniyah-kotorye-vedut-k-bloat-v-postgresql-andrej-salnikov","title":{"rendered":"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><strong>Apresento a voc\u00eas a transcri\u00e7\u00e3o do relat\u00f3rio de in\u00edcio de 2016 de Andrei Salnikov \"Erros t\u00edpicos em aplicativos que levam ao bloat no PostgreSQL\"<\/strong><\/p>\n<p><\/p>\n<p>Nesta palestra, abordarei os principais erros em aplicativos que ocorrem na fase de projeto e desenvolvimento do c\u00f3digo do aplicativo. Irei considerar apenas aqueles erros que levam ao bloat no Postgresql. Geralmente, esse \u00e9 o in\u00edcio do fim do desempenho do seu sistema como um todo, embora inicialmente n\u00e3o houvesse sinais disso.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/a9e199bfe2e01c76966b32868790f8f0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Sauda\u00e7\u00f5es a todos! Esta palestra n\u00e3o \u00e9 t\u00e3o t\u00e9cnica quanto a anterior do meu colega. Esta palestra \u00e9 voltada principalmente para desenvolvedores de sistemas de backend, pois temos um n\u00famero consider\u00e1vel de clientes. E todos cometem os mesmos erros. Sobre esses erros que vou falar. Explicarei as consequ\u00eancias fatais e negativas desses erros. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/c6c84dbafc595ae3068cd8bf804ccee7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Por que os erros ocorrem? Eles ocorrem por duas raz\u00f5es: por acaso, pode dar certo, e pela falta de conhecimento sobre alguns mecanismos que acontecem entre o banco de dados e o aplicativo, assim como no pr\u00f3prio banco de dados. <\/p>\n<p><\/p>\n<p>Vou lhe apresentar tr\u00eas exemplos com imagens horr\u00edveis do que acontece quando tudo d\u00e1 errado. Em resumo, falarei sobre o mecanismo que ocorre ali. E como lidar com eles quando acontecem, al\u00e9m de quais m\u00e9todos preventivos usar para evitar erros. Farei uma apresenta\u00e7\u00e3o de ferramentas auxiliares e fornecer links \u00fateis. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b0230d992f5b44f0e542df2e4b4d526f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Utilizei um banco de dados de teste, onde tinha duas tabelas. Uma tabela com as contas dos clientes e outra com as opera\u00e7\u00f5es dessas contas. E, com uma certa periodicidade, atualizamos os saldos dessas contas.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/1d2a21278b095b07546e1bb870819dbf.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dados iniciais da tabela: \u00e9 bastante pequena, 2 MB. O tempo de resposta do banco e especificamente da tabela tamb\u00e9m \u00e9 muito bom. E uma carga bastante boa - 2.000 opera\u00e7\u00f5es por segundo na tabela.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/dea5a4b1ac7952f8cfed0e2e1cfc10dd.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E ao longo desta palestra, vou mostrar gr\u00e1ficos para que fique claro o que est\u00e1 acontecendo. Sempre haver\u00e1 2 slides com gr\u00e1ficos. O primeiro slide mostrar\u00e1 o que est\u00e1 acontecendo em geral no servidor. <\/p>\n<p><\/p>\n<p>E nesta situa\u00e7\u00e3o, vemos que realmente temos uma tabela de tamanho pequeno. O \u00edndice \u00e9 pequeno, de 2 MB. Este \u00e9 o primeiro gr\u00e1fico \u00e0 esquerda. <\/p>\n<p><\/p>\n<p>O tempo m\u00e9dio de resposta do servidor tamb\u00e9m \u00e9 est\u00e1vel e pequeno. Este \u00e9 o gr\u00e1fico superior direito. <\/p>\n<p><\/p>\n<p>O gr\u00e1fico no canto inferior esquerdo mostra as transa\u00e7\u00f5es mais longas. Observamos que as transa\u00e7\u00f5es s\u00e3o conclu\u00eddas rapidamente. E o autovacuum ainda n\u00e3o est\u00e1 funcionando aqui, porque foi um teste inicial. Depois, ele funcionar\u00e1 e ser\u00e1 \u00fatil para n\u00f3s.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/9e9b46acd9a878ff70ca4a7850adff09.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>O segundo slide sempre ser\u00e1 dedicado \u00e0 tabela em teste. Nessa situa\u00e7\u00e3o, atualizamos constantemente os saldos das contas do cliente. E observamos que o tempo m\u00e9dio de resposta para a opera\u00e7\u00e3o de atualiza\u00e7\u00e3o \u00e9 bastante bom, abaixo de um milissegundo. Tamb\u00e9m vemos que os recursos da CPU (este \u00e9 o gr\u00e1fico no canto superior direito) s\u00e3o consumidos de forma uniforme e em quantidades bastante pequenas. <\/p>\n<p><\/p>\n<p>O gr\u00e1fico no canto inferior direito mostra quanta mem\u00f3ria operacional e de disco estamos percorrendo em busca da linha necess\u00e1ria antes de atualiz\u00e1-la. E a quantidade de opera\u00e7\u00f5es na tabela \u00e9 de 2.000 por segundo, como mencionei no in\u00edcio. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/84760d52716209b8dcfffb462c67a8e1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E agora ocorre uma trag\u00e9dia. Por algum motivo, surge uma transa\u00e7\u00e3o esquecida e longa. As raz\u00f5es geralmente s\u00e3o bastante banais: <\/p>\n<p><\/p>\n<ul>\n<li>Uma das mais comuns \u00e9 que come\u00e7amos a chamar um servi\u00e7o externo no c\u00f3digo do aplicativo. E esse servi\u00e7o n\u00e3o nos responde. Ou seja, abrimos uma transa\u00e7\u00e3o, fizemos uma altera\u00e7\u00e3o no banco e fomos ler e-mails ou buscar outro servi\u00e7o dentro da nossa infraestrutura, e por algum motivo ele n\u00e3o responde. E temos uma sess\u00e3o pendente em um estado \u2013 n\u00e3o sabemos quando ser\u00e1 resolvido.<\/li>\n<li>A segunda situa\u00e7\u00e3o ocorre quando, por algum motivo, houve uma exce\u00e7\u00e3o no c\u00f3digo. E n\u00e3o tratamos o fechamento da transa\u00e7\u00e3o na exce\u00e7\u00e3o. E acabamos com uma sess\u00e3o pendente com uma transa\u00e7\u00e3o aberta. <\/li>\n<li>E por \u00faltimo, este \u00e9 tamb\u00e9m um caso bastante comum. \u00c9 um c\u00f3digo de m\u00e1 qualidade. Alguns frameworks abrem uma transa\u00e7\u00e3o. Ela fica pendente, e voc\u00ea pode n\u00e3o saber em seu aplicativo que ela est\u00e1 pendente. <\/li>\n<\/ul>\n<p><\/p>\n<p>A que isso leva? <\/p>\n<p><\/p>\n<p>A que as tabelas e os \u00edndices come\u00e7am a crescer rapidamente. Este \u00e9 exatamente o efeito de bloat. Para o banco de dados, isso se manifestar\u00e1 em um aumento abrupto no tempo de resposta, aumento da carga no servidor de banco de dados. E, como resultado, o aplicativo sofrer\u00e1. Porque se no c\u00f3digo voc\u00ea gastava 10 milissegundos em uma consulta ao banco, 10 milissegundos em sua l\u00f3gica, sua fun\u00e7\u00e3o levava 20 milissegundos. Mas agora, a situa\u00e7\u00e3o ser\u00e1 bastante triste. <\/p>\n<p><\/p>\n<p>E vamos ver o que est\u00e1 acontecendo. O gr\u00e1fico no canto inferior esquerdo mostra que temos uma transa\u00e7\u00e3o longa. E se olharmos para o gr\u00e1fico no canto superior esquerdo, vemos que o tamanho da tabela de dois megabytes disparou para 300 megabytes. Entretanto, a quantidade de dados na tabela n\u00e3o mudou, ou seja, h\u00e1 uma quantidade consider\u00e1vel de lixo.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b1947f6487e440a770a1251a955e62d2.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>A situa\u00e7\u00e3o geral em rela\u00e7\u00e3o ao tempo m\u00e9dio de resposta do servidor tamb\u00e9m mudou em v\u00e1rias ordens de grandeza. Ou seja, todas as solicita\u00e7\u00f5es ao servidor come\u00e7aram a apresentar quedas significativas. E, al\u00e9m disso, processos internos do Postgres, como o autovacuum, come\u00e7aram a rodar, tentando fazer algo e consumindo recursos.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/8e91f035d1dd04e72e842d714cc611a5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>O que est\u00e1 acontecendo com nossa tabela? A mesma coisa. O tempo m\u00e9dio de resposta da tabela disparou em v\u00e1rias ordens de grandeza. Especificamente em rela\u00e7\u00e3o aos recursos consumidos, vemos que a carga sobre o processador aumentou consideravelmente. Este \u00e9 o gr\u00e1fico no canto superior direito. E isso aumentou porque o processador est\u00e1 tendo que percorrer uma quantidade enorme de linhas in\u00fateis em busca de uma linha necess\u00e1ria. Este \u00e9 o gr\u00e1fico no canto inferior direito. Como resultado, o n\u00famero de chamadas por segundo come\u00e7ou a cair drasticamente, porque o banco de dados n\u00e3o consegue processar a mesma quantidade de solicita\u00e7\u00f5es. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/424685ce852bc5f3ef77151f8d3d7289.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Precisamos voltar \u00e0 vida. Vamos \u00e0 internet e descobrimos que transa\u00e7\u00f5es longas levam a problemas. Encontramos e eliminamos essa transa\u00e7\u00e3o. E tudo volta ao normal. Tudo funciona como deve. <\/p>\n<p><\/p>\n<p>Ficamos calmos, mas ap\u00f3s algum tempo come\u00e7amos a notar que o aplicativo n\u00e3o est\u00e1 funcionando t\u00e3o bem quanto antes da situa\u00e7\u00e3o de emerg\u00eancia. As solicita\u00e7\u00f5es ainda est\u00e3o sendo processadas mais lentamente, e de fato, significativamente mais lentas. No meu caso, cerca de uma vez e meia a duas vezes mais lentas. A carga no servidor tamb\u00e9m est\u00e1 maior do que antes da emerg\u00eancia. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/ee3037719a31f8d18fc42745716c4da5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E a pergunta \u00e9: \"O que est\u00e1 acontecendo com o banco de dados nesse momento?\". O que acontece com o banco de dados \u00e9 a seguinte situa\u00e7\u00e3o. No gr\u00e1fico de transa\u00e7\u00f5es, voc\u00ea pode ver que ele parou e realmente n\u00e3o h\u00e1 transa\u00e7\u00f5es longas. Mas o tamanho da tabela durante a emerg\u00eancia aumentou drasticamente. E desde ent\u00e3o n\u00e3o diminuiu. O tempo m\u00e9dio no banco de dados se estabilizou. E as respostas parecem estar adequadas com uma velocidade aceit\u00e1vel para n\u00f3s. O autovacuum se tornou mais ativo e come\u00e7ou a fazer algo com a tabela, porque precisa lidar com uma maior quantidade de dados. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/f6205242c4024dc3ed4cade5844dbf76.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Especificamente em rela\u00e7\u00e3o \u00e0 tabela testada com as contas, onde mudamos os saldos: o tempo de resposta para a consulta parece ter voltado ao normal. Mas, na verdade, ainda est\u00e1 uma vez e meia mais alto.<\/p>\n<p><\/p>\n<p>Quanto \u00e0 carga do processador, vemos que a carga n\u00e3o retornou ao n\u00edvel necess\u00e1rio antes da falha. As raz\u00f5es est\u00e3o, na verdade, no gr\u00e1fico inferior direito. \u00c9 vis\u00edvel que l\u00e1 h\u00e1 um consumo excessivo de mem\u00f3ria. Ou seja, para encontrar a linha necess\u00e1ria, estamos consumindo recursos do servidor de banco de dados ao percorrer dados in\u00fateis. O n\u00famero de transa\u00e7\u00f5es por segundo estabilizou. <\/p>\n<p><\/p>\n<p>No geral, est\u00e1 bem, mas a situa\u00e7\u00e3o \u00e9 pior do que antes. H\u00e1 uma clara degrada\u00e7\u00e3o do banco de dados como consequ\u00eancia do nosso aplicativo que interage com esse banco de dados. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/0dfc9cd453fd84bc639ffd99cf189fd2.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E para entender o que est\u00e1 acontecendo, caso voc\u00ea n\u00e3o tenha assistido \u00e0 apresenta\u00e7\u00e3o anterior, uma breve teoria. Teoria sobre o processo interno. Para que serve o autovacuum e o que ele faz?<\/p>\n<p><\/p>\n<p>Resumidamente, para entendimento. Em algum momento, temos uma tabela. Na tabela, temos linhas. Essas linhas podem ser ativas, vivas, que precisamos agora. Na imagem, est\u00e3o marcadas em verde. E existem linhas mortas, que j\u00e1 foram processadas, foram atualizadas, surgiram novas entradas. Est\u00e3o marcadas como n\u00e3o mais interessantes para o banco de dados. Mas permanecem na tabela devido \u00e0s peculiaridades do Postgres.<\/p>\n<p><\/p>\n<p>Para que serve o autovacuum? O autovacuum em algum momento chega, se dirige ao banco de dados e pergunta: \"Por favor, me d\u00ea o id da transa\u00e7\u00e3o mais antiga que est\u00e1 aberta no momento no banco de dados\". O banco de dados retorna esse id. E o autovacuum, com base nisso, atravessa as linhas na tabela. Se ele v\u00ea que algumas linhas foram modificadas por transa\u00e7\u00f5es muito mais antigas, ele tem o direito de marc\u00e1-las como linhas que podemos reutilizar no futuro, gravando novos dados nelas. Este \u00e9 um processo em segundo plano.<\/p>\n<p><\/p>\n<p>Enquanto isso, continuamos a trabalhar com o banco de dados, fazendo algumas altera\u00e7\u00f5es na tabela. E para essas linhas que podemos reutilizar, gravamos novos dados. Assim, temos um ciclo, ou seja, sempre surgem algumas linhas mortas antigas, e em vez delas, gravamos novas linhas que precisamos. E esse \u00e9 um estado normal para o funcionamento do PostgreSQL.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/98dd4451a7ca5f418775f72822c2840c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>O que aconteceu durante o acidente? Como esse processo ocorreu?<\/p>\n<p><\/p>\n<p>T\u00ednhamos uma tabela em um certo estado, algumas linhas vivas e outras mortas. O autovacuum chegou. Ele perguntou ao banco de dados qual era a nossa transa\u00e7\u00e3o mais antiga e qual era o seu id. Recebeu esse id, que poderia ter horas de idade ou apenas dez minutos. Isso depende da carga que voc\u00ea tem no seu banco de dados. E come\u00e7ou a procurar as linhas que ele poderia marcar como reutiliz\u00e1veis. E n\u00e3o encontrou tais linhas na nossa tabela. <\/p>\n<p><\/p>\n<p>Mas, enquanto isso, continuamos a trabalhar na tabela. Estamos fazendo algo nela, atualizando, mudando dados. E o que o banco de dados faz nesse tempo? N\u00e3o resta a ele outra op\u00e7\u00e3o a n\u00e3o ser adicionar novas linhas ao final da tabela existente. E assim, o tamanho da tabela come\u00e7a a aumentar. <\/p>\n<p><\/p>\n<p>Na realidade, precisamos das linhas verdes para o trabalho. Mas durante esse problema, nosso percentual de linhas verdes \u00e9 extremamente baixo em todo o volume da tabela. <\/p>\n<p><\/p>\n<p>E quando executamos uma consulta, o banco de dados precisa percorrer todas as linhas: tanto as vermelhas quanto as verdes, para encontrar a linha certa. E o efeito de aumento da tabela com dados in\u00fateis \u00e9 chamado de 'bloat', que tamb\u00e9m consome nosso espa\u00e7o em disco. Lembra que era 2 MB, agora \u00e9 300 MB? Agora troque megabytes por gigabytes e voc\u00ea rapidamente ficar\u00e1 sem todos os seus recursos de disco.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/fe7cb6b5c99610744ebcfe5ad7235d1e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Quais podem ser as consequ\u00eancias para n\u00f3s? <\/p>\n<p><\/p>\n<ul>\n<li>No meu exemplo, a tabela e o \u00edndice cresceram 150 vezes. Alguns de nossos clientes tiveram casos mais fatais, quando simplesmente o espa\u00e7o em disco come\u00e7ava a acabar. <\/li>\n<li>O tamanho das tabelas em si nunca diminui. O autovacuum em alguns casos pode cortar a cauda da tabela se houver apenas linhas mortas. Mas como ocorre uma rota\u00e7\u00e3o constante, uma linha verde pode acabar pendurada no final e n\u00e3o ser atualizada, enquanto todas as outras ser\u00e3o gravadas em algum lugar no in\u00edcio da tabela. Mas isso \u00e9 um evento t\u00e3o improv\u00e1vel, que n\u00e3o \u00e9 algo que voc\u00ea deva esperar. <\/li>\n<li>O banco de dados precisa percorrer todo um monte de linhas in\u00fateis. E estamos consumindo recursos de disco, recursos de processador e energia el\u00e9trica. <\/li>\n<li>E isso impacta diretamente nosso aplicativo, pois, se no in\u00edcio gast\u00e1vamos 10 milissegundos em uma solicita\u00e7\u00e3o e 10 milissegundos no nosso c\u00f3digo, durante a falha passamos a gastar um segundo na solicita\u00e7\u00e3o e 10 milissegundos no c\u00f3digo, ou seja, a performance do aplicativo caiu drasticamente. E quando a falha foi resolvida, come\u00e7amos a gastar 20 milissegundos na solicita\u00e7\u00e3o e 10 milissegundos no c\u00f3digo. Isso significa que ainda assim nossa performance caiu em um fator de 1,5. E tudo isso devido a uma transa\u00e7\u00e3o que travou, possivelmente por nossa culpa. <\/li>\n<li>E a pergunta \u00e9: \"Como voltar atr\u00e1s?\" Para que tudo volte a funcionar bem e as solicita\u00e7\u00f5es sejam t\u00e3o r\u00e1pidas quanto antes da falha. <\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/1bf46e8cd9b28ca2862f978f2ca85819.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Para isso, existe um ciclo de trabalho definido que deve ser realizado. <\/p>\n<p><\/p>\n<p>Primeiro, precisamos identificar as tabelas problem\u00e1ticas que incharam. Compreendemos que algumas tabelas t\u00eam registros mais ativos e outras menos ativos. E para isso, utilizamos a extens\u00e3o <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/pgstattuple.html\">pgstattuple<\/a><\/noindex>. Ap\u00f3s instalar essa extens\u00e3o, voc\u00ea pode escrever consultas que ajudar\u00e3o a encontrar as tabelas que incharam significativamente. <\/p>\n<p><\/p>\n<p>Depois de identificar essas tabelas, elas precisam ser compactadas. Para isso, j\u00e1 existem ferramentas. Em nossa empresa, usamos tr\u00eas ferramentas. A primeira \u00e9 o VACUUM FULL embutido. Ele \u00e9 severo, rigoroso e implac\u00e1vel, mas \u00e0s vezes \u00e9 muito \u00fatil. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/reorg\/pg_repack\">Pg_repack<\/a><\/noindex> e <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dataegret\/pgcompacttable\">pgcompacttable<\/a><\/noindex> \u2014 s\u00e3o utilit\u00e1rios de terceiros para a compacta\u00e7\u00e3o de tabelas. E eles lidam com o banco de dados de maneira mais cuidadosa. <\/p>\n<p><\/p>\n<p>Eles s\u00e3o utilizados dependendo da sua conveni\u00eancia. Mas eu falarei sobre isso no final. O importante \u00e9 que h\u00e1 tr\u00eas ferramentas. H\u00e1 op\u00e7\u00f5es dispon\u00edveis. <\/p>\n<p><\/p>\n<p>Depois de corrigirmos tudo e assegurarmos que tudo est\u00e1 bem, devemos saber como prevenir essa situa\u00e7\u00e3o no futuro:<\/p>\n<p><\/p>\n<ul>\n<li>\u00c9 uma preven\u00e7\u00e3o relativamente f\u00e1cil. Precisamos monitorar a dura\u00e7\u00e3o das sess\u00f5es no Servidor Master. <strong>Sess\u00f5es especialmente perigosas em estado de idle in transaction.<\/strong>Essas s\u00e3o as que abriram uma transa\u00e7\u00e3o, realizaram algo e sa\u00edram ou simplesmente travaram, se perderam no c\u00f3digo. <\/li>\n<li>E para voc\u00eas, como desenvolvedores, \u00e9 importante testar o c\u00f3digo quando essas situa\u00e7\u00f5es surgem. N\u00e3o \u00e9 dif\u00edcil de fazer. Isso ser\u00e1 uma verifica\u00e7\u00e3o \u00fatil. Voc\u00ea evitar\u00e1 um grande n\u00famero de problemas \"infantis\" relacionados a transa\u00e7\u00f5es longas. <\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/d55465d96c4018db733954867d23aaba.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Nestes gr\u00e1ficos, eu queria mostrar como a tabela e o comportamento do banco de dados mudaram depois que passei, neste caso, um VACUUM FULL na tabela. Isso n\u00e3o \u00e9 produ\u00e7\u00e3o para mim.<\/p>\n<p><\/p>\n<p>O tamanho da tabela voltou imediatamente ao seu estado normal de funcionamento, com poucos megabytes. Isso n\u00e3o afetou muito o tempo m\u00e9dio de resposta do servidor. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/cbb07ad24dba899395223d1ca25e438e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Mas, especificamente para nossa tabela experimentada, onde atualizamos os saldos nas contas, vemos que o tempo m\u00e9dio de resposta para a solicita\u00e7\u00e3o de atualiza\u00e7\u00e3o de dados na tabela foi reduzido ao n\u00edvel pr\u00e9-acidente. Os recursos consumidos pelo processador para executar essa solicita\u00e7\u00e3o tamb\u00e9m ca\u00edram para o n\u00edvel pr\u00e9-acidente. E o gr\u00e1fico no canto inferior direito mostra que agora encontramos exatamente a linha que precisamos imediatamente, sem percorrer um monte de linhas mortas que existiam antes da compacta\u00e7\u00e3o da tabela. E o tempo m\u00e9dio das solicita\u00e7\u00f5es permaneceu aproximadamente no mesmo n\u00edvel. Mas aqui eu tenho, mais provavelmente, um erro do meu hardware.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/c1d90c5442e02fce209dc40e048a8ca2.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Aqui termina a primeira hist\u00f3ria. \u00c9 a mais comum. E acontece com todos, independentemente da experi\u00eancia do cliente e da qualifica\u00e7\u00e3o dos programadores. Mais cedo ou mais tarde isso acontece. <\/p>\n<p><\/p>\n<p>A segunda hist\u00f3ria, onde distribu\u00edmos a carga e otimizamos os recursos do servidor.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/cda421c554d1329107ddc935045cc1b9.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<ul>\n<li>J\u00e1 crescemos e nos tornamos um grupo s\u00e9rio. E entendemos que temos uma r\u00e9plica e seria bom balancear a carga: escrever no Master e ler da r\u00e9plica. Normalmente essa situa\u00e7\u00e3o surge quando queremos preparar alguns relat\u00f3rios ou fazer ETL. E o neg\u00f3cio fica muito satisfeito com isso. Ele realmente deseja relat\u00f3rios diversos com um monte de an\u00e1lises complexas. <\/li>\n<li>Os relat\u00f3rios levam horas, porque a an\u00e1lise complexa n\u00e3o pode ser realizada em milissegundos. N\u00f3s, como bons rapazes, escrevemos c\u00f3digo. Fazemos inser\u00e7\u00f5es no aplicativo, gravando no Master e executando relat\u00f3rios na r\u00e9plica. <\/li>\n<li>Distribu\u00edmos a carga. <\/li>\n<li>Tudo funciona perfeitamente. N\u00f3s estamos indo bem. <\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/e94c8c492197a5015ac8aae79389a4c2.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E como essa situa\u00e7\u00e3o se apresenta? Especificamente nestes gr\u00e1ficos, eu adicionei tamb\u00e9m a dura\u00e7\u00e3o das transa\u00e7\u00f5es com a r\u00e9plica. Todos os outros gr\u00e1ficos se referem apenas ao servidor Master. <\/p>\n<p><\/p>\n<p>A tabela de relat\u00f3rios cresceu at\u00e9 o momento. Agora temos mais dela. Vemos que o tempo m\u00e9dio de resposta do servidor est\u00e1 est\u00e1vel. Observamos que na r\u00e9plica h\u00e1 uma transa\u00e7\u00e3o longa, que est\u00e1 em andamento h\u00e1 2 horas. Notamos o funcionamento tranquilo do autovacuum, que lida com linhas mortas. E tudo est\u00e1 indo bem. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2da8acf098d12d6f146ab9b9dcb54b81.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Especificamente em rela\u00e7\u00e3o \u00e0 tabela testada, continuamos atualizando os saldos nas contas. E tamb\u00e9m temos um tempo de resposta est\u00e1vel para as consultas, com um consumo de recursos est\u00e1vel. Tudo est\u00e1 indo bem. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/3621ef723017bac6fb635caf0a5f4de6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Tudo vai bem at\u00e9 o momento em que esses relat\u00f3rios come\u00e7am a ser rejeitados devido a conflitos com a replica\u00e7\u00e3o. E eles s\u00e3o rejeitados com uma periodicidade constante. <\/p>\n<p><\/p>\n<p>Pesquisamos na internet e come\u00e7amos a ler por que isso acontece. E encontramos uma solu\u00e7\u00e3o. <\/p>\n<p><\/p>\n<p>A primeira solu\u00e7\u00e3o \u00e9 aumentar a lat\u00eancia de replica\u00e7\u00e3o. Sabemos que nosso relat\u00f3rio funciona por 3 horas. Definimos a lat\u00eancia de replica\u00e7\u00e3o para 3 horas. Ligamos tudo, mas ainda assim continuamos tendo problemas com o fato de que os relat\u00f3rios \u00e0s vezes s\u00e3o rejeitados. <\/p>\n<p><\/p>\n<p>Queremos que tudo funcione perfeitamente. Pesquisamos mais e encontramos uma configura\u00e7\u00e3o interessante na internet \u2013 hot_standby_feedback. Ativamos isso. O hot_standby_feedback nos permite segurar o funcionamento do autovacuum no Master. Assim, nos livramos completamente dos conflitos de replica\u00e7\u00e3o. E tudo funciona bem com os relat\u00f3rios.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/ee3c315168bdd3f392d2e8a1c5861004.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E o que est\u00e1 acontecendo com o servidor Master nesse momento? O que ocorre com o servidor Master \u00e9 um desastre total. Agora observamos os gr\u00e1ficos ap\u00f3s ativar essas duas configura\u00e7\u00f5es. E vemos que a sess\u00e3o na r\u00e9plica de alguma forma come\u00e7ou a influenciar a situa\u00e7\u00e3o no servidor Master. Ela realmente influencia, pois interrompeu o autovacuum, que remove linhas mortas. O tamanho da tabela disparou novamente. O tempo m\u00e9dio de execu\u00e7\u00e3o das consultas em toda a base de dados tamb\u00e9m disparou. Os autovacuums ficaram um pouco sobrecarregados. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/980611dcce8b189dc50f422ffd3d2d72.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Especificamente em rela\u00e7\u00e3o \u00e0 nossa tabela, vemos que a atualiza\u00e7\u00e3o dos dados nela tamb\u00e9m disparou. O consumo de recursos do processador aumentou significativamente. Estamos revisando um grande n\u00famero de linhas mortas e in\u00fateis. E o tempo de resposta desta tabela, o n\u00famero de transa\u00e7\u00f5es caiu. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/a648fd313a5dccf45f0056dc13c54263.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Como isso se parecer\u00e1 se n\u00e3o soubermos do que estou falando at\u00e9 agora?<\/p>\n<p><\/p>\n<ul>\n<li>Estamos come\u00e7ando a buscar problemas. Se encontramos problemas na primeira parte, sabemos que isso pode ser causado por uma transa\u00e7\u00e3o longa e temos que verificar o Master. O problema est\u00e1 no Master. Ele est\u00e1 inst\u00e1vel. Ele est\u00e1 esquentando e sua m\u00e9dia de carga est\u00e1 perto de cem. <\/li>\n<li>As requisi\u00e7\u00f5es l\u00e1 est\u00e3o lentas, mas n\u00e3o vemos nenhuma transa\u00e7\u00e3o longa. E n\u00e3o entendemos qual \u00e9 o problema. N\u00e3o sabemos onde procurar. <\/li>\n<li>Estamos verificando o hardware do servidor. Pode ser que o RAID tenha falhado. Pode ser que uma pe\u00e7a da mem\u00f3ria tenha queimado. Qualquer coisa pode estar acontecendo. Mas n\u00e3o, os servidores s\u00e3o novos, tudo est\u00e1 funcionando perfeitamente. <\/li>\n<li>Todos est\u00e3o correndo: administradores, desenvolvedores e o diretor. Nada ajuda. <\/li>\n<li>E em algum momento tudo come\u00e7a a se corrigir inesperadamente. <\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/7d4f6417bc5cb3cec33679d843c6661d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Na r\u00e9plica, enquanto isso, uma requisi\u00e7\u00e3o foi processada e enviada. Recebemos um relat\u00f3rio. O neg\u00f3cio ainda est\u00e1 satisfeito. Como podemos ver, nossa tabela cresceu novamente e n\u00e3o est\u00e1 diminuindo. No gr\u00e1fico de sess\u00f5es, deixei uma parte desta longa transa\u00e7\u00e3o da r\u00e9plica para que voc\u00ea possa avaliar quanto tempo leva at\u00e9 que a situa\u00e7\u00e3o se estabilize. <\/p>\n<p><\/p>\n<p>A sess\u00e3o se foi. E s\u00f3 depois de algum tempo o servidor come\u00e7a a se normalizar. E o tempo m\u00e9dio de resposta das requisi\u00e7\u00f5es no servidor Master volta ao normal. Porque, finalmente, o autovacuum teve a oportunidade de limpar e marcar essas linhas mortas. E ele come\u00e7ou a fazer seu trabalho. E qu\u00e3o r\u00e1pido ele faz isso, t\u00e3o r\u00e1pido voltaremos ao normal.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/547d195e08de1566da818150a47218eb.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Na tabela testada, onde atualizamos os saldos das contas, vemos exatamente a mesma imagem. O tempo m\u00e9dio de atualiza\u00e7\u00e3o da conta tamb\u00e9m se normaliza gradualmente. Os recursos consumidos pela CPU tamb\u00e9m diminuem. E o n\u00famero de transa\u00e7\u00f5es por segundo retorna ao normal. Mas novamente, n\u00e3o ao mesmo normal que t\u00ednhamos antes da falha. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/29372a5e9124690931485a7aea65befc.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>De qualquer forma, estamos enfrentando uma queda de desempenho, assim como na primeira vez, de uma vez e meia a duas vezes, \u00e0s vezes at\u00e9 mais. <\/p>\n<p><\/p>\n<p>Aparentemente fizemos tudo certo. Distribu\u00edmos a carga. O hardware n\u00e3o est\u00e1 ocioso. Distribu\u00edmos inteligentemente as requisi\u00e7\u00f5es, mas ainda assim, tudo acabou mal. <\/p>\n<p><\/p>\n<ul>\n<li>N\u00e3o ativar hot_standby_feedback? Sim, n\u00e3o \u00e9 recomendado ativ\u00e1-lo sem uma raz\u00e3o forte. Isso porque esse recurso impacta diretamente o Servidor Principal e interrompe o funcionamento do autovacuum nele. Se voc\u00ea ativ\u00e1-lo em uma r\u00e9plica e esquecer, pode prejudicar o Servidor Principal e enfrentar grandes problemas com o aplicativo. <\/li>\n<li>Aumentar max_standby_streaming_delay? Sim, isso \u00e9 verdade para relat\u00f3rios. Se voc\u00ea tem um relat\u00f3rio de tr\u00eas horas e n\u00e3o quer que ele falhe devido a conflitos de replica\u00e7\u00e3o, simplesmente aumente a lat\u00eancia. Relat\u00f3rios longos nunca exigem dados que acabaram de chegar ao banco de dados. Se voc\u00ea est\u00e1 rodando um relat\u00f3rio de tr\u00eas horas, significa que est\u00e1 obtendo dados de um per\u00edodo passado. E ter uma lat\u00eancia de tr\u00eas horas ou seis horas n\u00e3o far\u00e1 diferen\u00e7a, mas assim voc\u00ea receber\u00e1 os relat\u00f3rios de forma consistente e evitar\u00e1 problemas de falhas. <\/li>\n<li>Naturalmente, \u00e9 necess\u00e1rio controlar sess\u00f5es longas nas r\u00e9plicas, especialmente se voc\u00ea decidiu ativar hot_standby_feedback na r\u00e9plica. Porque pode acontecer de tudo. Damos essa r\u00e9plica a um desenvolvedor para que ele teste as consultas. Ele escreve uma consulta complexa, executa e vai tomar um ch\u00e1, enquanto n\u00f3s ficamos com o Servidor Principal sobrecarregado. Ou deixamos um aplicativo inadequado rodar. As situa\u00e7\u00f5es s\u00e3o variadas. As sess\u00f5es nas r\u00e9plicas devem ser monitoradas t\u00e3o rigorosamente quanto nas do Servidor Principal. <\/li>\n<li>E se voc\u00ea tiver consultas r\u00e1pidas e longas nas r\u00e9plicas, neste caso, \u00e9 melhor dividir a carga. Isso se relaciona ao streaming_delay. Para consultas r\u00e1pidas, tenha uma r\u00e9plica com um pequeno atraso na replica\u00e7\u00e3o. Para relat\u00f3rios longos, use uma r\u00e9plica que possa estar atrasada em at\u00e9 6 horas ou um dia. Isso \u00e9 uma situa\u00e7\u00e3o perfeitamente normal. <\/li>\n<\/ul>\n<p><\/p>\n<p>Eliminamos as consequ\u00eancias da mesma forma:<\/p>\n<p><\/p>\n<ul>\n<li>Encontramos tabelas crescidas.<\/li>\n<li>E as comprimimos com a ferramenta mais adequada para n\u00f3s. <\/li>\n<\/ul>\n<p><\/p>\n<p>A segunda hist\u00f3ria termina aqui. Vamos para a terceira hist\u00f3ria. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/c8784e0be27883640cb8f6919a1c25e0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Esta tamb\u00e9m \u00e9 bastante comum para n\u00f3s, na qual realizamos uma migra\u00e7\u00e3o. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/a04b9cd88a0e7e8a3b960ef930eb2657.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<ul>\n<li>Qualquer produto de software cresce. Os requisitos para ele mudam. N\u00f3s, de qualquer forma, queremos evoluir. E acontece que precisamos atualizar os dados na tabela, ou seja, executar uma atualiza\u00e7\u00e3o no contexto da nossa migra\u00e7\u00e3o para a nova funcionalidade que estamos implementando como parte do nosso desenvolvimento. <\/li>\n<li>O formato antigo de dados n\u00e3o \u00e9 aceit\u00e1vel. Suponha que agora iremos para a segunda tabela, onde tenho opera\u00e7\u00f5es nessas contas. E, suponha que estavam em rublos, mas decidimos aumentar a precis\u00e3o e fazer em copeques. E para isso precisamos fazer uma atualiza\u00e7\u00e3o: multiplicar o campo com o valor da opera\u00e7\u00e3o por cem. <\/li>\n<li>No mundo moderno, usamos ferramentas automatizadas de controle de vers\u00f5es de banco de dados. Suponha que <noindex><a rel=\"nofollow\" href=\"https:\/\/www.liquibase.org\/\">Liquibase<\/a><\/noindex>. Escrevemos nossa migra\u00e7\u00e3o. Testamos na nossa base de testes. Tudo \u00f3timo. A atualiza\u00e7\u00e3o acontece. Bloqueia o trabalho por um tempo, mas, em compensa\u00e7\u00e3o, obtemos dados atualizados. E podemos lan\u00e7ar novas funcionalidades a partir disso. Tudo foi testado e verificado. Todos confirmaram. <\/li>\n<li>Realizamos manuten\u00e7\u00f5es programadas, realizamos a migra\u00e7\u00e3o. <\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/9e046583f7b1723fc1eaf61a03900918.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Aqui est\u00e1 a migra\u00e7\u00e3o com a atualiza\u00e7\u00e3o apresentada para voc\u00ea. Como se trata de opera\u00e7\u00f5es de contas, a tabela tinha 15 GB. E como estamos atualizando cada linha, a atualiza\u00e7\u00e3o dobrou o tamanho da tabela, porque regravamos cada linha. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/06120c98ea43d0568045e71935c23592.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Durante a migra\u00e7\u00e3o, n\u00e3o pudemos fazer nada com esta tabela, porque todas as consultas a ela ficaram enfileiradas e aguardando a conclus\u00e3o desta atualiza\u00e7\u00e3o. Mas aqui gostaria de chamar sua aten\u00e7\u00e3o aos n\u00fameros que est\u00e3o no eixo vertical. Ou seja, temos um tempo m\u00e9dio de consulta antes da migra\u00e7\u00e3o em torno de 5 milissegundos e uma carga no processador, n\u00famero de opera\u00e7\u00f5es de leitura de mem\u00f3ria do disco menor do que 7,5. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/69a3ba4d1d0cec7d39284e09e9d3055b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Realizamos a migra\u00e7\u00e3o e novamente encontramos problemas. <\/p>\n<p><\/p>\n<p>A migra\u00e7\u00e3o foi bem-sucedida, mas:<\/p>\n<p><\/p>\n<ul>\n<li>A funcionalidade antiga come\u00e7ou a demorar mais. <\/li>\n<li>A tabela cresceu novamente em tamanho. <\/li>\n<li>A carga no servidor tornou-se maior do que era antes. <\/li>\n<li>E, naturalmente, enquanto ainda estamos lidando com a funcionalidade que funcionava bem, a melhoramos um pouco. <\/li>\n<\/ul>\n<p><\/p>\n<p>E isso \u00e9 novamente um bloat que estraga nossa vida mais uma vez. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/becd7cce3a1c8821c81c96257f41202b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Aqui demonstro que a tabela, como nos dois casos anteriores, n\u00e3o est\u00e1 disposta a retornar aos tamanhos anteriores. A carga m\u00e9dia no servidor parece adequada. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/4d703a60d43a3460bc3782d49865b690.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Se olharmos para a tabela de contas, veremos que o tempo m\u00e9dio de solicita\u00e7\u00e3o dobrou para esta tabela. A carga no processador e a quantidade de linhas percorridas na mem\u00f3ria subiram acima de 7,5, quando antes estava abaixo disso. E houve um aumento de duas vezes no caso dos processadores e de 1,5 vezes em opera\u00e7\u00f5es em bloco, ou seja, tivemos uma degrada\u00e7\u00e3o do desempenho do servidor. E, como consequ\u00eancia, uma degrada\u00e7\u00e3o do desempenho do nosso aplicativo. Entretanto, o n\u00famero de chamadas permaneceu aproximadamente no mesmo n\u00edvel. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/80772afa0643b29f5314a2482c9dfe0d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Aqui, o principal \u00e9 entender como fazer essas migra\u00e7\u00f5es corretamente. E elas precisam ser feitas. N\u00f3s realizamos essas migra\u00e7\u00f5es de forma bastante consistente.<\/p>\n<p><\/p>\n<ul>\n<li>Migra\u00e7\u00f5es grandes como essas n\u00e3o s\u00e3o feitas automaticamente. Elas devem sempre ser controladas. <\/li>\n<li>\u00c9 necess\u00e1rio ter um controle por parte de uma pessoa experiente. Se voc\u00ea tem um DBA na equipe, que ele fa\u00e7a isso. \u00c9 o trabalho dele. Se n\u00e3o houver, que a pessoa mais experiente a fa\u00e7a, aquela que sabe trabalhar com bancos de dados. <\/li>\n<li>Um novo esquema de banco de dados, mesmo que estejamos atualizando apenas uma coluna, sempre preparamos em etapas, ou seja, antecipadamente antes de lan\u00e7armos a nova vers\u00e3o do aplicativo:<\/li>\n<li>Novos campos s\u00e3o adicionados, onde vamos registrar os dados atualizados. <\/li>\n<li>Transferimos dados do campo antigo para o novo campo em pequenas partes. Por que fazemos isso? Primeiro, sempre controlamos o processo. Sabemos que j\u00e1 transferimos tantos lotes e quanto nos resta. <\/li>\n<li>Um segundo efeito positivo \u00e9 que entre cada lote, encerramos a transa\u00e7\u00e3o, abrimos uma nova, e isso permite que o autovacuum funcione na tabela, marcando as linhas mortas para reutiliza\u00e7\u00e3o. <\/li>\n<li>Para as linhas que aparecer\u00e3o durante o funcionamento do aplicativo (ainda temos o aplicativo antigo rodando), adicionamos um gatilho que registra novos valores nos novos campos. No nosso caso, isso \u00e9 multiplicar o valor antigo por cem. <\/li>\n<li>Se quisermos o mesmo campo, ent\u00e3o, ap\u00f3s a conclus\u00e3o de todas as migra\u00e7\u00f5es e antes do lan\u00e7amento da nova vers\u00e3o do aplicativo, simplesmente renomeamos os campos. Os antigos para algum nome inventado e os novos campos para os antigos. <\/li>\n<li>E s\u00f3 depois disso lan\u00e7amos a nova vers\u00e3o do aplicativo. <\/li>\n<\/ul>\n<p><\/p>\n<p>E assim n\u00e3o teremos incha\u00e7o e n\u00e3o sofreremos uma queda no desempenho. <\/p>\n<p><\/p>\n<p>Aqui termina a terceira hist\u00f3ria. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2afab2906b5ccd30e4c8772248818057.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dataegret\/pg-utils\/blob\/master\/sql\/table_bloat.sql\">https:\/\/github.com\/dataegret\/pg-utils\/blob\/master\/sql\/table_bloat.sql<\/a><\/noindex><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dataegret\/pg-utils\/blob\/master\/sql\/table_bloat_approx.sql\">https:\/\/github.com\/dataegret\/pg-utils\/blob\/master\/sql\/table_bloat_approx.sql<\/a><\/noindex><\/p>\n<p><\/p>\n<p>E agora, um pouco mais detalhadamente sobre as ferramentas que mencionei na primeira hist\u00f3ria. <\/p>\n<p><\/p>\n<p>Antes de procurar por bloat, \u00e9 essencial instalar a extens\u00e3o. <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/pgstattuple.html\">pgstattuple<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Para que voc\u00ea n\u00e3o precise criar consultas, j\u00e1 escrevemos essas consultas em nosso trabalho. Voc\u00ea pode utiliz\u00e1-las. Aqui est\u00e3o apresentadas duas consultas. <\/p>\n<p><\/p>\n<ul>\n<li>A primeira funciona por um tempo consider\u00e1vel, mas oferece os valores exatos de bloat na tabela. <\/li>\n<li>A segunda \u00e9 mais r\u00e1pida e muito eficaz quando voc\u00ea precisa avaliar rapidamente se h\u00e1 bloat na tabela ou n\u00e3o. E voc\u00ea deve entender que o bloat nas tabelas do Postgres est\u00e1 sempre presente. \u00c9 uma caracter\u00edstica do seu modelo MVCC. <\/li>\n<li>E 20% de bloat \u00e9 normal para tabelas na maioria dos casos. Ou seja, voc\u00ea n\u00e3o precisa se preocupar e comprimir essa tabela. <\/li>\n<\/ul>\n<p><\/p>\n<p>Como identificar tabelas que est\u00e3o incharam, n\u00f3s j\u00e1 entendemos, mesmo que tenham crescido com dados in\u00fateis. <\/p>\n<p><\/p>\n<p>Agora, sobre como corrigir o bloat:<\/p>\n<p><\/p>\n<ul>\n<li>Se temos uma tabela pequena e bons discos, ou seja, para tabelas de at\u00e9 um gigabyte, \u00e9 perfeitamente vi\u00e1vel usar o VACUUM FULL. Ele vai precisar obter um bloqueio exclusivo na tabela por alguns segundos, e isto \u00e9 o suficiente, pois vai fazer tudo de forma r\u00e1pida e eficaz. O que faz o VACUUM FULL? Ele obt\u00e9m um bloqueio exclusivo na tabela e reescreve as linhas vivas de tabelas antigas para uma nova tabela. E, no final, troca-as de lugar. Ele apaga os arquivos antigos e insere os novos no lugar dos antigos. Mas durante sua execu\u00e7\u00e3o, ele ret\u00e9m um bloqueio exclusivo da tabela. Isso significa que voc\u00ea n\u00e3o conseguir\u00e1 fazer nada com essa tabela: nem escrever, nem ler, nem modificar. E o VACUUM FULL exige espa\u00e7o adicional em disco para gravar os dados.<\/li>\n<li>A pr\u00f3xima ferramenta <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/reorg\/pg_repack\">pg_repack<\/a><\/noindex>\u00e9 bastante semelhante ao VACUUM FULL, pois tamb\u00e9m reescreve dados de arquivos antigos para novos e os substitui na tabela. Mas, ao contr\u00e1rio, n\u00e3o pega um bloqueio exclusivo na tabela desde o in\u00edcio de sua execu\u00e7\u00e3o; ele o obt\u00e9m apenas no momento em que j\u00e1 tem os dados prontos para substituir os arquivos. As exig\u00eancias de recursos em disco s\u00e3o similares \u00e0s do VACUUM FULL. Voc\u00ea precisa de espa\u00e7o adicional em disco, e isso pode ser cr\u00edtico, especialmente se suas tabelas forem de v\u00e1rios terabytes. Al\u00e9m disso, ele consome bastante CPU, pois realiza trabalho ativo de entrada e sa\u00edda. <\/li>\n<li>A terceira ferramenta \u00e9 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dataegret\/pgcompacttable\">pgcompacttable<\/a><\/noindex>. Ela utiliza os recursos de forma mais eficiente, pois funciona um pouco de maneira diferente. O principal aspecto do pgcompacttable \u00e9 que, com as atualiza\u00e7\u00f5es na tabela, ela move todas as linhas ativas para o in\u00edcio da tabela. E ent\u00e3o executa um vacuum nessa tabela, porque sabemos que no in\u00edcio est\u00e3o as linhas ativas e no final est\u00e3o as linhas mortas. E o vacuum j\u00e1 corta essa parte final, ou seja, n\u00e3o requer muito espa\u00e7o extra em disco. E ainda por cima, ele pode ser ajustado para consumir menos recursos. <\/li>\n<\/ul>\n<p><\/p>\n<p>Com as ferramentas, est\u00e1 tudo certo. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Erros comuns em aplicativos que levam ao bloat no PostgreSQL. Andrei Salnikov\" src=\"\/wp-content\/uploads\/2020\/05\/4187915e54e54a0b85a342fe0280f78f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Se o tema do bloat parecer interessante para voc\u00ea explorar mais a fundo, aqui est\u00e3o alguns links \u00fateis:<\/p>\n<p><\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/www.slideshare.net\/alexius2Mb\/where-is-the-space-postgres\">https:\/\/www.slideshare.net\/alexius2Mb\/where-is-the-space-postgres<\/a><\/noindex> \u2013 esta \u00e9 a apresenta\u00e7\u00e3o do meu colega. Ele \u00e9 geral sobre onde o espa\u00e7o vai no Postgres durante seu funcionamento e vida. E l\u00e1 h\u00e1 uma parte t\u00e9cnica muito extensa e detalhada para administradores de bancos de dados sobre bloat. <\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dataegret\/pg-utils\">https:\/\/github.com\/dataegret\/pg-utils<\/a><\/noindex> \u2013 este \u00e9 o link para nosso reposit\u00f3rio, onde armazenamos uma s\u00e9rie de scripts \u00fateis para verificar o estado do banco de dados. Voc\u00ea pode encontrar scripts para buscar bloat l\u00e1. <\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/reorg\/pg_repack\">Terceiro<\/a><\/noindex> e <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dataegret\/pgcompacttable\">quatro<\/a><\/noindex> links para ferramentas que ajudar\u00e3o voc\u00ea a compactar tabelas. <\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/blog.dataegret.com\/2Mb018\/03\/postgresql-bloatbusters.html\">http:\/\/blog.dataegret.com\/2Mb018\/03\/postgresql-bloatbusters.html<\/a><\/noindex> \u2013 este \u00e9 um post do meu colega. Ele analisa t\u00e9cnica e detalhadamente o bloat, j\u00e1 em um n\u00edvel mais pr\u00f3ximo dos administradores. <\/li>\n<\/ul>\n<p><\/p>\n<p>Eu tentei mais mostrar um alerta para os desenvolvedores, pois eles s\u00e3o nossos principais clientes de banco de dados e precisam entender quais a\u00e7\u00f5es levam a que resultados. Espero ter conseguido. Obrigado pela aten\u00e7\u00e3o!<\/p>\n<p><\/p>\n<p>Perguntas<\/p>\n<p><\/p>\n<p><em>Obrigado pela apresenta\u00e7\u00e3o! Voc\u00ea falou sobre como identificar problemas. E como podemos preveni-los? Ou seja, eu tive uma situa\u00e7\u00e3o em que as consultas estavam travadas n\u00e3o apenas porque acessavam algum servi\u00e7o externo. Eram apenas algumas jun\u00e7\u00f5es muito complexas. Havia algumas consultas pequenas e inofensivas que ficaram travadas por um dia, e depois come\u00e7aram a causar problemas. Isso est\u00e1 muito parecido com o que voc\u00ea descreveu. Como monitorar isso? Precisamos ficar constantemente olhando para uma consulta travada? Como podemos evitar isso?<\/em><\/p>\n<p><\/p>\n<p>Nesse caso, \u00e9 uma tarefa para os administradores da sua empresa, n\u00e3o necessariamente para o DBA.<\/p>\n<p><\/p>\n<p><em>Eu sou administrador.<\/em><\/p>\n<p><\/p>\n<p>No PostgreSQL, existe uma visualiza\u00e7\u00e3o chamada pg_stat_activity, que mostra as consultas pendentes. E voc\u00ea pode ver h\u00e1 quanto tempo elas est\u00e3o travadas.<\/p>\n<p><\/p>\n<p><em>Eu preciso entrar a cada 5 minutos para verificar?<\/em><\/p>\n<p><\/p>\n<p>Configure cron and monitor it. If you have a long-running query, send an email, and that's it. In other words, you don't need to watch it manually; this can be automated. You'll receive an email, and you react to it. Alternatively, you can set automatic triggers.<\/p>\n<p><\/p>\n<p><em>Are there clear reasons why this is happening?<\/em><\/p>\n<p><\/p>\n<p>I listed some. Others are more complex. It could lead to a lengthy discussion.<\/p>\n<p><\/p>\n<p><em>Thank you for your presentation! I wanted to clarify about the pg_repack utility. If it doesn't acquire exclusive locks, then\u2026<\/em><\/p>\n<p><\/p>\n<p>It does acquire exclusive locks. <\/p>\n<p><\/p>\n<p>\u2026 <em>then I could potentially lose data. My application shouldn't write anything during that time?<\/em><\/p>\n<p><\/p>\n<p>No, it can work with the table without issues. Pg_repack first moves all live rows. Naturally, there will be some writing to the table. It simply appends that tail. <\/p>\n<p><\/p>\n<p><em>So, it does that in the end?<\/em><\/p>\n<p><\/p>\n<p>In the end, it takes an exclusive lock to swap those files. <\/p>\n<p><\/p>\n<p><em>Will this be faster than VACUUM FULL?<\/em><\/p>\n<p><\/p>\n<p>VACUUM FULL, once started, immediately acquires an exclusive lock. And it won\u2019t release it until it's done. Pg_repack only takes an exclusive lock during the file replacement. At that moment, you won't be able to write there, but no data will be lost; everything will be fine. <\/p>\n<p><\/p>\n<p><em>Hello! You talked about the autovacuum's operation. There was a chart with red, yellow, and green recorded cells. So, yellow ones are marked as deleted. Consequently, can something new be written into them?<\/em><\/p>\n<p><\/p>\n<p>Yes. Postgres doesn't delete rows; that's its peculiarity. If we update a row, we mark the old one as deleted. It shows the transaction ID that modified that row and we write a new row. We have sessions that can potentially read them. At some point, they become very old. The essence of autovacuum is to go through these rows and mark them as unnecessary. You can then overwrite that data. <\/p>\n<p><\/p>\n<p><em>I understand. But the question is a bit different. I didn't finish my thought. Let's say we have a table with variable-sized fields. If I try to insert something new, it might simply not fit into the old cell.<\/em> <\/p>\n<p><\/p>\n<p>N\u00e3o, de qualquer forma, toda a linha ser\u00e1 atualizada. No Postgres, existem dois modelos de armazenamento de dados. Ele escolhe com base no tipo de dados. Existem dados que s\u00e3o armazenados diretamente na tabela e outros dados tos. Estes s\u00e3o grandes volumes de dados: texto, json. Eles s\u00e3o armazenados em tabelas separadas. E nessas tabelas ocorre a mesma quest\u00e3o de bloat, ou seja, tudo \u00e9 igual. Apenas est\u00e3o separados. <\/p>\n<p><\/p>\n<p><em>Obrigado pela apresenta\u00e7\u00e3o! Qual a aceitabilidade de usar o statement timeout para limitar a dura\u00e7\u00e3o das consultas?<\/em><\/p>\n<p><\/p>\n<p>\u00c9 bastante aceit\u00e1vel. N\u00f3s usamos isso em todos os lugares. E como n\u00e3o temos nossos pr\u00f3prios servi\u00e7os, fornecemos suporte remoto, ent\u00e3o temos clientes bastante variados. E todos ficam bastante satisfeitos com isso. Ou seja, temos tarefas no cron que verificam. Apenas combinamos a dura\u00e7\u00e3o das sess\u00f5es com o cliente, que n\u00e3o podemos encerrar antes do tempo definido. Pode ser um minuto ou dez minutos. Isso depende da carga na base de dados e de seu objetivo. Mas todos usamos pg_stat_activity.<\/p>\n<p><\/p>\n<p><em>Obrigado pela apresenta\u00e7\u00e3o! Estou tentando aplicar sua palestra aos meus aplicativos. E parece que em todos os lugares n\u00f3s iniciamos transa\u00e7\u00f5es e as encerramos explicitamente. Se houver alguma exce\u00e7\u00e3o, o rollback ainda ocorre. E aqui eu fiquei pensando. Afinal, uma transa\u00e7\u00e3o pode ser iniciada de forma n\u00e3o expl\u00edcita. \u00c9 uma dica para a garota, provavelmente. Se eu apenas fa\u00e7o uma atualiza\u00e7\u00e3o de registro, a transa\u00e7\u00e3o come\u00e7ar\u00e1 no PostgreSQL e s\u00f3 ser\u00e1 conclu\u00edda quando a conex\u00e3o for encerrada?<\/em><\/p>\n<p><\/p>\n<p>Se voc\u00ea est\u00e1 falando agora sobre o n\u00edvel do aplicativo, isso depende do driver que voc\u00ea est\u00e1 usando, da ORM que est\u00e1 em uso. H\u00e1 muitas configura\u00e7\u00f5es. Se o auto commit estiver ativado, ent\u00e3o a transa\u00e7\u00e3o come\u00e7a e logo em seguida \u00e9 encerrada.<\/p>\n<p><\/p>\n<p><em>Ou seja, ela \u00e9 encerrada imediatamente ap\u00f3s a atualiza\u00e7\u00e3o?<\/em><\/p>\n<p><\/p>\n<p>Isso depende das configura\u00e7\u00f5es. Eu mencionei uma configura\u00e7\u00e3o. Essa \u00e9 a auto commit on. Ela \u00e9 bastante comum. Se estiver ativada, a transa\u00e7\u00e3o \u00e9 aberta e fechada. Se voc\u00ea n\u00e3o disser explicitamente 'start transaction' e 'end transaction', mas apenas executar uma consulta na sess\u00e3o. <\/p>\n<p><\/p>\n<p><em>Ol\u00e1! Obrigado pela apresenta\u00e7\u00e3o! Suponha que temos um banco de dados que est\u00e1 crescendo e de repente o servidor fica sem espa\u00e7o. Existem ferramentas para corrigir essa situa\u00e7\u00e3o?<\/em> <\/p>\n<p><\/p>\n<p>O espa\u00e7o no servidor deve ser monitorado corretamente. <\/p>\n<p><\/p>\n<p><em>Por exemplo, o DBA foi tomar um ch\u00e1, estava de f\u00e9rias, etc.<\/em><\/p>\n<p><\/p>\n<p>Quando um sistema de arquivos \u00e9 criado, ele sempre reserva algum espa\u00e7o, onde os dados n\u00e3o s\u00e3o escritos. <\/p>\n<p><\/p>\n<p><em>E se for completamente zero?<\/em><\/p>\n<p><\/p>\n<p>Esse espa\u00e7o \u00e9 chamado de espa\u00e7o reservado, ou seja, ele pode ser liberado e, dependendo de qu\u00e3o grande ele foi criado, voc\u00ea ter\u00e1 espa\u00e7o livre. Por padr\u00e3o, eu n\u00e3o sei quanto h\u00e1 l\u00e1. Em outro caso, \u00e9 preciso fornecer discos para ter espa\u00e7o para realizar a opera\u00e7\u00e3o de recupera\u00e7\u00e3o. Voc\u00ea pode excluir alguma tabela que definitivamente n\u00e3o \u00e9 necess\u00e1ria. <\/p>\n<p><\/p>\n<p><em>N\u00e3o h\u00e1 outras ferramentas?<\/em><\/p>\n<p><\/p>\n<p>Isso \u00e9 sempre um trabalho manual. E \u00e9 no local que se determina o que \u00e9 melhor fazer, pois existem dados cr\u00edticos e n\u00e3o cr\u00edticos. E para cada banco de dados e aplica\u00e7\u00e3o que trabalha com ele, isso depende do neg\u00f3cio. Sempre se decide no local. <\/p>\n<p><\/p>\n<p><em>Obrigado pela apresenta\u00e7\u00e3o! Eu tenho duas perguntas. Primeiro, voc\u00ea mostrou slides onde foi demonstrado que, em caso de transa\u00e7\u00f5es pendentes, tanto o volume do espa\u00e7o da tabela quanto o tamanho do \u00edndice aumentam. E depois na apresenta\u00e7\u00e3o havia v\u00e1rias utilit\u00e1rios que compactam a tabela. E quanto ao \u00edndice?<\/em><\/p>\n<p><\/p>\n<p>Eles tamb\u00e9m os compactam. <\/p>\n<p><\/p>\n<p><em>Mas o vacuum n\u00e3o afeta o \u00edndice?<\/em><\/p>\n<p><\/p>\n<p>Alguns trabalham com o \u00edndice. Por exemplo, pg_rapack, pgcompacttable. O vacuum recria os \u00edndices, afeta-os. O VACUUM FULL tem a ess\u00eancia de reescrever tudo, ou seja, ele trabalha com todos. <\/p>\n<p><\/p>\n<p><em>E a segunda pergunta. Eu n\u00e3o entendi por que os relat\u00f3rios nas r\u00e9plicas dependem tanto da pr\u00f3pria replica\u00e7\u00e3o. Eu pensei que os relat\u00f3rios eram leitura, e a replica\u00e7\u00e3o era grava\u00e7\u00e3o.<\/em> <\/p>\n<p><\/p>\n<p>Onde ocorre o conflito de replica\u00e7\u00e3o? Temos o Master, onde ocorrem os processos. Temos o autovacuum. O autovacuum, na verdade, o que faz? Ele elimina algumas linhas antigas. Se nesse momento em que est\u00e1 sendo feito na r\u00e9plica, h\u00e1 uma consulta que l\u00ea essas linhas antigas, mas no Master ocorreu uma situa\u00e7\u00e3o em que o autovacuum marcou essas linhas como poss\u00edveis para regrava\u00e7\u00e3o, ent\u00e3o n\u00f3s as regravamos. E recebemos um pacote de dados, quando devemos regravar as linhas que s\u00e3o necess\u00e1rias para a consulta na r\u00e9plica, o processo de replica\u00e7\u00e3o aguardar\u00e1 o timeout que voc\u00ea configurou. E ent\u00e3o o PostgreSQL decidir\u00e1 o que \u00e9 mais importante para ele. E a replica\u00e7\u00e3o \u00e9 mais importante para ele do que a consulta, ent\u00e3o ele descartar\u00e1 a consulta para realizar essas altera\u00e7\u00f5es na r\u00e9plica. <\/p>\n<p><\/p>\n<p><em>Andr\u00e9, tenho uma pergunta. Esses gr\u00e1ficos incr\u00edveis que voc\u00ea mostrou durante a apresenta\u00e7\u00e3o, s\u00e3o resultado do trabalho de alguma das suas ferramentas? Como foram feitos esses gr\u00e1ficos?<\/em><\/p>\n<p><\/p>\n<p>Este \u00e9 um servi\u00e7o <noindex><a rel=\"nofollow\" href=\"https:\/\/okmeter.io\/\">Okmeter<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p><em>\u00c9 um produto comercial?<\/em><\/p>\n<p><\/p>\n<p>Sim. \u00c9 um produto comercial.<\/p>\n<p>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/501040\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043d\u0430\u0447\u0430\u043b\u0430 2016 \u0433\u043e\u0434\u0430 \u0410\u043d\u0434\u0440\u0435\u044f \u0421\u0430\u043b\u044c\u043d\u0438\u043a\u043e\u0432\u0430 &quot;\u0422\u0438\u043f\u043e\u0432\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0435\u0434\u0443\u0442 \u043a bloat \u0432 postgresql&quot; \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0434\u043e\u043a\u043b\u0430\u0434\u0435 \u044f \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0442 \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0418 \u0432\u043e\u0437\u044c\u043c\u0443 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435 \u043e\u0448\u0438\u0431\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0435\u0434\u0443\u0442 \u043a bloat \u0432 Postgresql. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u044d\u0442\u043e \u043d\u0430\u0447\u0430\u043b\u043e \u043a\u043e\u043d\u0446\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":81090,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-81089","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043d\u0430\u0447\u0430\u043b\u0430 2016 \u0433\u043e\u0434\u0430 \u0410\u043d\u0434\u0440\u0435\u044f \u0421\u0430\u043b\u044c\u043d\u0438\u043a\u043e\u0432\u0430 &quot;\u0422\u0438\u043f\u043e\u0432\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0435\u0434\u0443\u0442 \u043a bloat \u0432 postgresql&quot; \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0434\u043e\u043a\u043b\u0430\u0434\u0435 \u044f \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/tipovye-oshibki-v-prilozheniyah-kotorye-vedut-k-bloat-v-postgresql-andrej-salnikov\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"pt_PT\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0422\u0438\u043f\u043e\u0432\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0435\u0434\u0443\u0442 \u043a bloat \u0432 postgresql. \u0410\u043d\u0434\u0440\u0435\u0439 \u0421\u0430\u043b\u044c\u043d\u0438\u043a\u043e\u0432 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043d\u0430\u0447\u0430\u043b\u0430 2016 \u0433\u043e\u0434\u0430 \u0410\u043d\u0434\u0440\u0435\u044f \u0421\u0430\u043b\u044c\u043d\u0438\u043a\u043e\u0432\u0430 &quot;\u0422\u0438\u043f\u043e\u0432\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0435\u0434\u0443\u0442 \u043a bloat \u0432 postgresql&quot; \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0434\u043e\u043a\u043b\u0430\u0434\u0435 \u044f \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/tipovye-oshibki-v-prilozheniyah-kotorye-vedut-k-bloat-v-postgresql-andrej-salnikov\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-05-10T23:42:24+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-05-10T23:42:24+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47 Erros Comuns em Aplica\u00e7\u00f5es que Levam a Bloat no PostgreSQL. Andr\u00e9 Salnikov | ProHoster","description":"Sugiro que voc\u00ea veja a transcri\u00e7\u00e3o da palestra no in\u00edcio de 2016 de Andr\u00e9 Salnikov \"Erros Comuns em Aplica\u00e7\u00f5es que Levam a Bloat no PostgreSQL\". Nesta palestra, vou analisar os principais pontos.","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/tipovye-oshibki-v-prilozheniyah-kotorye-vedut-k-bloat-v-postgresql-andrej-salnikov","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pt_PT","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0422\u0438\u043f\u043e\u0432\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0435\u0434\u0443\u0442 \u043a bloat \u0432 postgresql. \u0410\u043d\u0434\u0440\u0435\u0439 \u0421\u0430\u043b\u044c\u043d\u0438\u043a\u043e\u0432 | ProHoster","og:description":"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043d\u0430\u0447\u0430\u043b\u0430 2016 \u0433\u043e\u0434\u0430 \u0410\u043d\u0434\u0440\u0435\u044f \u0421\u0430\u043b\u044c\u043d\u0438\u043a\u043e\u0432\u0430 &quot;\u0422\u0438\u043f\u043e\u0432\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0435\u0434\u0443\u0442 \u043a bloat \u0432 postgresql&quot; \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0434\u043e\u043a\u043b\u0430\u0434\u0435 \u044f \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435.","og:url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/tipovye-oshibki-v-prilozheniyah-kotorye-vedut-k-bloat-v-postgresql-andrej-salnikov","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-05-10T23:42:24+00:00","article:modified_time":"2020-05-10T23:42:24+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"81089","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 16:05:22","updated":"2022-09-27 16:01:50","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/81089","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/comments?post=81089"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/81089\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media\/81090"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=81089"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=81089"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=81089"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}