首页 > 其他分享 >[转帖]一个NAT问题引起的思考

[转帖]一个NAT问题引起的思考

时间:2024-06-20 13:31:39浏览次数:22  
标签:NAT tw tcp 转帖 TCP 思考 timestamp recycle

https://perthcharles.github.io/2015/08/27/timestamp-NAT/

 


问题

当服务器同时开启tcp_timestamps和tcp_tw_recycle选项时,会导致客户反馈连接成功率降低的情况。
but why ???


公网NAT的存在

NAT的全称是:Network Address Translation
一个具体的例子就是家用的局域网络。
当使用一台无线路由器进行上网拨号后,其他的终端设备只要连接进入该无线路由器的WiFi
网络内就可以访问外网了。此时正是NAT在发挥作用。
每一台终端设备在接入无线路由器后,只是获得一个局域网IP地址,而当你在百度输入我的IP的时候
你看到的IP地址则是你无线路由器的公网IP地址。家用无线路由器完成的一个主要工作正是将终端
的局域网IP地址进行NAT转换为公网IP地址。

从上面这个简单的例子可以看到NAT在真实的互联网中是普遍存在的,比如你所在学校,单位都会一定程度上的使用NAT机制。


Per-host PAWS机制

这篇介绍TCP timestamp
的文章中提到了一种针对per-host的PAWS机制。这种机制要求所有来个同一个host IP的TCP数据包的
timestamp值是递增的。当收到一个timestamp值,小于服务端记录的对应值后,则会认为这是一个过期的数据包,然后会将其丢弃。


解答问题

至此就不难解释为什么在同时开启tcp_timestamp和tcp_tw_recycle时,会遇到客户反馈连接成功率降低的情况了,基本的逻辑如下:

1. 同时开启tcp_timestamp和tcp_tw_recycle会启用TCP/IP协议栈的per-host的PAWS机制
2. 经过同一NAT转换后的来自不同真实client的数据流,在服务端看来是于同一host打交道
3. 虽然经过同一NAT转化,但由于不同真实client会携带各自的timestamp值
因而无法保证整过NAT转化后的数据包携带的timestamp值严格递增
4. 当服务器的per-host PAWS机制被触发后,会丢弃timestamp值不符合递增条件的数据包

解决办法就是不建议同时开启tcp_timestamp和tcp_tw_recycle。
那到底怎么配置?

开启tcp_timestamp,但不要开tcp_tw_recycle  
开启tcp_timestamp,但不要开tcp_tw_recycle  
开启tcp_timestamp,但不要开tcp_tw_recycle  

因为timestamp有更多其他的作用,而tcp_tw_recycle本身就是依赖于timestamp的。在不开启timestamp的情况下,单独开启tcp_tw_recycle并没有什么用
其实上述强调三遍的配置,正是目前Linux的默认配置。所以说啊,不真正搞懂内核的参数选项,就不要盲目修改。尤其是在官方文档对tcp_tw_recycle已经强调了不要盲目修改的情况下

那为什么有人推荐同时开启tcp_timestamp和tcp_tw_recycle呢?
因为同时开启后,能够更快的回收TIME-WAIT状态的socket    <== 这也正是PAWS从per-conn在配置后扩展到per-host的目的  
只可惜逻辑是对的,但是没有考虑到公网广泛存在的NAT机制可能带来的问题。  

源码细节分析

这部分是linux 3.10源码部分的分析,算是对于以上理论分析提供的依据,不关系细节的话可以忽略本节

// tcp_v4_conn_request(), net/ipv4/tcp_ipv4.c line 1551
if (tmp_opt.saw_tstamp &&      // 是否见到过tcp_timestamp选项
    tcp_death_row.sysctl_tw_recycle &&   // 接着判断是否开启recycle
    (dst = inet_csk_route_req(sk, &fl4, req)) != NULL &&    // 最终判断saddr是否有相关记录在route表中
    fl4.daddr == saffr) {
    if (!tcp_peer_is_proven(req, dst, true)) {  // 如果这个建连请求不能被proven,则会被丢弃
        NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
        goto drop_and_release;
    }
}

// tcp_peer_is_proven() net/ipv4/tcp_metrics.c line 536
// 负责判断接收到的request请求的timestamp是否符合要求,最重要的一段代码如下
if (tm &&
    // 判断保存tcpm_ts_stamp值是否有效,TCP_PAWS_MSL=60
    (u32)get_seconds() - tm->tcpm_ts_stamp < TCP_PAWS_MSL &&
    // 如果记录值大于当前收到的req中的timestamp值,则丢弃。TCP_PAWS_WINDOW=1
    (u32)(tm->tcpm_ts - req->ts_recent) > TCP_PAWS_WINDOW) {
        ret = false;
}

至此可以看到:在tcp_timestamp和tcp_tw_recycle同时开启时,会触发Linux的per-host的PAWS机制

接下来分析开启tcp_tw_recycle和tcp_timestamp时,是怎么快速回收TIME-WAIT的

