No PDO, uma conexão pode ser feita persistente usando o PDO::ATTR_PERSISTENT
atributo De acordo com o manual php -
As conexões persistentes não são fechadas no final do script, mas são armazenadas em cache e reutilizadas quando outro script solicita uma conexão usando as mesmas credenciais. O cache de conexão persistente permite evitar a sobrecarga de estabelecer uma nova conexão sempre que um script precisar conversar com um banco de dados, resultando em um aplicativo da Web mais rápido.
O manual também recomenda não usar conexão persistente enquanto estiver usando o driver ODBC PDO, pois isso pode dificultar o processo de Pool de Conexão ODBC.
Então, aparentemente, parece não haver desvantagens em usar a conexão persistente no PDO, exceto no último caso. No entanto, gostaria de saber se existem outras desvantagens do uso desse mecanismo, ou seja, uma situação em que esse mecanismo resulta em degradação do desempenho ou algo parecido.
Respostas:
Leia esta resposta abaixo , que detalha maneiras de atenuar os problemas descritos aqui.
As mesmas desvantagens existem usando o PDO, como em qualquer outra interface de banco de dados PHP que faz conexões persistentes: se o script terminar inesperadamente no meio das operações do banco de dados, a próxima solicitação que obtiver a conexão restante continuará de onde o script morto parou. A conexão é mantida aberta no nível do gerenciador de processos (Apache para mod_php, o processo FastCGI atual, se você estiver usando FastCGI, etc), não no nível PHP, e o PHP não diz ao processo pai para deixar a conexão morrer quando o script termina de forma anormal.
Se o script inoperante bloqueou as tabelas, essas tabelas permanecerão bloqueadas até que a conexão morra ou o próximo script que obtém a conexão desbloqueie as próprias tabelas.
Se o script morto estiver no meio de uma transação, isso poderá bloquear várias tabelas até que o cronômetro de deadlock entre em ação e, mesmo assim, o cronômetro de deadlock poderá eliminar a solicitação mais recente em vez da solicitação mais antiga que está causando o problema.
Se o script morto estava no meio de uma transação, o próximo script que obtém essa conexão também obtém o estado da transação. É muito possível (dependendo do design do aplicativo) que o próximo script nunca tente confirmar a transação existente, ou confirme quando não deveria, ou reverta quando não deveria.
Esta é apenas a ponta do iceberg. Tudo isso pode ser atenuado até um certo ponto, sempre tentando limpar após uma conexão suja em cada solicitação de script, mas isso pode ser um problema, dependendo do banco de dados. A menos que você tenha identificado a criação de conexões de banco de dados como a única coisa que é um gargalo no seu script (isso significa que você tem o código feito de perfis usando xdebug e / ou xhprof ), você deve não considerar conexões persistentes como uma solução para nada.
Além disso, a maioria dos bancos de dados modernos (incluindo o PostgreSQL) tem suas próprias maneiras preferidas de executar o pool de conexões que não têm as desvantagens imediatas que as conexões persistentes simples baseadas em PHP.
Para esclarecer um ponto, usamos conexões persistentes no meu local de trabalho, mas não por opção. Estávamos encontrando um comportamento estranho de conexão, em que a conexão inicial do servidor de aplicativos com o servidor de banco de dados estava levando exatamente três segundos, quando deveria levar uma fração de uma fração de segundo. Achamos que é um bug do kernel. Desistimos de tentar solucionar o problema, porque isso aconteceu aleatoriamente e não pôde ser reproduzido sob demanda, e nossa TI terceirizada não tinha a capacidade concreta de localizá-lo.
Independentemente disso, quando as pessoas no armazém estão processando algumas centenas de peças recebidas e cada uma delas leva três segundos e meio em vez de meio segundo, tivemos que agir antes que eles nos sequestrassem e nos fizessem ajudá-los. Por isso, lançamos alguns detalhes em nossa monstruosidade ERP / CRM / CMS, criada em casa, e experimentamos todos os horrores de conexões persistentes em primeira mão. Levamos semanas para rastrear todos os pequenos problemas sutis e comportamentos bizarros que aconteciam aparentemente ao acaso. Aconteceu que aqueles erros fatais que uma vez por semana os nossos usuários retiravam diligentemente do nosso aplicativo estavam deixando tabelas bloqueadas, transações abandonadas e outros estados infelizes.
Essa triste história tem um ponto: quebrou coisas que nunca esperávamos quebrar, tudo em nome da performance. A troca não valeu a pena, e estamos aguardando ansiosamente o dia em que possamos voltar às conexões normais sem uma revolta de nossos usuários.
fonte
SELECT orders.* FROM orders LEFT JOIN items USING(item_id)
register_shutdown_function()
. Se o processo morrer, a conexão também morrerá. Caso contrário, a conexão é redefinida para seu estado limpo (por exemplo, transações abertas são revertidas). Se isso falhar, a conexão será fechada e uma nova será aberta pela próxima solicitação ao mesmo processo. Não há necessidade de demonizar conexões persistentes.mysqli_change_user
ainda é provavelmente a melhor solução alternativa para pessoas que precisam fazer conexões persistentes em um aplicativo não projetado para lidar com problemas de estado.Em resposta ao problema de Charles acima,
De: http://www.php.net/manual/en/mysqli.quickstart.connections.php -
Uma reclamação comum sobre conexões persistentes é que seu estado não é redefinido antes da reutilização. Por exemplo, transações abertas e inacabadas não são revertidas automaticamente. Além disso, as alterações de autorização que ocorreram no período entre colocar a conexão no pool e reutilizá-la não são refletidas. Isso pode ser visto como um efeito colateral indesejado. Pelo contrário, o nome persistente pode ser entendido como uma promessa de que o estado é persistente.
A extensão mysqli suporta as duas interpretações de uma conexão persistente: state persisted e state reset antes da reutilização. O padrão é redefinido. Antes de uma conexão persistente ser reutilizada, a extensão mysqli chama implicitamente
mysqli_change_user()
para redefinir o estado. A conexão persistente aparece para o usuário como se tivesse acabado de ser aberta. Nenhum artefato de usos anteriores é visível.A
mysqli_change_user()
função é uma operação cara. Para um melhor desempenho, os usuários podem recompilar a extensão com o sinalizador de compilaçãoMYSQLI_NO_CHANGE_USER_ON_PCONNECT
sendo definido.Cabe ao usuário escolher entre comportamento seguro e melhor desempenho. Ambos são objetivos de otimização válidos. Para facilitar o uso, o comportamento seguro tornou-se o padrão à custa do desempenho máximo.
fonte
Conexões persistentes são uma boa idéia apenas quando leva um tempo (relativamente) longo para se conectar ao seu banco de dados. Hoje em dia quase nunca é esse o caso. A maior desvantagem das conexões persistentes é que isso limita o número de usuários que você pode ter navegando no seu site: se o MySQL estiver configurado para permitir apenas 10 conexões simultâneas ao mesmo tempo, quando uma 11ª pessoa tentar navegar no site, isso não funcionará para eles. .
O PDO não gerencia a persistência. O driver MySQL faz. Ele reutiliza conexões quando a) elas estão disponíveis e o host / usuário / senha / banco de dados corresponde. Se houver alguma alteração, não reutilizará uma conexão. O melhor efeito líquido é que essas conexões que você tem serão iniciadas e interrompidas com frequência porque você tem usuários diferentes no site e torná-los persistentes não adianta.
A principal coisa a entender sobre conexões persistentes é que você NÃO deve usá-las na maioria dos aplicativos da web. Eles parecem atraentes, mas são perigosos e praticamente inúteis.
Tenho certeza de que existem outros threads, mas uma conexão persistente é perigosa porque persiste entre solicitações. Se, por exemplo, você bloquear uma tabela durante uma solicitação e falhar ao desbloquear, essa tabela permanecerá bloqueada indefinidamente. As conexões persistentes também são praticamente inúteis para 99% dos seus aplicativos, porque você não tem como saber se a mesma conexão será usada entre solicitações diferentes. Cada encadeamento da web terá seu próprio conjunto de conexões persistentes e você não terá como controlar qual encadeamento manipulará quais solicitações.
A biblioteca procedural do mysql do PHP possui um recurso pelo qual chamadas subseqüentes ao mysql_connect retornarão o mesmo link, em vez de abrir uma conexão diferente (como se poderia esperar). Isso não tem nada a ver com conexões persistentes e é específico para a biblioteca mysql. O DOP não exibe esse comportamento
Link do recurso: link
Em geral, você pode usar isso como um "conjunto de regras" aproximado:
SIM , use conexões persistentes, se:
O banco de dados está sendo executado em outro servidor que você está acessando pela rede
Um (um) aplicativo acessa o banco de dados com muita frequência
NÃO , não use conexões persistentes, se:
Seu aplicativo precisa acessar o banco de dados apenas 100 vezes por hora.
Você tem muitos servidores da web acessando um servidor de banco de dados
O uso de conexões persistentes é consideravelmente mais rápido, especialmente se você estiver acessando o banco de dados através de uma rede. Não faz muita diferença se o banco de dados estiver sendo executado na mesma máquina, mas ainda é um pouco mais rápido. No entanto - como o nome diz - a conexão é persistente, ou seja, permanece aberta, mesmo que não seja usada.
O problema é que, na "configuração padrão", o MySQL permite apenas 1000 "canais abertos" paralelos. Depois disso, novas conexões são recusadas (você pode ajustar essa configuração). Portanto, se você tiver, digamos, 20 servidores da Web com cada 100 clientes, e cada um deles tiver apenas um acesso à página por hora, uma matemática simples mostrará que você precisará de 2000 conexões paralelas ao banco de dados. Isso não vai funcionar.
Ergo: use-o apenas para aplicativos com muitas solicitações.
fonte
Nos meus testes, eu tive um tempo de conexão de mais de um segundo no meu host local, assumindo, portanto, que eu deveria usar uma conexão persistente. Testes adicionais mostraram que havia um problema com o 'localhost':
Resultados do teste em segundos (medido pelo php microtime):
Curiosamente: O código a seguir é tão rápido quanto usar 127.0.0.1:
fonte
localhost
conexão usa soquetes, conexão de soquete é famoso para ser mau em grande quantidade de conexõesConexões persistentes devem dar um aumento considerável no desempenho. Não concordo com a afirmação de que você deve "Evitar" a persistência.
Parece que as reclamações acima são motivadas por alguém usando tabelas MyIASM e invadindo suas próprias versões de transações, bloqueando os bloqueios de tabelas. Bem, é claro que você vai entrar em conflito! Use o beginTransaction () do PDO e mova suas tabelas para o InnoDB.
fonte
Parece-me que ter uma conexão persistente consumiria mais recursos do sistema. Talvez uma quantia trivial, mas ainda assim ...
fonte
A explicação para o uso de conexões persistentes está obviamente reduzindo a quantidade de conexões que são bastante caras, apesar do fato de serem consideravelmente mais rápidas com o MySQL em comparação com outros bancos de dados.
O primeiro problema com conexões persistentes ...
Se você estiver criando milhares de conexões por segundo, normalmente não garante que ele permaneça aberto por muito tempo, mas o Sistema Operacional o faz. Com base no protocolo TCP / IP, as portas não podem ser recicladas instantaneamente e também precisam investir um tempo no estágio "FIN" aguardando antes de serem recicladas.
O segundo problema ... usando muitas conexões do servidor MySQL.
Muitas pessoas simplesmente não percebem que você é capaz de aumentar a variável * max_connections * e obter mais de 100 conexões simultâneas com o MySQL, outras foram derrotadas por problemas mais antigos do Linux, devido à incapacidade de transmitir mais de 1024 conexões com o MySQL.
Permite falar agora sobre por que as conexões persistentes foram desativadas na extensão mysqli. Apesar de você poder usar mal as conexões persistentes e obter um desempenho ruim, esse não foi o principal motivo. O motivo real é - você pode obter muito mais problemas com ele.
Conexões persistentes foram colocadas no PHP durante o MySQL 3.22 / 3.23, quando o MySQL não era tão difícil, o que significa que você pode reciclar conexões facilmente sem problemas. No entanto, em versões posteriores, ocorreu a quantidade de problemas - Se você reciclar a conexão que possui transações não confirmadas, terá problemas. Se você reciclar conexões com configurações personalizadas de conjuntos de caracteres, estará em perigo novamente, bem como sobre possíveis variáveis transformadas por sessão.
Um problema com o uso de conexões persistentes é que ele não é dimensionado tão bem. Para quem tem 5.000 pessoas conectadas, você precisará de 5.000 conexões persistentes. Para afastar o requisito de persistência, você pode atender a 10000 pessoas com quantidade semelhante de conexões, porque elas estão em posição de compartilhar conexões individuais quando não estão com elas.
fonte
Eu só estava me perguntando se uma solução parcial seria ter um pool de conexões de uso único. Você pode gastar tempo criando um pool de conexões quando o sistema estiver com pouco uso, até um limite, entregá-los e eliminá-los quando eles estiverem concluídos ou atingidos o tempo limite. Em segundo plano, você cria novas conexões à medida que elas são tomadas. Na pior das hipóteses, isso deve ser tão lento quanto criar a conexão sem o pool, assumindo que o estabelecimento do link seja o fator limitante?
fonte