Error -76719 / Erro -76719
If you see this error, you're most likely using a J2EE application server, and you have a firewall between it and your database (original version http://informix-technology.blogspot.com/2015/02/error-76719-erro-76719.html)
English version
I've found this error many times. And recently it happened again while working on a customer. Invariably it happens on application servers with a firewall between them and the database. The error description is:
-79716 System or internal error.
An operating or runtime system error or a driver internal error
occurred.
The accompanying message describes the problem.
Often the error also shows this message:
java.net.SocketException: Broken pipe
If you find this, most likely you have a firewall between the database and the application server and your firewall is forcing the closing of the sockets. Why would it do that? Typically the firewalls are configured to close connections they consider "idle" for a period of time. And usually in an application server, using connection pooling it may happen that a specific connection is not used for many minutes. Without traffic in the connection the firewall will decide the connecting is "forgotten" and will close it. To be honest this is the part I never was able to figure out... when a system decides to close a socket, a signal (13) is usually sent to the endpoints. Upon receiving the signal, the client and server learn the connection was broken and they can create another one, or raise an appropriate error. The problem I'm used to, is that the client (in this case the J2EE application server) never receive (or ignore?) that signal. So they don't "know" the socket is not there anymore. Instead they keep the socket reference associated with a connection that is part of their pools. Once a client application requests a connection from the pool, it may get one of these "phantom" connections. When it tries to send the SQL request, the exception is generated and the error is raised.
All this explains the problem. But what we really want is the solution. And that is a bit more complex to explain but trivial to implement. In fact there are two solutions:
- Have you network administrators change the firewall rules either to increment the period before considering a connection as stale, or to ignore Informix connections. I never saw a situation where this happened. Somehow the network admins act like dictators and they refuse any change.
- Force some sort of traffic through the connection so that the firewall doesn't think the connection is stale
- That the OS "decides" to activate the mechanism (as we'll see we can direct Informix to ask for it)
- That we configure the "interval" at which a "probe" will be sent
- That we configure the maximum time to wait for an answer
- Eventually that we configure the number of probes to send before assuming the connection is not good if no answer is received
- On the server side just adding a "k=1" to the $INFORMIXSQLHOSTS options field
- On the client (JDBC) side just add the property IFX_SOC_KEEPALIVE and set it to true. Note that this is available only on version 4.10.JC6+
Another option on some application servers would be to "test" the connections (usually requires some dummy and simple query), or define a maximumage for the connections. But these configurations depend on your application server
A final note: Sometimes we need to check if an opened socket is using the keepalive option. In most operating systems we can use the lsof command with the option "-Tf". This adds the socket options used to open the socket (or added later) to the output. But this option does not work on Linux. In this OS we can use the netstat command with the "-o" option:
castelo@primary:informix-> netstat -no | grep ":10000"
tcp 0 0 192.168.142.202:10000 192.168.142.202:33053 ESTABLISHED keepalive (5332.90/0/0)
tcp 0 0 192.168.142.202:33053 192.168.142.202:10000 ESTABLISHED keepalive (5332.88/0/0)
castelo@primary:informix->
The number shown between parenthesis is the counter till the sending of the next probe.
Versão Portuguesa
Encontrei este erro muitas vezes. E voltou a acontecer novamente enquanto estava num cliente. Invariavelmente isto acontece quando existe um firewall entre um servidor aplicacional (normalmente J2EE) e a base de dados. A descrição do erro é:
-79716 System or internal error.
An operating or runtime system error or a driver internal error
occurred.
The accompanying message describes the problem.
Muitas vezes aparece também a seguinte mensagem:
java.net.SocketException: Broken pipe
Se encontrar isto, a probabilidade é que exista um firewall entre o servidor aplicacional e a base de dados que esteja a fechar os sockets de comunicação. Porque o haveria de fazer? Porque tipicamente os firewalls estão configurados para fecharem as ligações que consideram inativas por um determinado período de tempo. E é normal que num servidor aplicacional que utilize connection pooling uma determinada conexão pode não ser usada durante largos minuto. Sem tráfego na ligação o firewall irá considerá-la como "esquecida" e fechá-la-á. Para ser honesto esta é a parte que nunca percebi.... Quando um sistema quebra uma ligação (por interrupção física da comunicação por exemplo) a aplicação associada ao socket normalmente recebe um sinal (13). Ao receber este sinal a aplicação sabe que a conexão foi fechada e pode tomar as ações apropriadas, como recriá-la ou gerar um erro.
O problema a que me habituei é que o cliente (neste caso o servidor aplicacional J2EE) nunca recebe (ou porventura ignora?) o sinal. Por isso não "sabe" que o socket já não existe. E portanto mantém uma referência a um socket que já não existe na sua pool de conexões. Quando uma aplicação pede uma conexão dessa pool pode receber a referência "fantasma". E ao tentar usá-la para enviar uma instrução SQL para a base de dados é gerada a exceção com o erro referido.
Tudo isto explica o problema. Mas o que queremos realmente é resolvê-lo. E isso é um pouco mais complicado de explicar, mas simples de implementar. De facto há duas soluções:
- Fazer com que os administradores de rede mudem as regras do firewall para aumentar o período de inatividade aceitável ou para ignorar completamente as conexões ao informix. Nunca presenciei uma situação onde tal acontecesse. Por algum motivo que me ultrapassa os administradores de rede atuam como ditadores e recusam qualquer mudança
- Forçar o envio de algum tipo de tráfego através de cada conexão para que o firewall não a considere "inativa"
- Que o SO "decida" ativar o mecanismo para determinadas conexões (como veremos podemos configurar o Informix para requisitar isto ao SO)
- Que se configure o "intervalo" de teste das ligações (quando serão enviadas as "sondas")
- Que se configure o tempo máximo para receção da resposta
- Eventualmente que se configurem o número de "sondas" a serem enviadas e que fiquem sem resposta antes de o SO considerar a ligação como "morta"
Atrás referi que é possível forçar o Informix a activar este mecanismo no SO. Atualmente podemos fazer isso no lado do servidor e no lado do cliente (JDBC)::
- No lado do servidor basta acrescentar a opção "k=1" no campo das opções no $INFORMIXSQLHOSTS
- No cliente (JDBC) basta adicionar a propriedade IFX_SOC_KEEPALIVE com o valor true. Note-se que isto só está disponível nas versões 4.10.JC6+
Outra opção em alguns servidores aplicacionais seria "testar" as conexões (normalmente com uma query simples e rápida), ou definir uma idade máxima para as conexões. Mas estas configurações dependem de servidor para servidor.
Uma nota final: Por vezes é necessário perceber ou verificar se um socket aberto tem mesmo a opção de keepalive ativa. Na maioria dos sistemas operativos podemos usar o comando lsof com a opção "-Tf". Isto acrescenta as flags usadas na abertura do socket. Mas esta opção não funciona em Linux. Neste SO pode usar-se o "netstat" com a opção "-o":
castelo@primary:informix-> netstat -no | grep ":10000"
tcp 0 0 192.168.142.202:10000 192.168.142.202:33053 ESTABLISHED keepalive (5332.90/0/0)
tcp 0 0 192.168.142.202:33053 192.168.142.202:10000 ESTABLISHED keepalive (5332.88/0/0)
castelo@primary:informix->
O número entre parenteses é o contador até ao envio da próxima "sonda"