Haproxy + netty:防止连接重置异常的方法?

 我爱上帝爱我 发布于 2023-01-29 15:00

我们在netty-3.6运行的后端使用haproxy.我们正在处理大量的连接,其中一些可能是长期的.

现在的问题是,当haproxy关闭连接以实现重新平衡时,它会通过发送tcp-RST来实现.当netty使用的sun.nio.ch-class看到这个时,它会抛出一个IOException:"Connection 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一段时间了,并没有真正找到任何听起来像解决方案的东西(或者当我尝试它时工作).

1 个回答
  • 注意:根据我的理解,您不必担心连接重置异常,除非您最后使用保持连接连接建立连接池.

    在使用HAProxy进行服务时,我遇到了类似的问题,即大量的连接重置(RST)(在10秒的窗口中,基于负载,它是5-20倍).
    这是我修复它的方式.

    我们有一个系统,其中连接始终保持活动状态(在HTTP连接级别保持活动始终是真的.即,一旦建立连接,我们就会从HTTP连接池重用此连接以用于后续调用而不是创建新连接.)

    现在,根据我在CodeTCP Dump中的调试,我发现RST是在下面的场景中从HAProxy抛出的

      在空闲连接上达到HAProxy的超时客户端 或超时服务器时.
      我们将此配置设置为60秒.由于我们有一个连接池,当服务器上的负载减少时,会导致其中一些连接在一分钟内没有被使用.
      然后,这些连接由HAProxy使用RST信号关闭.

      当没有设置HAProxy的选项prefer-last-server时.
      根据文件:

    真正的用途是发送到服务器的保持活动连接.使用此选项时,haproxy将尝试重用连接到服务器的相同连接,而不是重新平衡到另一个服务器,从而导致关闭连接.

    由于未设置此选项,因此每次从池中重新使用连接时,HAProxy都会使用RST Signal关闭此连接,并为不同的服务器创建一个新连接(因为我们的Load Balancer设置为循环).这搞乱了,整个连接池无法使用.

    所以配置工作正常:

      option prefer-last-server:因此将重用现有的服务器连接.
      注意:这不会导致负载均衡器在新服务器上使用以前的服务器进行新连接.新连接的决策始终基于负载平衡算法.此选项仅适用于客户端和服务器之间已存在的现有连接.
      当我使用此选项进行测试时,即使之前的连接已发送到server1,新连接仍会转到server2.

      balance leastconn:使用Round robinKeep-Alive,可能会出现与单个服务器连接的偏差.(假设只有2台服务器,当一台服务器因部署而关闭时,所有新连接都将开始转移到另一台服务器.所以即使server2启动,循环仍然会向server1分配一个新请求,一分配给尽管server1在其末端有很多连接,所以服务器的负载永远不会完全平衡.).

      将HAProxy的超时客户端 或超时服务器设置为10分钟.这增加了我们的连接闲置的时间.

      实现了IdleConnectionMonitor:当超时设置为10m时,来自HAProxy的RST的可能性降低但未消除.
      为了完全删除它,我们添加了一个IdleConnectionMonitor,它负责关闭空闲超过9分钟的连接.


    通过这些配置,我们可以

    消除连接重置

    获取连接池工作

    确保负载均衡在服务器上均匀发生,无论它们何时启动.

    希望这可以帮助!!

    2023-01-29 15:01 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有