Quando usar conexões persistentes no PHP com PDO?

Pretendo aqui explicar o que concluí na prática sobre este assunto pois não encontrei nenhum texto claro que sanasse minhas dúvidas por completo até então.


Segundo o próprio php.net em sua documentação oficial:

Conexões persistentes são conexões que não fecham quando a execução do seu script termina. Quando uma conexão persistente é requisitada, o PHP verifica se já existe uma conexão persistente idêntica (que foi mantida aberta anteriormente) - e, se ela existir, ele a usa. Se ela não existir, ele cria a conexão. Uma conexão 'idêntica' é uma conexão que foi aberta para o mesmo host, com o mesmo nome de usuário e a mesma senha (onde for aplicável)

Para quem é experiente em PHP talvez já tenha se deparado com a seguinte mensagem:

Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000] [1040] Too many connections'

Geralmente quando isso acontece é porque a conexão persistente está ativada, tal como no exemplo a seguir:

$db = new PDO('mysql:host=seu.url.dsn;dbname=nome_do_database', 'nome_do_usuario', 'senha_do_usuario', array(PDO::ATTR_PERSISTENT => TRUE));

A partir do momento em que a conexão acima é estabelecida com o banco de dados, é o banco de dados que definirá quando encerrar essa conexão que você inicializou como "persistente". Obs: não vou explicar aqui como gerenciar a configuração do banco de dados em relação ao encerramento dessas conexões, somente a parte do que se refere o PHP.

A instrução $db=null; deveria encerrar a conexão acima, mas por ela ter sido aberta em modo persistente, a conexão não será encerrada com essa instrução.

Realize um experimento prático aí na sua máquina local:

$ mysql -u root -padmin
> use nome_do_database;
> show processlist;

Então escreva o seguinte trecho de código no seu PHP:

<?php
$db = new PDO('mysql:host=seu.url.dsn;dbname=nome_do_database', 'nome_do_usuario', 'senha_do_usuario', array(PDO::ATTR_PERSISTENT => TRUE));
$db = null;


Então repita a instrução show processlist; e verá uma conexão aberta. Essa conexão não se encerra por ter sido aberto em modo persistente.

Experimente agora reiniciar o serviço do seu banco de dados MySQL, em seguida repita os passos acima definindo FALSE no PDO::ATTR_PERSISTENT.

Observe que não há conexões abertas no banco de dados se a instrução for definida como não persistente, ela encerra de verdade na instrução $db=null;.


Conclusão

Se as conexões persistentes não possuem nenhuma funcionalidade excepcional, para que servem? A resposta aqui é extremamente simples: eficiência. 

As conexões persistentes são boas se a latência para criar um vínculo com o servidor SQL for alta. Elas fazem com que o processo filho simplesmente se conecte uma única vez durante toda a sua vida útil, ao invés de sempre estabelecer uma conexão nova com seu banco de dados a cada requisição feita no PHP.

Isso significa que para cada filho que abriu uma conexão persistente terá sua própria conexão persistente aberta com o servidor, não sendo necessário criar uma conexão nova a cada requisição, então a mesma deverá ser reutilizada. Se você usa o php-fpm entenda que é ele quem vai gerenciar essa persistência junto ao banco, tanto que você poderá ficar confuso por ver várias conexões sendo abertas no banco quando a conexão persistente estiver ativada em sua máquina local. Neste caso o PDO junto ao php-fpm farão um pool automático das conexões abertas, e essa gestão não é transparente de modo que consigamos ver claramente o número real de conexões em uso. Mas fica um pouco mais claro quando observamos que as conexões persistentes encerram na medida em que reiniciamos nosso servidor Web junto ao php-fpm.

Por exemplo, se você tivesse 20 processos filho diferentes que executassem um script que fizesse uma conexão persistente com seu servidor SQL, você teria 20 conexões diferentes com o servidor SQL, uma de cada filho. Portanto, mesmo que ainda exista N usuários simultâneos, cada um teria sua própria conexão, mas reutilizaria a mesma conexão por solicitação subsequente. Isso oferece boa performance quando você tem um número baixo de requisições ou utilizadores simultâneos.

Então, como concluído no início, dependendo do seu ambiente a reutilização das conexões persistentes pode não ajudar, e logo você poderá se deparar com "Too many connections". 

Por outro lado conexões não persistentes podem eliminar o assustador "Too many connections", mas podem gerar lentidão na sua aplicação se mal gerenciadas dentro de seu código ou mesmo se você esquecer de encerrar alguma conexão aberta principalmente se você faz uso de transactions, por isso minha recomendação é fazer uso de certos design patterns de modo a equilibrar essa balança.

Comentários

Postagens mais visitadas deste blog

Configurar teclado americano com acentuação em português + Ç no Ubuntu 18.04LTS e 20.04LTS

Como instalar a impressora Epson L395 via wi-fi no Ubuntu 18.04 LTS e Ubuntu 20.04 LTS