Haproxy + netty: maneira de evitar exceções na redefinição de conexão?
Estamos usando haproxy na frente de um back-end netty-3.6-run. Estamos lidando com um grande número de conexões, algumas das quais podem ser duradouras.
Agora, o problema é que, quando o haproxy fecha uma conexão para reequilibrar, o faz enviando um tcp-RST. Quando a classe sun.nio.ch empregada por netty vê isso, lança uma IOException: "Conexão redefinida pelo par".
Vestígio:
sun.nio.ch.FileDispatcherImpl.read0(Native Method):1 in ""
sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39):1 in ""
sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:225):1 in ""
sun.nio.ch.IOUtil.read(IOUtil.java:193):1 in ""
sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:375):1 in ""
org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:64):1 in ""
org.jboss.netty.channel.socket.nio.AbstractNioWorker.process(AbstractNioWorker.java:109):1 in ""
org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:312):1 in ""
org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:90):1 in ""
org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:178):1 in ""
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145):1 in ""
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615):1 in ""
java.lang.Thread.run(Thread.java:724):1 in ""
Isso causa os seguintes problemas por configuração:
opção http-pretend-keepalive
É isso que funciona melhor (como o haproxy parece fechar a maioria das conexões com um FIN em vez do RST), mas ainda produz cerca de 3 exceções por servidor por segundo. Além disso, ele neutraliza efetivamente o balanceamento de carga, porque algumas conexões de entrada são muito antigas com uma taxa de transferência muito alta: com a atividade de fingir de manutenção, elas nunca são reequilibradas para outro servidor por haproxy.
opção http-keep-alive
Como nosso back-end espera que as conexões keep-alive sejam realmente mantidas ativas (e, portanto, não as fecha por conta própria), essa configuração equivale a todas as conexões que acabam gerando uma exceção, que por sua vez trava nossos servidores. Tentamos adicionar prefer-last-server, mas isso não ajuda muito.
opção http-server-close
Teoricamente, isso deve funcionar para balanceamento de carga adequado e sem exceções. No entanto, parece que depois que nossos servidores de back-end respondem, há uma corrida sobre qual lado envia seu RST primeiro: haproxy ou nosso ChannelFutureListener.CLOSE registrado. Na prática, ainda temos muitas exceções e nossos servidores travam.
Curiosamente, as exceções geralmente ganham mais, mais trabalhadores fornecemos aos nossos canais. Eu acho que acelera ler mais do que escrever.
De qualquer forma, eu li as diferentes opções de canal e soquete no netty e haproxy por um tempo e realmente não encontrei nada que parecesse uma solução (ou funcionou quando tentei).