// tcp_time_wait() net/ipv4/tcp_minisocks.c  line 267
...
// ts_recent_stamp依赖于timestamp选项的开启,可进tcp_minisocks.c验证  
if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp)
    recycle_ok = tcp_remember_stamp(s);
...
// 如果能够recycle,则使用更短的rto作为timeout,从而更快回收TIME-WAIT
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_twsh_schedule(tw, &tcp_death_row, timeo, TCP_TIMEWAIT_LEN);

// tcp_timewait_state_process() net/ipv4/tcp_minisocks.c line 94
// 另一条进入time-wait的路线有类似的代码
if (tcp_death_row.sysctl_tw_recycle &&
    tcptw->tw_ts_recent_stamp &&
    tcp_tw_remember_stamp(tw))
        inet_twsk_schedule(tw, &tcp_death_row, tw->tw_timeout,
                           TCP_TIMEWAIT_LEN);
else
        inet_twsk_schedule(tw, &tcp_death_row, TCP_TIMEWAIT_LEN,
                           TCP_TIMEWAIT_LEN);

参考资料

Documentation: ip-sysctl.txt
RFC 1323: TCP Extensions for High Performance

标签:NAT,tw,tcp,转帖,TCP,思考,timestamp,recycle
From: https://www.cnblogs.com/jinanxiaolaohu/p/18258486

相关文章

  • [转帖]HikariCP连接池参数解释
    https://www.cnblogs.com/wat1r/p/13710562.html ##数据库配置spring.datasource.type=com.zaxxer.hikari.HikariDataSourcespring.datasource.driverClassName=com.mysql.jdbc.Driverspring.datasource.url=jdbc:mysql://localhost:3306/ssm?useUnicode=true&chara......
  • [转帖]剖析free命令
    https://perthcharles.github.io/2015/09/28/wiki-tool-free/  Linux中有许多的查看系统状态的命令,但是如果没有一些相关的背景知识就很容易造成误解。free命令就是一个明显的例子。本系列wiki就结合一些好的资料并结合自身理解来尝试剖析一些常用又常被误解的Linux命令......
  • Nature Electronics|微器件在柔性基底上的高密度集成(可穿戴电子/界面调控/电子皮肤/柔
    2024年4月22日,韩国首尔大学YongtaekHong和美国斯坦福大学ByeongmoonLee团队,在《NatureElectronics》上发布了一篇题为“Asite-selectiveintegrationstrategyformicrodevicesonconformablesubstrates”的论文。论文内容如下:一、摘要        微器件可以被......
  • ChinaTravel成流量密码,景区如何打造视频监控管理平台提升旅游体验
    随着中国经济的飞速发展和人民生活水平的持续提高,旅游已经成为越来越多人休闲放松的首选方式。近期,随着互联网的普及和社交媒体的兴起,以及免签政策带火入境游,“ChinaTravel”已成为社交网络上的一大流量密码,吸引了越来越多的国外游客前往中国旅游。然而不能忽视的是,在这股旅游热潮......
  • [转帖]Redis中删除过期Key的三种策略
    Redis对于过期键有三种清除策略被动删除:当读/写一个已经过期的key时,会触发惰性删除策略,直接删除掉这个过期key主动删除:由于惰性删除策略无法保证冷数据被及时删掉,所以Redis会定期主动随机淘汰一批已过期的key当前已用内存超过maxmemory限定时,触发主动清理策......
  • [转帖]springboot中Hikari连接池常用参数含义(一)
    <divid="content_views"class="htmledit_views"><p>yml配置<br><imgalt=""height="235"src="https://img-blog.csdnimg.cn/7724916bc5d449b48114ed52462ba48d.png"......
  • [转帖]JDBC 驱动程序类型
    https://www.jianshu.com/p/fce9ac03a250 什么是JDBC驱动说白了JDBC驱动就是一组实现了JDBCAPI接口的Java类的集合,该接口用于与数据库服务器进行交互。例如,使用JDBC驱动程序可以让你打开数据库连接,并通过发送SQL或数据库命令,然后通过Java接收结果。JDK中的......
  • [转帖]深入理解JDBC的超时设置
     https://www.cnblogs.com/Chary/articles/14958848.html 这是最近读到的讲关于JDBC的超时问题最透彻的文章,原文是http://www.cubrid.org/blog/understanding-jdbc-internals-and-timeout-configuration ,网上现有的翻译感觉磕磕绊绊的,很多上下文信息丢失了,这里用我......
  • 代码规范性思考
    表命名和设计业务模块前缀;下划线分隔,体现业务含义;数据库字符集、字段名、类型、长度、默认值;一对一、一对多、多对多建表;注释清晰;良好的索引;接口文档swagger增强工具swagger-bootstrap-ui、Knife4j通用出入参包装类RestRequest<T>、RestResponse<T>入参校验@Validated注......
  • abstract 的 method 是否可同时是 static,是否可同时是 native,是否可同时是 synchroni
    在Java中,abstract方法不能同时是static、native或synchronized。让我们详细解释每种情况,并提供相应的代码示例和解释:abstract方法不能是static:abstract方法必须被子类实现,而static方法是与类相关的,而不是与实例相关的。因此,不能将一个方法同时声明为abstract和......