Haproxy + netty: способ предотвращения исключений при сбросе соединения?
Мы используем haproxy перед бэкендом, запускаемым netty-3.6. Мы работаем с огромным количеством соединений, некоторые из которых могут быть давними.
Теперь проблема в том, что, когда haproxy закрывает соединение для восстановления баланса, оно делает это, отправляя tcp-RST. Когда класс sun.nio.ch, используемый netty, видит это, он генерирует IOException: «Сброс соединения по одноранговому узлу».
Трассировка:
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 ""
Это вызывает следующие проблемы для каждой конфигурации:
опция http-pretend-keepalive
Это то, что работает лучше всего (поскольку haproxy, по-видимому, закрывает большинство соединений с помощью FIN, а не RST), но все равно выдает около 3 исключений на сервер в секунду. Кроме того, он эффективно нейтрализует балансировку нагрузки, поскольку некоторые входящие соединения очень продолжительны и имеют очень высокую пропускную способность: с помощью pretend-keepalive они никогда не перебалансируются на другой сервер с помощью haproxy.
опция http-keep-alive
Поскольку наш бэкэнд ожидает, что соединения keep-alive действительно будут поддерживаться (и, следовательно, не будут закрывать их сами по себе), этот параметр равняется каждому соединению, в конечном итоге приводящему к одному исключению, что, в свою очередь, приводит к сбою наших серверов. Мы попытались добавить предпочитаемый-последний-сервер, но это не сильно помогает.
опция http-server-close
Теоретически это должно работать как для правильной балансировки нагрузки, так и без исключений. Однако, похоже, что после ответа наших backend-серверов возникает гонка относительно того, какая сторона отправляет свой RST в первую очередь: haproxy или наш зарегистрированный ChannelFutureListener.CLOSE. На практике мы все еще получаем слишком много исключений, и наши серверы аварийно завершают работу.
Интересно, что, как правило, исключений становится больше, чем больше работников мы снабжаем нашими каналами. Я предполагаю, что это ускоряет чтение больше, чем письмо.
В любом случае, я некоторое время читал о различных каналах и сокетах в netty, а также в haproxy и не нашел ничего, что звучало бы как решение (или работало, когда я его пробовал).