我们在netty-3.6运行的后端使用haproxy。我们正在处理大量的连接,其中一些可能是长期存在的。
现在的问题是,当haproxy关闭连接以实现重新平衡时,它会通过发送tcp-RST来实现。当netty使用的sun.nio.ch-class看到这个时,会抛出一个IOException:“peer by peer”。
跟踪:
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个异常。此外,它实际上是neuters负载平衡,因为一些传入连接非常长,并且具有非常高的吞吐量:使用pretend-keepalive,它们永远不会被haproxy重新平衡到另一台服务器。
选项http-keep-alive
由于我们的后端期望保持活动连接真正保持活动(因此不会自行关闭它们),因此此设置相当于每个连接最终会导致一个异常,从而导致我们的服务器崩溃。我们尝试添加prefer-last-server,但它没有多大帮助。
选项http-server-close
理论上,这应该适用于正确的负载均衡和无异常。但是,似乎在我们的后端服务器响应之后,有一个竞争对手首先发送其RST:haproxy或我们注册的ChannelFutureListener.CLOSE。在实践中,我们仍然会遇到太多异常而且我们的服务器崩溃了。
有趣的是,例外情况通常会越多,我们为渠道提供的工作人员就越多。我想它的阅读速度超过了写作速度。
无论如何,我已经阅读了netty中的不同频道和套接字以及haproxy一段时间了,并没有找到任何听起来像解决方案的东西(或者在我尝试时工作)。
答案 0 :(得分:6)
注意:根据我的理解,您不必担心连接重置异常,除非您最后使用保持连接连接建立连接池。
在使用HAProxy进行服务时,我遇到了类似的问题大量连接重置(RST)(在10秒的窗口中,基于负载,它是5-20倍)。
这就是我修复它的方法。
我们有一个系统,其中连接始终保持活动状态(在HTTP连接级别保持活动始终为真。即,一旦建立连接,我们就会重新使用HTTP Connection pool中的此连接进行后续调用,而不是创建新的。)
现在,根据我的调试代码和 TCP Dump ,我发现RST是在下面的场景中从HAProxy抛出的
在空闲连接时,当HAProxy的timeout client或timeout server到达时。
我们将此配置设置为60秒。由于我们有一个连接池,当服务器上的负载减少时,会导致其中一些连接在一分钟内没有被使用。
因此,这些连接由HAProxy使用RST信号关闭。
未设置HAProxy的option prefer-last-server时 根据文件:
真正的用途是发送到服务器的保持活动连接。当这个 使用选项,haproxy将尝试重用相同的连接 连接到服务器而不是重新平衡到另一台服务器, 导致关闭。
由于未设置此项,因此每次从池中重新使用连接时,HAProxy都会使用RST Signal关闭此连接并为另一台服务器创建一个新连接(因为我们的Load Balancer已设置为圆形-Robin )。 这使得整个Connection Pooling变得混乱并无法使用。
所以配置工作正常:
通过这些配置,我们可以
希望这会有所帮助!!
答案 1 :(得分:2)
Tomcat Nio-handler正好:
} catch (java.net.SocketException e) {
// SocketExceptions are normal
Http11NioProtocol.log.debug
(sm.getString
("http11protocol.proto.socketexception.debug"), e);
} catch (java.io.IOException e) {
// IOExceptions are normal
Http11NioProtocol.log.debug
(sm.getString
("http11protocol.proto.ioexception.debug"), e);
}
所以看起来内部sun-class(sun.nio.ch.FileDispatcherImpl)的初始抛出真的是不可避免的,除非你自己重新实现它们。
答案 2 :(得分:0)
'通过对等方重置Connecton'通常是由写入已被另一端关闭的连接引起的。这会导致对等体发送RST。但几乎可以肯定已经发送了一个FIN。我会在这里重新审视你的假设。很少有应用程序故意发送RST。您最可能遇到的是应用程序协议错误。如果这是不可避免的,那么ECONNRESET也是如此。
答案 3 :(得分:0)
尝试
不确定重新发送,但 http-tunnel 修复了我们的问题。
答案 4 :(得分:0)
从haproxy 1.5开始,它现在将FIN
(FIN,ACK
)发送到后端服务器,而harpoxy 1.4用于发送RST
。这可能对这种情况有所帮助。
如果可以找到此文件,我将添加链接...