Estou trabalhando com um desenvolvedor que está lutando para interromper o seguinte erro:
O servidor interromperá a conexão porque o driver cliente enviou várias solicitações enquanto a sessão está no modo de usuário único. Esse erro ocorre quando um cliente envia uma solicitação para redefinir a conexão enquanto ainda há lotes em execução na sessão ou quando o cliente envia uma solicitação enquanto a sessão está redefinindo uma conexão. Entre em contato com o fornecedor do driver do cliente.
Quando esse erro ocorre, um resultado típico é uma sessão que está mantendo bloqueios, mas não tem nenhum SQL em execução (nenhuma linha sys.dm_exec_requests
para o session_id) e causa bloqueio até que seja eliminado. A causa do bloqueio é direta, mas como impedir que o erro ocorra não é.
Alguns fatos sobre o problema:
- O cliente está usando Entity Framework (sim, eu sei...), com MARS habilitado (sim, eu sei...)
- A versão do SQL Server é 10.00.5844 (SQL Server 2008 SP3 CU12). Eles provavelmente não atualizarão as versões principais sem testes extensivos, mas a aplicação de uma CU mais recente é viável.
- O programa cliente aparece
sys.dm_exec_connections
como .Net SqlClient Data Provider - A conexão aberta parece definitivamente ter o MARS ativado, como
net_transport
nossys.dm_exec_connections
showsSession
. - Disseram-me que a string de conexão do aplicativo tem processamento assíncrono ativado, de acordo com o comentário de Matt Neerincx neste tópico (não tenho acesso aos servidores de aplicativos para confirmar isso sozinho):
Se você definir Async=true na cadeia de conexão, isso deve evitar esse problema. Se você estiver usando MARS e usando a mesma conexão em vários threads simultâneos, o que pode acontecer é que a chamada para redefinir a conexão pode ficar um pouco atrasada e acionar esse erro. Se você definir Async=true, executaremos um bloqueio adicional no driver cliente para evitar que isso aconteça.
Mais informações sobre esse erro são escassas. Parece sugerir que o programa do cliente está chamando sp_reset_connection
enquanto um lote ainda está em execução. Eu poderia configurar um rastreamento para confirmar isso, mas teria que registrar muitas atividades não relacionadas e o problema está acontecendo apenas uma vez a cada poucos dias. Além disso, não tenho certeza se o desenvolvedor seria capaz de tirar proveito dessa evidência para resolver o problema.
Existe alguma outra técnica que eu possa usar como DBA ou administrador de sistema para solucionar isso ainda mais, ou qualquer coisa que eu possa sugerir ao desenvolvedor que possa fornecer a ele informações úteis ou tornar o problema menos provável de acontecer?
Não vejo em lugar nenhum qual versão do .NET Framework está sendo usada, mas como essa pergunta foi feita em maio de 2014 e o .NET Framework versão 4.5 foi lançado em 15/08/2012, o seguinte nota em SqlConnection.ConnectionString para a palavra-chave
Asynchronous Processing
/Async
parece relevante:Portanto, pode ser útil descobrir a versão exata do Entity Framework que está sendo usada e a versão de destino do .NET Framework.
No entanto, parece que esse problema pode ser resultado do pool de conexões. Suspeito do pool de conexões porque, após a mensagem de erro sobre o fechamento da conexão, a sessão ainda estava ativa.
A primeira coisa a tentar é simplesmente desabilitar o pool de conexões adicionando o seguinte à string de conexão:
Se o problema nunca mais voltar, provavelmente esse foi o problema. Hesito em dizer que esse era o problema, pois não é exatamente uma prova. Poderia ter apenas reduzido a frequência de "uma vez a cada poucos dias" para uma vez a cada poucas semanas ou até meses. Mas, se isso melhorar as coisas, mas o aplicativo acessar o servidor com frequência e você preferir usar o pool de conexões, se possível, tente reintroduzir o pool de conexões, mas em sentido limitado: você pode definir um valor baixo para o
Connection Lifetime
palavra-chave:Isso fará com que as conexões sejam fechadas ao retornar ao pool de conexões, se tiverem mais de 2 segundos. Isso permite que uma série de execuções de consultas rápidas ocorram sem que cada uma delas gaste tempo estabelecendo a conexão, ao mesmo tempo em que não permite que a conexão permaneça por aí, possivelmente segurando bloqueios, etc.
Mesmo que o erro ainda ocorra, por não ter um pool de conexões mantendo a sessão e a conexão vivas, isso deve permitir uma limpeza adequada, liberação de bloqueios etc.
Só para deixar claro, já que foi questionado nos comentários sobre a questão: Multiple Active Result Sets (MARS) é usado pelo Entity Framework para fazer Lazy Loading. Portanto, se o aplicativo foi desenvolvido para usar o Lazy Loading, desativar o MARS não é uma opção.