美文网首页
Cannot assign requested address问

Cannot assign requested address问

作者: 小小辉 | 来源:发表于2017-01-07 15:43 被阅读0次

    1.背景

        最近一个项目中,出现了java.net.ConnectException:Cannotassignrequestedaddress的异常。通过查找资料、分析后,认为是由于程序对外建立新连接,结果本地端口已经用完导致的异常。

     2.问题原因

        为什么会出现这种情况呢?就要从linux的TCP/IP协议栈说起了。 先看一下TCP/IP的状态图:

    主动关闭连接的一方,连接会处在TIME-WAIT的状态下,需要等2MSL时间后,系统才会回收这条连接,端口才可以继续被使用。

        我们的项目场景是需要发送大量的短连接。这样在高并发的场景下,就会出现端口不足,从而抛出java.net.ConnectException:Cannotassignrequestedaddress的异常。

    3.解决方案

    3.1 横向扩展

      简单就是加机器,减少单台服务器的TCP创建次数。

      不过这样需要注意几个地方:

        第一,项目是否可以支持横向扩展,我们的项目是基于kafka的consumer,很难简单通过加机器做到横向扩展。

        第二,需要明确单台服务器的处理瓶颈,如果随着业务量的不断增加,还是会出现这种异常。需要对应业务量的增加,不断动态调整服务器数量。

    3.2 调整linux内核参数

        linux内核中存在两个参数:

          net.ipv4.tcp_tw_reuse = 1表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;

          net.ipv4.tcp_tw_recycle = 1表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。

        在/etc/sysctl.conf文件中加入上述参数,然后执行/sbin/sysctl -p让参数生效。

        但是由于我们项目在docker中运行,并且很难单纯通过增加机器进行横向扩展。当时从网上找到了docker调整网络内核参数的方式,但是经过试验,没有效果。

    3.3 针对该异常进行单独处理

        如果在对实时性要求不是特别高的场景下,可以采用如果出现这种异常,就暂停发送程序,类似一种限流保护的机制,等到可以发送之后,再进行发送。 

        这样处理,需要能够明确项目本身或者项目的使用方能够做缓冲。(我们项目的从kafka拉去消息,暂停发送后,将消息都缓存到了kafka中,是不存在风险的)。

    3.4 修改TCP短连接为长连接

        出现这种问题,归根到底还是因为需要频繁创建大量的连接。那么,可不可以修改一种方式避免,避免频繁创建大量的TCP短连接。这需要根据项目的具体原因进行评估。

    4.总结

        虽然是java程序员,还是需要了解操作系统的底层细节。这样,出现问题可以从多个角度、多个层次去分析解决。

    5.引用

    5.1 TCP状态变迁图及状态说明

    5.2 发现大量的TIME_WAIT解决办法

    5.3 对docker container进行内核参数调优

    相关文章

      网友评论

          本文标题:Cannot assign requested address问

          本文链接:https://www.haomeiwen.com/subject/palhdttx.html