Haproxy + netty: ¿Una forma de evitar excepciones en el restablecimiento de la conexión?
Estamos utilizando haproxy delante de un backend de netty 3.6-run. Estamos manejando una gran cantidad de conexiones, algunas de las cuales pueden ser de larga data.
Ahora el problema es que cuando el haproxy cierra una conexión para rebalancearlo, lo hace enviando un tcp-RST. Cuando la clase sun.nio.ch empleada por netty ve esto, lanza una excepción IOException: "Restablecimiento de la conexión por par".
Rastro:
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 ""
Esto causa los siguientes problemas por configuración:
Opción http-pretend-keepalive
Esto es lo que funciona mejor (ya que el haproxy parece cerrar la mayoría de las conexiones con un FIN en lugar de RST), pero aún produce aproximadamente 3 excepciones por servidor por segundo. Además, neutraliza de manera efectiva el equilibrio de carga, ya que algunas conexiones entrantes son muy antiguas y tienen un rendimiento muy alto: con el pretendida-keepalive, nunca se reequilibran a otro servidor por haproxy.
Opción http-keep-alive
Debido a que nuestro backend espera que las conexiones se mantengan vivas (y, por lo tanto, no las cierre por sí mismas), esta configuración equivale a que cada conexión eventualmente genera una excepción, lo que a su vez bloquea nuestros servidores. Intentamos agregar prefer-last-server, pero no ayuda mucho.
Opción http-server-close
Esto debería funcionar teóricamente tanto para el balanceo de carga adecuado como para no tener excepciones. Sin embargo, parece que después de que nuestros servidores backend respondan, hay una carrera en cuanto a qué lado envía su RST primero: haproxy o nuestro registrado ChannelFutureListener.CLOSE. En la práctica, todavía tenemos demasiadas excepciones y nuestros servidores fallan.
Curiosamente, las excepciones generalmente obtienen más, cuanto más trabajadores suministramos a nuestros canales. Supongo que acelera la lectura más que la escritura.
De todos modos, he leído sobre las diferentes opciones de canal y socket en netty y haproxy desde hace un tiempo y realmente no encontré nada que sonara como una solución (o funcionó cuando lo probé).