良玉的博客 点点滴滴,积水成河_良玉的博客_页游、手游linux运维工程师之路

fastdfs errno: 99, error info: Cannot assign requested address

[2014-01-18 12:42:18] ERROR - file: tracker_proto.c, line: 590, connect to tracker server 111.111.111.111:22122 fail, errno: 99, error info: Cannot assign requested address
[2014-01-18 12:42:21] ERROR - file: tracker_proto.c, line: 590, connect to tracker server 111.111.111.111:22122 fail, errno: 99, error info: Cannot assign requested address
[2014-01-18 12:42:24] ERROR - file: tracker_proto.c, line: 590, connect to tracker server 111.111.111.111:22122 fail, errno: 99, error info: Cannot assign requested address
[2014-01-18 12:42:28] ERROR - file: tracker_proto.c, line: 590, connect to tracker server 111.111.111.111:22122 fail, errno: 99, error info: Cannot assign requested address
[2014-01-18 12:42:31] ERROR - file: tracker_proto.c, line: 590, connect to tracker server 111.111.111.111:22122 fail, errno: 99, error info: Cannot assign requested address
[2014-01-18 12:42:34] ERROR - file: tracker_proto.c, line: 590, connect to tracker server 111.111.111.111 22122 fail, errno: 99, error info: Cannot assign requested address


发现错误日志如上
网络搜索得到一个解释:客户端频繁的连服务器,由于每次连接都在很短的时间内结束,导致很多的TIME_WAIT,以至于用光了可用的端口号,所以新的连接没办法绑定端口,即“Cannot assign requested address”
其实书上看过 close时候只是把fd的使用数-1,但是还没有回收链接,这时候需要修改系统参数,快速回收使用数已经为0 的链接(即正常close的df)。
 
解决办法:

sysctl -w net.ipv4.tcp_tw_recycle=1 表示开启TCP连接中TIME-WAIT sockets的快速回收,重启fastdfs



(还有一个 sysctl -w net.ipv4.tcp_timestamps=1  开启对于TCP时间戳的支持,若该项设置为0,则上面一项设置不起作用)

解释:
近来线上陆续出现了一些connect失败的问题,经过分析试验,最终确认和proc参数tcp_tw_recycle/tcp_timestamps相关;
1. 现象
    第一个现象:模块A通过NAT网关访问服务S成功,而模块B通过NAT网关访问服务S经常性出现connect失败,抓包发现:服务S端已经收到了syn包,但没有回复synack;另外,模块A关闭了tcp timestamp,而模块B开启了tcp timestamp;
    第二个现象:不同主机上的模块C(开启timestamp),通过NAT网关(1个出口ip)访问同一服务S,主机C1 connect成功,而主机C2 connect失败;

2. 分析
    根据现象上述问题明显和tcp timestmap有关;查看linux 2.6.32内核源码,发现tcp_tw_recycle/tcp_timestamps都开启的条件下,60s内同一源ip主机的socket connect请求中的timestamp必须是递增的。
    源码函数:tcp_v4_conn_request(),该函数是tcp层三次握手syn包的处理函数(服务端);
    源码片段:
       if (tmp_opt.saw_tstamp &&
            tcp_death_row.sysctl_tw_recycle &&
            (dst = inet_csk_route_req(sk, req)) != NULL &&
            (peer = rt_get_peer((struct rtable *)dst)) != NULL &&
            peer->v4daddr == saddr) {
            if (get_seconds() < peer->tcp_ts_stamp + TCP_PAWS_MSL &&
                (s32)(peer->tcp_ts - req->ts_recent) >
                            TCP_PAWS_WINDOW) {
                NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
                goto drop_and_release;
            }
        }
        tmp_opt.saw_tstamp:该socket支持tcp_timestamp
        sysctl_tw_recycle:本机系统开启tcp_tw_recycle选项
        TCP_PAWS_MSL:60s,该条件判断表示该源ip的上次tcp通讯发生在60s内        TCP_PAWS_WINDOW:1,该条件判断表示该源ip的上次tcp通讯的timestamp 大于 本次tcp

    分析:主机client1和client2通过NAT网关(1个ip地址)访问serverN,由于timestamp时间为系统启动到当前的时间,因此,client1和client2的timestamp不相同;根据上述syn包处理源码,在tcp_tw_recycle和tcp_timestamps同时开启的条件下,timestamp大的主机访问serverN成功,而timestmap小的主机访问失败;

    参数:/proc/sys/net/ipv4/tcp_timestamps - 控制timestamp选项开启/关闭
          /proc/sys/net/ipv4/tcp_tw_recycle - 减少timewait socket释放的超时时间

3. 解决方法
    echo 0 > /proc/sys/net/ipv4/tcp_tw_recycle;
    tcp_tw_recycle默认是关闭的,有不少服务器,为了提高性能,开启了该选项;
    为了解决上述问题,个人建议关闭tcp_tw_recycle选项,而不是timestamp;因为 在tcp timestamp关闭的条件下,开启tcp_tw_recycle是不起作用的;而tcp timestamp可以独立开启并起作用。
    源码函数:  tcp_time_wait()
    源码片段:
        if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp)
            recycle_ok = icsk->icsk_af_ops->remember_stamp(sk);
        ......
       
        if (timeo < rto)
            timeo = rto;

        if (recycle_ok) {
            tw->tw_timeout = rto;
        } else {
            tw->tw_timeout = TCP_TIMEWAIT_LEN;
            if (state == TCP_TIME_WAIT)
                timeo = TCP_TIMEWAIT_LEN;
        }

        inet_twsk_schedule(tw, &tcp_death_row, timeo,
                   TCP_TIMEWAIT_LEN);

    timestamp和tw_recycle同时开启的条件下,timewait状态socket释放的超时时间和rto相关;否则,超时时间为TCP_TIMEWAIT_LEN,即60s;

    内核说明文档 对该参数的介绍如下:
    tcp_tw_recycle - BOOLEAN
    Enable fast recycling TIME-WAIT sockets. Default value is 0.
    It should not be changed without advice/request of technical
    experts.


标签: fastdfserrerrno

作者:良玉 分类:FastDFS 浏览:2052 评论:0
留言列表
发表评论
来宾的头像