{"id":96515,"date":"2020-10-12T19:43:02","date_gmt":"2020-10-12T17:43:02","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/odyssey-roadmap-chto-eshhyo-my-hotim-ot-pulera-soedinenij-andrej-borodin-2019"},"modified":"2020-10-12T19:43:02","modified_gmt":"2020-10-12T17:43:02","slug":"odyssey-roadmap-chto-eshhyo-my-hotim-ot-pulera-soedinenij-andrej-borodin-2019","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/odyssey-roadmap-chto-eshhyo-my-hotim-ot-pulera-soedinenij-andrej-borodin-2019","title":{"rendered":"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/6c445191705a4c96939cd094bc457a53.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>No relat\u00f3rio, Andrei Borodin falar\u00e1 sobre como eles consideraram a experi\u00eancia de escalonamento do PgBouncer ao projetar o pooler de conex\u00f5es <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/yandex\/odyssey\">Odyssey<\/a><\/noindex>, como foi implementado em produ\u00e7\u00e3o. Al\u00e9m disso, discutiremos quais fun\u00e7\u00f5es do pooler gostar\u00edamos de ver nas novas vers\u00f5es: \u00e9 importante para n\u00f3s n\u00e3o apenas atender \u00e0s nossas necessidades, mas tamb\u00e9m desenvolver a comunidade de usu\u00e1rios <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/yandex\/odyssey\">Odiss\u00e9ia<\/a><\/noindex>.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>V\u00eddeo:<\/p>\n<p>\n<center><div class=\"youtube-placeholder\" data-id=\"OUx40ABHFZY\" onclick=\"loadVideo(this)\">\r\n        <img decoding=\"async\" src=\"https:\/\/img.youtube.com\/vi\/OUx40ABHFZY\/hqdefault.jpg\" alt=\"Por que no hosting comum a administra\u00e7\u00e3o do PrestaShop \u00e9 lenta, e no seu n\u00e3o \u00e9?\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/dd2ea50b72e3d9c4e795aecbf9afdd25.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ol\u00e1 a todos! Meu nome \u00e9 Andrei. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/0a2f1880005bec1f61b72fb23b555adc.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>No Yandex, estou envolvido no desenvolvimento de bancos de dados open source. E hoje temos um tema sobre o pooler de conex\u00f5es. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/c18e7c937423d2514faa12e820e78e70.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Se voc\u00ea souber como se chama pooler de conex\u00f5es em russo, por favor, me avise. Estou ansioso para encontrar um bom termo t\u00e9cnico que deva se consolidar na literatura t\u00e9cnica. <\/p>\n<p><\/p>\n<p>O tema \u00e9 bastante complicado, porque em muitos bancos de dados o pooler de conex\u00f5es j\u00e1 est\u00e1 integrado e voc\u00ea nem precisa saber sobre ele. Algumas configura\u00e7\u00f5es, \u00e9 claro, existem em todos os lugares, mas n\u00e3o funciona assim no Postgres. E, paralelamente (no HighLoad++ 2019), haver\u00e1 uma apresenta\u00e7\u00e3o de Nikolai Samokhvalov sobre a configura\u00e7\u00e3o de consultas no Postgres. E entendo que as pessoas que vieram aqui j\u00e1 configuraram consultas de maneira ideal, e s\u00e3o pessoas que enfrentam problemas sist\u00eamicos mais raros, relacionados \u00e0 rede e \u00e0 utiliza\u00e7\u00e3o de recursos. E em alguns pontos isso pode ser bastante complicado, uma vez que os problemas n\u00e3o s\u00e3o \u00f3bvios.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/89c660dd530575e2938e6bf312b83e95.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>No Yandex, temos o Postgres. No Yandex.Cloud, vivem muitos servi\u00e7os do Yandex. E temos v\u00e1rios petabytes de dados que geram n\u00e3o menos de um milh\u00e3o de consultas por segundo no Postgres. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/288bfa37b9dcd60acd22ba48f0ef8a39.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E fornecemos um cluster bastante padr\u00e3o para todos os servi\u00e7os - esta \u00e9 a principal inst\u00e2ncia do n\u00f3, duas r\u00e9plicas comuns (s\u00edncrona e ass\u00edncrona), backup e escalonamento de consultas de leitura na r\u00e9plica. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/c249ca55bb387e25a5560324024cc523.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Cada n\u00f3 do cluster \u00e9 um Postgres, no qual, al\u00e9m do Postgres e dos sistemas de monitoramento, tamb\u00e9m est\u00e1 instalado o pooler de conex\u00f5es. O pooler de conex\u00f5es \u00e9 utilizado para isolamento e para sua fun\u00e7\u00e3o principal. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/0e29be55cc048007db21c80bbb08a9d4.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Qual \u00e9 a fun\u00e7\u00e3o principal do pooler de conex\u00f5es? <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/e2fbbd440c2781573cb35deeef358f20.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>No Postgres, \u00e9 adotado um modelo de processos ao trabalhar com o banco de dados. Isso significa que uma conex\u00e3o \u00e9 um processo, um backend do Postgres. E nesse backend existem muitos caches diferentes, que s\u00e3o bastante caros para serem feitos de maneira distinta para diferentes conex\u00f5es. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/587498063b1af8fac4a845961c654bc2.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Al\u00e9m disso, no c\u00f3digo Postgres existe um array chamado procArray. Ele cont\u00e9m os dados principais sobre conex\u00f5es de rede. Quase todos os algoritmos de processamento do procArray t\u00eam complexidade linear, percorrendo todo o array de conex\u00f5es de rede. Este \u00e9 um ciclo bastante r\u00e1pido, mas com um grande n\u00famero de conex\u00f5es de rede, tudo se torna um pouco mais caro. E quando tudo fica um pouco mais caro, no final, voc\u00ea pode pagar um pre\u00e7o muito alto por um grande n\u00famero de conex\u00f5es. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/b534a38d0bfae7a65fc4258155a50280.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Existem 3 abordagens poss\u00edveis:<\/p>\n<p><\/p>\n<ul>\n<li>Do lado do aplicativo. <\/li>\n<li>Do lado do banco de dados. <\/li>\n<li>E entre os dois, ou seja, diversas combina\u00e7\u00f5es poss\u00edveis. <\/li>\n<\/ul>\n<p><\/p>\n<p>Infelizmente, o pooler embutido est\u00e1 atualmente em desenvolvimento. Os amigos da empresa PostgreSQL Professional est\u00e3o trabalhando principalmente nisso. Quando ele aparecer, \u00e9 dif\u00edcil prever. E, na verdade, temos duas solu\u00e7\u00f5es \u00e0 escolha do arquiteto. \u00c9 o pool de lado do aplicativo e o proxy pool. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/702527a09e9fc86dd39b7fd69dcf1fc9.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>O pool de lado do aplicativo \u00e9 a maneira mais simples. Quase todos os drivers de cliente oferecem uma maneira de representar milh\u00f5es de suas conex\u00f5es no c\u00f3digo como algumas dezenas de conex\u00f5es ao banco de dados. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/7b66b9e20d22f472ca5ac39f6b9e0ba4.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Surge o problema de que, em determinado momento, voc\u00ea quer escalar o backend, voc\u00ea deseja implant\u00e1-lo em v\u00e1rias m\u00e1quinas virtuais. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/f216fd7a8c01c2b07891e2242c48b06a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Depois voc\u00ea percebe que tem v\u00e1rias zonas de disponibilidade, v\u00e1rios data centers. E a abordagem com pooling do lado do cliente leva a n\u00fameros grandes. Grandes, cerca de 10.000 conex\u00f5es. Esse \u00e9 o limite que pode funcionar normalmente. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/e5bc5f284fd8ff568bbe16c3895b7ac6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Falando sobre poolers proxy, existem dois poolers que fazem muitas coisas. Eles n\u00e3o s\u00e3o apenas poolers. S\u00e3o poolers + mais uma funcionalidade legal. Isso \u00e9 <noindex><a rel=\"nofollow\" href=\"https:\/\/www.pgpool.net\/\">Pgpool<\/a><\/noindex> e <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CrunchyData\/crunchy-proxy\">Crunchy-Proxy<\/a><\/noindex>. <\/p>\n<p><\/p>\n<p>Mas, infelizmente, essa funcionalidade adicional n\u00e3o \u00e9 necess\u00e1ria para todos. E isso leva ao fato de que os poolers suportam apenas o pooling de sess\u00f5es, ou seja, um cliente de entrada, um cliente de sa\u00edda no banco de dados. <\/p>\n<p><\/p>\n<p>Para nossas tarefas, isso n\u00e3o \u00e9 muito adequado, portanto utilizamos o PgBouncer, que implementa o pooling de transa\u00e7\u00f5es, ou seja, as conex\u00f5es do servidor s\u00e3o mapeadas para as conex\u00f5es do cliente apenas durante o tempo de transa\u00e7\u00e3o. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/e5fedbe14656d2ac2cde8d1878a950e2.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E, sob nossa carga, isso \u00e9 verdade. <strong>Mas existem alguns problemas.<\/strong>.<img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/61fd36cadcd9948d624dafa711777307.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Os problemas come\u00e7am quando voc\u00ea quer diagnosticar uma sess\u00e3o, porque todas as conex\u00f5es de entrada s\u00e3o locais. Todas vieram do loopback e tra\u00e7ar a sess\u00e3o se torna complicado. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/36108c4956c410a1b1f286a88bc393d6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Claro, voc\u00ea pode usar application_name_add_host. Essa \u00e9 uma maneira do lado do Bouncer adicionar um endere\u00e7o IP ao application_name. Mas o application_name \u00e9 estabelecido por uma conex\u00e3o adicional. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/b4cec483aa776f48db7ad3966c3b78e4.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Neste gr\u00e1fico, a linha amarela representa as solicita\u00e7\u00f5es reais, enquanto a linha azul representa as solicita\u00e7\u00f5es que entram na base. E essa diferen\u00e7a \u00e9 exatamente a defini\u00e7\u00e3o do application_name, que \u00e9 necess\u00e1rio apenas para rastreamento, mas n\u00e3o \u00e9 gratuito. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/c02ea73a6f1a2a4cd6af6c621f321ab4.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Al\u00e9m disso, no Bouncer n\u00e3o \u00e9 poss\u00edvel limitar um pool, ou seja, o n\u00famero de conex\u00f5es ao banco de dados para um usu\u00e1rio espec\u00edfico em um banco de dados espec\u00edfico. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/3431a463e04106066e2799aead66f571.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>A que isso leva? Voc\u00ea tem um servi\u00e7o sobrecarregado, escrito em C++, e ali perto um pequeno servi\u00e7o em Node que n\u00e3o faz nada alarmante com o banco, mas seu driver enlouquece. Ele abre 20.000 conex\u00f5es, e todo o resto ter\u00e1 que esperar. Seu c\u00f3digo est\u00e1 normal. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/d7fa321714dc017b017945dffcf79bc6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Claro, escrevemos um pequeno patch para o Bouncer que adicionou essa configura\u00e7\u00e3o, ou seja, limitando os clientes a um pool. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/d58884fc5ac0f90ff8442f126972157a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Isso poderia ser feito do lado do Postgres, ou seja, restringindo os pap\u00e9is no banco de dados a um n\u00famero espec\u00edfico de conex\u00f5es.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/8d6ff70db72964ed4eae5eaa47309931.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Mas ent\u00e3o voc\u00ea perde a capacidade de entender por que n\u00e3o h\u00e1 conex\u00f5es com o servidor. O PgBouncer n\u00e3o propaga o erro de conex\u00e3o, ele sempre retorna a mesma informa\u00e7\u00e3o. E voc\u00ea n\u00e3o pode entender: talvez sua senha tenha mudado, talvez o banco simplesmente tenha ca\u00eddo, ou talvez algo esteja errado. Mas n\u00e3o h\u00e1 diagn\u00f3sticos. Se a sess\u00e3o n\u00e3o pode ser estabelecida, voc\u00ea n\u00e3o saber\u00e1 o motivo. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/cb3048344a94f2953bf403485d28e69f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Em determinado momento, voc\u00ea olha os gr\u00e1ficos do aplicativo e v\u00ea que ele n\u00e3o est\u00e1 funcionando.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/e67c6680bb9a7f41242af9f9e4920916.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Voc\u00ea verifica o topo e v\u00ea que o Bouncer \u00e9 de thread \u00fanica. Este \u00e9 um ponto de virada na vida do servi\u00e7o. Voc\u00ea percebe que se preparou para escalar o banco de dados em um ano e meio, mas precisa escalar o pooler. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/4c140c4ba6db19cb9939c1148638fb73.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Chegamos \u00e0 conclus\u00e3o de que precisamos de mais PgBouncers. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/d369f572a66c16a8917e13393324a644.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/lwn.net\/Articles\/542629\/\">https:\/\/lwn.net\/Articles\/542629\/<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Um pouco de patching foi feito no Bouncer. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/97755489a25ebfe38efd56ff897bd8fa.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E configuramos para que v\u00e1rios Bouncers pudessem ser levantados reutilizando a porta TCP. E o sistema operacional automaticamente distribui as conex\u00f5es TCP de entrada entre eles em round-robin.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/ac30d3f067de2a8cd66ad2325c3a3b58.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Isso \u00e9 transparente para os clientes, ou seja, tudo parece como se voc\u00ea tivesse um \u00fanico Bouncer, mas voc\u00ea tem fragmenta\u00e7\u00e3o de conex\u00f5es idle entre os Bouncers em execu\u00e7\u00e3o. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/53825f075db00b026c12013a610be456.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E em determinado momento, voc\u00ea pode perceber que estes 3 Bouncers est\u00e3o consumindo 100% de cada um de seus n\u00facleos. Voc\u00ea precisa de muitos Bouncers. Por qu\u00ea? <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/66c17883a043e157cd7ceab2c2a4e326.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Porque voc\u00ea tem TLS. Voc\u00ea tem uma conex\u00e3o criptografada. E se voc\u00ea comparar o Postgres com e sem TLS, descobrir\u00e1 que o n\u00famero de conex\u00f5es estabelecidas cai quase em dois ordens de magnitude com a inclus\u00e3o da criptografia, porque o handshake TLS consome recursos da CPU. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/6101121ebe136af16e5eb1a484c65d66.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E no pico, voc\u00ea pode ver v\u00e1rias fun\u00e7\u00f5es criptogr\u00e1ficas sendo executadas durante o fluxo de conex\u00f5es de entrada. Como nosso primary pode alternar entre zonas de disponibilidade, esse fluxo de conex\u00f5es de entrada \u00e9 uma situa\u00e7\u00e3o bastante comum. Ou seja, por algum motivo, o antigo primary estava indispon\u00edvel, e toda a carga foi enviada para outro datacenter. Eles chegar\u00e3o todos ao mesmo tempo para se cumprimentar com TLS. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/c238ac2f511568590dc275e01c192c00.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E um grande n\u00famero de handshakes TLS pode n\u00e3o apenas cumprimentar o Bouncer, mas pression\u00e1-lo. Devido ao timeout, o fluxo de conex\u00f5es de entrada pode se tornar sem fim. Se voc\u00ea tiver um retry no banco de dados sem exponential backoff, as conex\u00f5es voltar\u00e3o repetidamente de forma n\u00e3o coerente. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/f42d0b210174d4d172254603ae6b834a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Aqui est\u00e1 um exemplo de 16 PgBouncers que carregam 16 n\u00facleos a 100%.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/8d048d3774c09e5b6a3fb3c7bff62084.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Chegamos ao PgBouncer em cascata. Esta \u00e9 a melhor configura\u00e7\u00e3o que podemos alcan\u00e7ar em nossa carga com o Bouncer. Os Bouncers externos servem para o handshake TCP, enquanto os Bouncers internos servem para o verdadeiro pooling, para n\u00e3o fragmentar muito as conex\u00f5es externas.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/3a4ee4ea46d5fe8479a5a7222ee134da.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Com essa configura\u00e7\u00e3o, \u00e9 poss\u00edvel realizar um rein\u00edcio suave. Voc\u00ea pode reiniciar todos esses 18 Bouncers um por um. Mas manter essa configura\u00e7\u00e3o \u00e9 bastante desafiador. Administradores de sistemas, DevOps e pessoas que realmente s\u00e3o respons\u00e1veis por esse servidor n\u00e3o ficar\u00e3o muito felizes com esse esquema. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/5291fe67dbe02036f3ff8e98bdd84d1b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u00c0 primeira vista, poderia parecer que poder\u00edamos promover todas as nossas melhorias como open source, mas o Bouncer n\u00e3o \u00e9 muito bem suportado. Por exemplo, a capacidade de rodar v\u00e1rios PgBouncers na mesma porta foi commitada h\u00e1 um m\u00eas. E o pull request com essa funcionalidade foi feito h\u00e1 alguns anos. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/2059d7f49649d136249103db4aa3ec19.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/libpq-cancel.html\">https:\/\/www.postgresql.org\/docs\/current\/libpq-cancel.html<\/a><\/noindex><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pgbouncer\/pgbouncer\/pull\/79\">https:\/\/github.com\/pgbouncer\/pgbouncer\/pull\/79<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Ou outro exemplo. No Postgres, voc\u00ea pode cancelar uma consulta em execu\u00e7\u00e3o enviando um segredo por outra conex\u00e3o sem autentica\u00e7\u00e3o adicional. Mas alguns clientes enviam simplesmente um TCP-reset, ou seja, quebram a conex\u00e3o de rede. O que o Bouncer far\u00e1 nesse caso? Ele n\u00e3o far\u00e1 nada. Ele continuar\u00e1 a executar a consulta. Se voc\u00ea tiver um grande n\u00famero de conex\u00f5es que, com pequenas consultas, sobrecarregaram o banco de dados, simplesmente desconectar o Bouncer n\u00e3o ser\u00e1 suficiente; voc\u00ea tamb\u00e9m precisar\u00e1 finalizar as consultas que est\u00e3o rodando no banco de dados. <\/p>\n<p><\/p>\n<p>Isso foi corrigido e esse problema ainda n\u00e3o foi integrado ao upstream do Bouncer. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/a9695b6d9e640a5543dc73429eb0050b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E assim chegamos \u00e0 necessidade de nosso pr\u00f3prio pool de conex\u00f5es, que evoluir\u00e1, ser\u00e1 corrigido, onde poderemos resolver problemas rapidamente e que, claro, deve ser multiprocessado. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/e755cd9b06a004f0eced1dc12fd3a6fb.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Fizemos da multiprocessamento nossa principal tarefa. Precisamos lidar bem com a onda de conex\u00f5es TLS que chegam. <\/p>\n<p><\/p>\n<p>Para isso, tivemos que desenvolver uma biblioteca separada, chamada Machinarium, que \u00e9 destinada a descrever os estados da m\u00e1quina de conex\u00e3o de rede como um c\u00f3digo sequencial. Se voc\u00ea olhar o c\u00f3digo-fonte do libpq, ver\u00e1 chamadas bastante complexas, que podem retornar um resultado e dizer: \"Chame-me um pouco mais tarde. Agora estou com IO, mas, quando o IO passar, haver\u00e1 carga para o processador\". E esta \u00e9 uma estrutura de m\u00faltiplos n\u00edveis. A intera\u00e7\u00e3o de rede geralmente \u00e9 descrita como uma m\u00e1quina de estados. Com v\u00e1rias regras do tipo \"Se eu recebi anteriormente um cabe\u00e7alho de pacote de tamanho N, agora estou esperando N bytes\", \"Se enviei um pacote SYNC, agora estou esperando um pacote com metadados do resultado\". Isso resulta em um c\u00f3digo bastante dif\u00edcil e contraintuitivo, como se um labirinto fosse transformado em um desdobramento linear. Fizemos com que, em vez de uma m\u00e1quina de estados, o programador descrevesse o caminho principal da intera\u00e7\u00e3o como um c\u00f3digo imperativo comum. Simplesmente, neste c\u00f3digo imperativo, \u00e9 necess\u00e1rio inserir locais onde a sequ\u00eancia de execu\u00e7\u00e3o deve ser interrompida para aguardar dados da rede, passando o contexto de execu\u00e7\u00e3o para outra corrotina (green thread). Essa abordagem \u00e9 semelhante \u00e0 de registrar o caminho mais esperado em um labirinto em sequ\u00eancia e, em seguida, adicionar ramifica\u00e7\u00f5es a ele. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/a6bfb4b11961c7db3a7c7184674e3bc2.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>No final, temos uma \u00fanica thread que faz o TCP accept e, em round-robin, passa a conex\u00e3o TPC para v\u00e1rias workers. <\/p>\n<p><\/p>\n<p>Al\u00e9m disso, cada conex\u00e3o do cliente sempre opera em um \u00fanico processador, o que a torna otimizada em rela\u00e7\u00e3o ao cache. <\/p>\n<p><\/p>\n<p>Al\u00e9m do mais, aprimoramos a coleta de pequenos pacotes em um grande pacote para aliviar a carga do TCP-stack do sistema.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/7d740c23baecdd2f993c83cd54a0a8e1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Tamb\u00e9m melhoramos o pooling transacional, de modo que o Odyssey, com a configura\u00e7\u00e3o adequada, pode enviar CANCEL e ROLLBACK em caso de interrup\u00e7\u00e3o da conex\u00e3o de rede, ou seja, se ningu\u00e9m estiver aguardando a solicita\u00e7\u00e3o, o Odyssey informa ao banco para n\u00e3o tentar executar aquele pedido que pode consumir recursos valiosos.<\/p>\n<p><\/p>\n<p>Sempre que poss\u00edvel, mantemos conex\u00f5es com o mesmo cliente. Isso permite que n\u00e3o haja necessidade de reinstala\u00e7\u00e3o do application_name_add_host. Se vi\u00e1vel, n\u00e3o teremos reconfigura\u00e7\u00f5es adicionais que s\u00e3o necess\u00e1rias para diagn\u00f3stico. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/afb2fb7fb16d65c9ea73a8978d1eb83c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>N\u00f3s trabalhamos em prol do Yandex.Cloud. E se voc\u00ea utiliza o PostgreSQL gerenciado e possui um connection pooler instalado, voc\u00ea pode criar replica\u00e7\u00e3o l\u00f3gica externa, ou seja, se desejar, poder\u00e1 se desvincular de n\u00f3s atrav\u00e9s da replica\u00e7\u00e3o l\u00f3gica. O Bouncer n\u00e3o enviar\u00e1 o fluxo de replica\u00e7\u00e3o l\u00f3gica para fora. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/c53defc92ebd8f3bec57ce64d97b9f72.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Este \u00e9 um exemplo de configura\u00e7\u00e3o de replica\u00e7\u00e3o l\u00f3gica. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/a37d9d1abf288d17fa646b642e8b62ab.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Al\u00e9m disso, temos suporte \u00e0 replica\u00e7\u00e3o f\u00edsica externa. No Cloud, isso, claro, \u00e9 imposs\u00edvel, pois o cluster estaria fornecendo informa\u00e7\u00f5es em excesso sobre si mesmo. Mas nas suas instala\u00e7\u00f5es, se voc\u00ea precisar de replica\u00e7\u00e3o f\u00edsica atrav\u00e9s do connection pooler no Odyssey, isso \u00e9 vi\u00e1vel. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/572934ce5b08115e57ab4b55d2153c6d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>No Odyssey, o monitoramento \u00e9 totalmente compat\u00edvel com o PgBouncer. Temos um console semelhante que executa quase todos os mesmos comandos. Se faltar algo, envie um pull request ou, ao menos, crie uma issue no GitHub, e iremos adicionar os comandos necess\u00e1rios. Mas a funcionalidade principal do console PgBouncer j\u00e1 est\u00e1 dispon\u00edvel. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/451dd798fb3523a7a174ebfe00a14bc5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E, claro, temos o encaminhamento de erros. Retornaremos o erro que o banco informou. Voc\u00ea receber\u00e1 informa\u00e7\u00f5es sobre o motivo pelo qual n\u00e3o est\u00e1 acessando o banco, e n\u00e3o apenas que voc\u00ea n\u00e3o tem acesso. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/14b4cb0efa33a2658dfc528349a5382f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Essa funcionalidade pode ser desativada caso voc\u00ea precise de 100% de compatibilidade com o PgBouncer. Podemos nos comportar exatamente como o Bouncer, apenas por seguran\u00e7a. <\/p>\n<p><\/p>\n<p><strong>Desenvolvimento<\/strong><\/p>\n<p><\/p>\n<p>Algumas palavras sobre o c\u00f3digo-fonte do Odyssey. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/6055d5ec9676c331a83592916a6a292f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/yandex\/odyssey\/pull\/66\">https:\/\/github.com\/yandex\/odyssey\/pull\/66<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Por exemplo, existem os comandos \"Pause \/ Resume\". Eles s\u00e3o geralmente usados para atualizar o banco de dados. Se voc\u00ea precisar atualizar o Postgres, pode paus\u00e1-lo no connection pooler, fazer o pg_upgrade e, em seguida, retomar. E do lado do cliente, parecer\u00e1 que o banco s\u00f3 estava lento. Essa funcionalidade nos foi trazida por pessoas da comunidade. Ainda n\u00e3o est\u00e1 mesclada, mas em breve tudo estar\u00e1. (J\u00e1 mesclada)<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/d2f7c57e0ae3e466ec2a701bbdb8eb3f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/yandex\/odyssey\/pull\/73\">https:\/\/github.com\/yandex\/odyssey\/pull\/73<\/a><\/noindex> \u2014 j\u00e1 mesclada<\/p>\n<p><\/p>\n<p>Al\u00e9m disso, uma das novas funcionalidades no PgBouncer \u00e9 o suporte \u00e0 Autentica\u00e7\u00e3o SCRAM, que tamb\u00e9m nos foi trazida por uma pessoa que n\u00e3o trabalha na Yandex.Cloud. Ambas s\u00e3o funcionalidades complexas e importantes. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/f39346a543c88d17728233d05c2dff19.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Portanto, gostaria de falar sobre como o Odyssey \u00e9 feito, talvez voc\u00ea tamb\u00e9m esteja querendo escrever um pouco de c\u00f3digo. <\/p>\n<p><\/p>\n<p>Voc\u00ea tem a base original do Odyssey, que se baseia em duas bibliotecas principais. A biblioteca Kiwi \u00e9 a implementa\u00e7\u00e3o do protocolo de mensagens do Postgres. Ou seja, o proto nativo 3 do Postgres s\u00e3o mensagens padr\u00e3o que front-ends e back-ends podem trocar. Elas est\u00e3o implementadas na biblioteca Kiwi.<\/p>\n<p><\/p>\n<p>A biblioteca Machinarium \u00e9 uma biblioteca de implementa\u00e7\u00e3o de threads. Um pequeno trecho deste Machinarium foi escrito em assembly. Mas n\u00e3o se preocupe, s\u00e3o apenas 15 linhas. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/cd18f250af50eabd53536b2c0d7f12b5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Arquitetura do Odyssey. Existe uma m\u00e1quina principal, onde coroutines est\u00e3o em execu\u00e7\u00e3o. Nesta m\u00e1quina, ocorre a aceita\u00e7\u00e3o de conex\u00f5es TCP de entrada e a distribui\u00e7\u00e3o entre os workers. <\/p>\n<p><\/p>\n<p>Dentro de um worker, pode haver um manipulador de v\u00e1rios clientes. Al\u00e9m disso, no fluxo principal, est\u00e3o a console e o processamento de tarefas crone para remover conex\u00f5es que n\u00e3o s\u00e3o mais necess\u00e1rias no pool.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/7072fb20f406f2ee5788542860ccdf50.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Para testar o Odyssey, usamos o conjunto padr\u00e3o de testes do Postgres. Simplesmente executamos o install-check atrav\u00e9s do Bouncer e atrav\u00e9s do Odyssey, recebendo um div nulo. Existem v\u00e1rios testes relacionados \u00e0 formata\u00e7\u00e3o de datas que n\u00e3o passam de forma id\u00eantica no Bouncer e no Odyssey.<\/p>\n<p><\/p>\n<p>Al\u00e9m disso, h\u00e1 v\u00e1rios drivers que t\u00eam seus pr\u00f3prios testes. E utilizamos esses testes para testar o Odyssey.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/fb01cc9a0e9724ddcd3cc3d088afb182.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Al\u00e9m disso, devido \u00e0 nossa configura\u00e7\u00e3o em cascata, temos que testar diferentes combina\u00e7\u00f5es: Postgres + Odyssey, PgBouncer + Odyssey, Odyssey + Odyssey, para termos certeza de que, se o Odyssey estiver em alguma parte da cascata, ele ainda funcionar\u00e1 como esperamos. <\/p>\n<p><\/p>\n<p><strong>Truques<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/25855b691180bca083025b9e8b611c09.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Estamos usando o Odyssey em produ\u00e7\u00e3o. E n\u00e3o seria justo dizer que tudo funciona perfeitamente. N\u00e3o, ou seja, sim, mas nem sempre. Por exemplo, em produ\u00e7\u00e3o tudo simplesmente funcionou, depois nossos amigos da PostgreSQL Professional disseram que t\u00ednhamos um vazamento de mem\u00f3ria. Eles realmente estavam certos, n\u00f3s o corrigimos. Mas isso foi algo inesperado. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/e638d88397b32b1ca0b74c9c1b905f81.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Depois descobrimos que no connection pooler existem conex\u00f5es TLS de entrada e conex\u00f5es TLS de sa\u00edda. E nas conex\u00f5es s\u00e3o necess\u00e1rios certificados de cliente e certificados de servidor.<\/p>\n<p><\/p>\n<p>Os certificados de servidor do Bouncer e do Odyssey leem seus pcache, mas os certificados de cliente n\u00e3o precisam ser lidos do pcache, porque nosso Odyssey escal\u00e1vel, no final, esbarra na performance de leitura desse certificado. Isso foi uma surpresa para n\u00f3s, porque isso n\u00e3o aconteceu imediatamente. Inicialmente, ele escalou linearmente, mas ap\u00f3s 20.000 conex\u00f5es simult\u00e2neas de entrada, esse problema se manifestou.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/6cff094cd59a990e448b82fa0b1572b7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>O M\u00e9todo de Autentica\u00e7\u00e3o Pluggable \u00e9 a possibilidade de se autenticar com os recursos integrados do Linux. No PgBouncer, isso \u00e9 implementado de forma que h\u00e1 uma thread separada esperando a resposta do PAM e h\u00e1 a thread principal do PgBouncer, que gerencia a conex\u00e3o atual e pode solicitar que elas aguardem na thread do PAM. <\/p>\n<p><\/p>\n<p>N\u00f3s n\u00e3o implementamos isso por uma raz\u00e3o simples. Temos muitas threads. Para que precisamos disso?<\/p>\n<p><\/p>\n<p>No final, isso pode criar problemas, pois, se voc\u00ea tem autentica\u00e7\u00e3o PAM e n\u00e3o PAM, uma grande onda de autentica\u00e7\u00f5es PAM pode atrasar significativamente a autentica\u00e7\u00e3o n\u00e3o PAM. Esta \u00e9 uma das coisas que n\u00e3o corrigimos. Mas se voc\u00ea quiser corrigir, pode trabalhar nisso. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/c7bd9e9980ff7298b30a59c130f03dbb.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Outro desafio foi que temos uma thread que aceita todas as conex\u00f5es de entrada. E ent\u00e3o as passa para o pool de trabalhadores, onde ocorrer\u00e1 o handshake TLS.<\/p>\n<p><\/p>\n<p>Portanto, se voc\u00ea tem uma onda coerente de 20.000 conex\u00f5es de rede, todas elas ser\u00e3o aceitas. E do lado do cliente, o libpq come\u00e7ar\u00e1 a contar os timeouts. Por padr\u00e3o, parece que \u00e9 configurado para 3 segundos. <\/p>\n<p><\/p>\n<p>Se todas elas n\u00e3o podem acessar o banco de dados ao mesmo tempo, ent\u00e3o elas n\u00e3o conseguem entrar no banco de dados, porque tudo isso pode ser coberto por uma tentativa de reconex\u00e3o n\u00e3o exponencial. <\/p>\n<p><\/p>\n<p>Chegamos \u00e0 conclus\u00e3o de que copiamos aqui o esquema do PgBouncer com o que temos de throttling na quantidade de conex\u00f5es TCP que aceitamos. <\/p>\n<p><\/p>\n<p>Se virmos que aceitamos conex\u00f5es, mas elas n\u00e3o conseguem completar o handshake a tempo, as colocamos em uma fila para que n\u00e3o consumam recursos da CPU central. Isso leva ao fato de que o handshake simult\u00e2neo pode n\u00e3o ser realizado para todas as conex\u00f5es recebidas. Mas pelo menos algu\u00e9m conseguir\u00e1 acessar o banco, mesmo que a carga seja bastante alta.<\/p>\n<p><\/p>\n<p><strong>Roteiro<\/strong><\/p>\n<p><\/p>\n<p>O que gostar\u00edamos de ver no futuro no Odyssey? O que estamos prontos para desenvolver e o que esperamos da comunidade?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/4719437d80b33efc3da6572af9a4dedb.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>Em agosto de 2019.<\/strong><\/p>\n<p><\/p>\n<p>Assim era o roteiro do Odyssey em agosto:<\/p>\n<p><\/p>\n<ul>\n<li>Quer\u00edamos autentica\u00e7\u00e3o SCRAM e PAM.<\/li>\n<li>Quer\u00edamos redirecionar consultas de leitura para o standby. <\/li>\n<li>Gostar\u00edamos de rein\u00edcio online. <\/li>\n<li>E a possibilidade de fazer uma pausa no servidor. <\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/455c92f92df826257c2c57dc2b034e22.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Metade deste roteiro foi cumprida, e n\u00e3o por n\u00f3s. E isso \u00e9 bom. Portanto, vamos discutir o que resta e adicionar mais. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/4a1daafbfe8d65ba0dd3e1ebdae8dd94.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/yandex\/odyssey\/issues\/12\">Quanto ao redirecionamento de consultas somente leitura para o standby<\/a><\/noindex>? \u0423 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0440\u0435\u043f\u043b\u0438\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0435\u0437 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u0433\u0440\u0435\u0442\u044c \u0432\u043e\u0437\u0434\u0443\u0445. \u041e\u043d\u0438 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u0434\u043b\u044f \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f failover \u0438 switchover. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0432 \u043e\u0434\u043d\u043e\u043c \u0438\u0437 \u0434\u0430\u0442\u0430-\u0446\u0435\u043d\u0442\u0440\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0438\u0445 \u0437\u0430\u043d\u044f\u0442\u044c \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u043e\u0439. \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0442\u0435 \u0436\u0435 \u0441\u0430\u043c\u044b\u0435 \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u044b, \u0442\u0443 \u0436\u0435 \u0441\u0430\u043c\u0443\u044e \u043f\u0430\u043c\u044f\u0442\u044c \u043c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u0441\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e-\u0434\u0440\u0443\u0433\u043e\u043c\u0443, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0438\u043d\u0430\u0447\u0435 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u044f.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/0873cffd4f1ae15d9ffa6d080671051b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Basicamente, no Postgres, a partir da vers\u00e3o 10, existe a possibilidade de especificar tamb\u00e9m session_attrs na conex\u00e3o. Voc\u00ea pode listar todos os hosts de banco de dados na conex\u00e3o e dizer por que est\u00e1 acessando o banco de dados: para gravar ou apenas para ler. E o driver escolher\u00e1 automaticamente o primeiro host da lista que mais gosta e que atende aos requisitos de session_attrs. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/0693d1327fe5826502a01c21d05d5b4c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Mas o problema dessa abordagem \u00e9 que ela n\u00e3o controla o atraso de replica\u00e7\u00e3o. Voc\u00ea pode ter uma r\u00e9plica que esteja atrasada por um tempo inaceit\u00e1vel para o seu servi\u00e7o. Para que possamos executar consultas de leitura na r\u00e9plica de forma funcional, essencialmente precisamos garantir que o Odyssey n\u00e3o funcione quando a leitura n\u00e3o \u00e9 poss\u00edvel. <\/p>\n<p><\/p>\n<p>O Odyssey deve periodicamente consultar o banco e verificar a dist\u00e2ncia de replica\u00e7\u00e3o em rela\u00e7\u00e3o ao prim\u00e1rio. E se ela atingir um valor limite, novas consultas ao banco n\u00e3o devem ser permitidas, informando ao cliente que \u00e9 necess\u00e1rio reiniciar as conex\u00f5es e, possivelmente, escolher outro host para executar as consultas. Isso permitir\u00e1 que o banco se recupere mais rapidamente do atraso de replica\u00e7\u00e3o e volte a responder \u00e0s consultas. <\/p>\n<p><\/p>\n<p>\u00c9 dif\u00edcil estipular um prazo para implementa\u00e7\u00e3o, pois \u00e9 open source. Mas espero que n\u00e3o leve 2,5 anos como para os colegas do PgBouncer. Essa \u00e9 uma fun\u00e7\u00e3o que gostaria de ver no Odyssey. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/4ec3cd2ff7b2298927cccfe8e0ba890a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/yandex\/odyssey\/issues\/16\">Na comunidade, as pessoas perguntaram sobre o suporte para prepared statements.<\/a><\/noindex>Agora voc\u00ea pode criar uma declara\u00e7\u00e3o preparada de duas maneiras. Primeiro, voc\u00ea pode executar o comando SQL, que \u00e9 \"prepared\". Para entender esse comando SQL, precisamos aprender a compreender o SQL do lado do Bouncer. Seria um exagero, pois precisar\u00edamos de um parser completo. N\u00e3o podemos parsear cada comando SQL. <\/p>\n<p><\/p>\n<p>Mas existe a declara\u00e7\u00e3o preparada no n\u00edvel do protocolo de mensagens no proto3. E \u00e9 nesse momento que a informa\u00e7\u00e3o sobre a cria\u00e7\u00e3o da declara\u00e7\u00e3o preparada chega de forma estruturada. E poder\u00edamos manter a compreens\u00e3o de que em alguma conex\u00e3o de servidor o cliente pediu para criar declara\u00e7\u00f5es preparadas. E mesmo se a transa\u00e7\u00e3o foi encerrada, ainda precisamos manter a consist\u00eancia entre servidor e cliente. <\/p>\n<p><\/p>\n<p>Mas aqui surge um desvio no di\u00e1logo, porque algu\u00e9m fala sobre a necessidade de entender qual declara\u00e7\u00e3o preparada foi criada pelo cliente e dividir a conex\u00e3o do servidor entre todos os clientes que criaram essa conex\u00e3o de servidor, isto \u00e9, que criaram tal declara\u00e7\u00e3o preparada. <\/p>\n<p><\/p>\n<p>Andres Freund disse que se um cliente vier a voc\u00ea que j\u00e1 criou tal declara\u00e7\u00e3o preparada em outra conex\u00e3o de servidor, voc\u00ea deve cri\u00e1-la por ele. Mas, parece meio errado fazer consultas no banco em vez do cliente, mas do ponto de vista do desenvolvedor que escreve o protocolo de intera\u00e7\u00e3o com o banco, seria conveniente se ele simplesmente tivesse uma conex\u00e3o de rede onde h\u00e1 essa consulta preparada. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/cd56b3ad015195d86a64e52be365b16a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E mais uma funcionalidade que precisamos implementar. Atualmente temos monitoramento compat\u00edvel com PgBouncer. Podemos retornar o tempo m\u00e9dio de execu\u00e7\u00e3o da consulta. Mas o tempo m\u00e9dio \u00e9 uma m\u00e9dia, n\u00e3o reflete a realidade: alguns est\u00e3o frios, alguns quentes - em m\u00e9dia todos est\u00e3o saud\u00e1veis. Isso n\u00e3o \u00e9 verdade. <\/p>\n<p><\/p>\n<p>Precisamos implementar o suporte a percentis, que indicariam que existem consultas lentas que consomem recursos e tornariam o monitoramento mais aceit\u00e1vel. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/6f285f3eb0d79e7f25d42f0e792b85b1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>O mais importante - gostar\u00edamos da vers\u00e3o 1.0 (a vers\u00e3o 1.1 j\u00e1 foi lan\u00e7ada). O fato \u00e9 que atualmente o Odyssey est\u00e1 na vers\u00e3o 1.0rc, ou seja, release candidate. E todos os problemas que mencionei foram corrigidos nesta vers\u00e3o, exceto o vazamento de mem\u00f3ria. <\/p>\n<p><\/p>\n<p>O que a vers\u00e3o 1.0 significar\u00e1 para n\u00f3s? Estamos lan\u00e7ando o Odyssey em nossas bases. Ele j\u00e1 est\u00e1 funcionando em nossas bases, mas quando alcan\u00e7ar 1.000.000 de consultas por segundo, podemos dizer que esta \u00e9 a vers\u00e3o de lan\u00e7amento e \u00e9 a vers\u00e3o que podemos chamar de 1.0. <\/p>\n<p><\/p>\n<p>Na comunidade, algumas pessoas pediram que na vers\u00e3o 1.0 houvesse tamb\u00e9m pausa e SCRAM. Mas isso significaria que precisar\u00edamos lan\u00e7ar a pr\u00f3xima vers\u00e3o em produ\u00e7\u00e3o, porque nem SCRAM nem pausa est\u00e3o integrados ainda. Mas, provavelmente, essa quest\u00e3o ser\u00e1 resolvida rapidamente. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Roadmap Odyssey: o que mais queremos do conector de pools. Andrey Borodin (2019)\" src=\"\/wp-content\/uploads\/2020\/10\/2f50de9f51f653a7396965239bd545e1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Estou aguardando suas solicita\u00e7\u00f5es de pull request. E tamb\u00e9m gostaria de saber quais problemas voc\u00eas t\u00eam com o Bouncer. Vamos discuti-los. Talvez possamos implementar algumas fun\u00e7\u00f5es que s\u00e3o necess\u00e1rias para voc\u00eas. <\/p>\n<p><\/p>\n<p>Com isso, minha parte termina, gostaria de ouvir voc\u00eas. Obrigado!<\/p>\n<p><\/p>\n<p>Perguntas<\/p>\n<p><\/p>\n<p><em>Se eu definir meu application_name, ele ser\u00e1 corretamente transmitido, incluindo no transaction pooling no Odyssey?<\/em><\/p>\n<p><\/p>\n<p>No Odyssey ou no Bouncer?<\/p>\n<p><\/p>\n<p><em>No Odyssey. \u00c9 feito no Bouncer.<\/em> <\/p>\n<p><\/p>\n<p>Faremos o set. <\/p>\n<p><\/p>\n<p><em>E se minha conex\u00e3o real estiver pulando entre outras conex\u00f5es, ela ser\u00e1 transmitida?<\/em><\/p>\n<p><\/p>\n<p>Faremos o set de todos os par\u00e2metros que est\u00e3o na lista. N\u00e3o posso dizer se o application_name est\u00e1 nesta lista. Parece que o vi l\u00e1. Definiremos todos os mesmos par\u00e2metros. Com uma solicita\u00e7\u00e3o, o set far\u00e1 tudo o que foi definido pelo cliente na inicializa\u00e7\u00e3o. <\/p>\n<p><\/p>\n<p><em>Obrigado, Andrey, pela apresenta\u00e7\u00e3o! Boa apresenta\u00e7\u00e3o! Fico feliz que o Odyssey esteja se desenvolvendo cada vez mais r\u00e1pido a cada minuto. Desejo que continue assim. J\u00e1 entramos em contato com voc\u00eas pedindo para ter a conex\u00e3o multi data-source, para que o Odyssey possa se conectar simultaneamente a diferentes bancos de dados, ou seja, master-slave, e depois se reconectar automaticamente a um novo master ap\u00f3s failover.<\/em> <\/p>\n<p><\/p>\n<p>Sim, parece que me lembro dessa discuss\u00e3o. Atualmente, existem v\u00e1rios storages. Mas n\u00e3o h\u00e1 altern\u00e2ncia entre eles. Precisamos monitorar o servidor do nosso lado, para saber se ele ainda est\u00e1 ativo e entender que ocorreu um failover, quem chamar\u00e1 o pg_recovery. Tenho um m\u00e9todo padr\u00e3o para entender que n\u00e3o estamos no master. E devemos entender de alguma forma por meio dos erros ou como? Ou seja, a ideia \u00e9 interessante, est\u00e1 em discuss\u00e3o. Escrevam mais coment\u00e1rios. Se voc\u00eas tiverem m\u00e3os que conhecem C, isso seria \u00f3timo. <\/p>\n<p><\/p>\n<p>A quest\u00e3o do dimensionamento por r\u00e9plicas tamb\u00e9m nos interessa, porque queremos tornar a ado\u00e7\u00e3o de clusters replicados o mais simples poss\u00edvel para os desenvolvedores de aplicativos. Mas gostaria de mais coment\u00e1rios, ou seja, como exatamente fazer isso, como fazer bem. <\/p>\n<p><\/p>\n<p><em>A pergunta tamb\u00e9m \u00e9 sobre r\u00e9plicas. Ent\u00e3o, voc\u00eas t\u00eam um mestre e v\u00e1rias r\u00e9plicas. Fica claro que as conex\u00f5es para a r\u00e9plica ocorrem com menos frequ\u00eancia do que para o mestre, pois podem haver diferen\u00e7as. Voc\u00ea mencionou que as diferen\u00e7as nos dados podem ser tais que n\u00e3o atendem ao seu neg\u00f3cio e voc\u00ea n\u00e3o se conectar\u00e1 a elas at\u00e9 que estejam completamente replicadas. Al\u00e9m disso, se voc\u00ea n\u00e3o se conectar a elas por muito tempo e depois come\u00e7ar a se conectar, os dados necess\u00e1rios n\u00e3o estar\u00e3o imediatamente dispon\u00edveis. Ou seja, se constantemente nos conectamos ao mestre, o cache estar\u00e1 aquecido, enquanto na r\u00e9plica o cache pode estar um pouco atrasado.<\/em> <\/p>\n<p><\/p>\n<p>Sim, isso \u00e9 verdade. No pcache n\u00e3o haver\u00e1 blocos de dados que voc\u00ea deseja, no cache real n\u00e3o haver\u00e1 informa\u00e7\u00f5es sobre as tabelas que voc\u00ea deseja, nos planos n\u00e3o haver\u00e1 consultas analisadas, na verdade, nada haver\u00e1. <\/p>\n<p><\/p>\n<p><em>E quando voc\u00ea tem um cluster e adiciona uma nova r\u00e9plica, enquanto ela est\u00e1 sendo iniciada, as coisas est\u00e3o ruins, ou seja, ela est\u00e1 aumentando seu cache.<\/em> <\/p>\n<p><\/p>\n<p>Entendi a ideia. A abordagem correta seria executar uma pequena porcentagem de consultas primeiro na r\u00e9plica, para aquecer o cache. Grosso modo, temos a condi\u00e7\u00e3o de que n\u00e3o devemos ficar mais do que 10 segundos atr\u00e1s do mestre. E essa condi\u00e7\u00e3o deve ser ativada n\u00e3o de uma s\u00f3 vez, mas gradualmente para alguns clientes. <\/p>\n<p><\/p>\n<p><em>Sim, aumentar o peso.<\/em><\/p>\n<p><\/p>\n<p>\u00c9 uma boa ideia. Mas primeiro precisamos implementar esse desligamento. Primeiro, devemos desligar, e depois pensaremos em como reativar. \u00c9 um \u00f3timo recurso para ativar suavemente.<\/p>\n<p><\/p>\n<p><em>No nginx existe essa op\u00e7\u00e3o <code>iniciar lentamente<\/code> no cluster para o servidor. E ele gradualmente aumenta a carga.<\/em> <\/p>\n<p><\/p>\n<p>Sim, \u00f3tima ideia, vamos tentar quando chegarmos l\u00e1.<\/p>\n<p>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/522734\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412 \u0434\u043e\u043a\u043b\u0430\u0434\u0435 \u0410\u043d\u0434\u0440\u0435\u0439 \u0411\u043e\u0440\u043e\u0434\u0438\u043d \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0435\u0442, \u043a\u0430\u043a \u043e\u043d\u0438 \u0443\u0447\u043b\u0438 \u043e\u043f\u044b\u0442 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f PgBouncer \u043f\u0440\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043f\u0443\u043b\u0435\u0440\u0430 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 Odyssey, \u043a\u0430\u043a \u0432\u044b\u043a\u0430\u0442\u044b\u0432\u0430\u043b\u0438 \u0435\u0433\u043e \u0432 production. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043e\u0431\u0441\u0443\u0434\u0438\u043c \u043a\u0430\u043a\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u0443\u043b\u0435\u0440\u0430 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0432\u0438\u0434\u0435\u0442\u044c \u0432 \u043d\u043e\u0432\u044b\u0445 \u0432\u0435\u0440\u0441\u0438\u044f\u0445: \u043d\u0430\u043c \u0432\u0430\u0436\u043d\u043e \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u043d\u043e\u0441\u0442\u0438, \u043d\u043e \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u041e\u0434\u0438\u0441\u0441\u0435\u044f. \u0412\u0438\u0434\u0435\u043e: \u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0410\u043d\u0434\u0440\u0435\u0439. \u0412 \u042f\u043d\u0434\u0435\u043a\u0441\u0435 \u044f \u0437\u0430\u043d\u0438\u043c\u0430\u044e\u0441\u044c [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":96516,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-96515","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.4 - aioseo.com -->\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\/odyssey-roadmap-chto-eshhyo-my-hotim-ot-pulera-soedinenij-andrej-borodin-2019\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\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\udd47Odyssey roadmap: \u0447\u0442\u043e \u0435\u0449\u0451 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043e\u0442 \u043f\u0443\u043b\u0435\u0440\u0430 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439. \u0410\u043d\u0434\u0440\u0435\u0439 \u0411\u043e\u0440\u043e\u0434\u0438\u043d (2019) | ProHoster\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/odyssey-roadmap-chto-eshhyo-my-hotim-ot-pulera-soedinenij-andrej-borodin-2019\" \/>\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-10-12T17:43:02+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-10-12T17:43:02+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\udd47Odyssey roadmap: o que mais queremos do pooler de conex\u00f5es. Andrey Borodin (2019) | ProHoster","description":"","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/odyssey-roadmap-chto-eshhyo-my-hotim-ot-pulera-soedinenij-andrej-borodin-2019","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\udd47Odyssey roadmap: \u0447\u0442\u043e \u0435\u0449\u0451 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043e\u0442 \u043f\u0443\u043b\u0435\u0440\u0430 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439. \u0410\u043d\u0434\u0440\u0435\u0439 \u0411\u043e\u0440\u043e\u0434\u0438\u043d (2019) | ProHoster","og:url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/odyssey-roadmap-chto-eshhyo-my-hotim-ot-pulera-soedinenij-andrej-borodin-2019","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-10-12T17:43:02+00:00","article:modified_time":"2020-10-12T17:43:02+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"96515","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 10:41:30","updated":"2022-10-01 00:02:14","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\/96515","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=96515"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/96515\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media\/96516"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=96515"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=96515"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=96515"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}