大历史下的 tcp:恼人的 timewait

tcp timewait 是个恼人的状态,它的恶心自两类恶心的询问,oncall 和面试。大概诸如 “如何减少 timewait socket 数量”,“tw_reuse 和 tw_recycle …”,如果只为应用,用 reset 关连接就够了。

timewait 状态的根本目的是 “防止旧连接的报文干扰复用相同四元组的新连接”。

由于所有 tcp 连接完全复用相同的平坦的 32bit 序列号空间,所有 tcp 连接的序列号就在这 32bit 空间绕来绕去,如何区别报文所属的连接以及连接内所属的位置就是个问题。

连接内部序列号回绕好说,限制 wscale 最大 14 即可约束 tcp window 不超过 1/4 个序列号空间(请参考 rfc1323 和 linux before,after 宏),足以区分了。而为了在连接间区别序列号,tcp 内置了 timewait 状态,在关闭连接时等待足够的时间后才能复用相同四元组创建新连接,这段时间足够久,以至于任何旧连接的报文在网络上死的透透的。

linux tcp timewait 等待时间为 60s,这时间太久,大多数短视频都播完了。

事实上 wscale-max 已经足够好,linux timewait 这 60s 也已经够短,但还不够,于是借助 rfc1323 timestamps 选项的 paws 被标准化。为此优化效果,linux 又有 tcp_tw_reuse 和 tcp_tw_recycle 配置选项,但这些选项又太复杂,必须听专家的:“It should not be changed without advice/request of technical experts.” 且默认又不开启,显然绝大部分好学成性的程序员就给这些 technical experts 找了不少麻烦。

说到底,为什么 tcp_tw_reuse 默认不开启呢?因为它相当于取消了 timewait 状态并可以立马复用相同四元组新建连接,该四元组旧连接迟到报文如果且恰恰命中 window(32bit 说大不大,命中不难),就会污染新连接,至于新建连接时对端 lastack 状态等 last ack 却等来个 syn 倒是次要,如果序列号空间是 128bit,就算 lastack 等来个 syn 又如何,正常建连就是了。

核心还是无法区别一个序列号属于哪个连接。tcp 用 timewait 状态解决这问题是一个非常拙劣的手法,说实在的就是 “搞不定就等一段时间”。这种手段如何 low 到被喷,我举个例子。在我们写内核模块时,卸载时总担心引用问题,如果卸载当时正好有一个线程要访问模块数据就会触发莫名其妙的问题,很多人会在 fini 函数最后加入 sleep(5) 这种调用来模拟一个类似 rcu 的逻辑,然后被经理猛喷,能喷好几年,逢人就跟说谁谁做的这个 sleep(5) 好 low,可经理却一句也不敢喷 tcp waitwait。

paws 作为解决 tcp 序列号区分的通用方案,tcp_tw_reuse 和 tcp_tw_recycle 为 paws 而来,然后 tcp_tw_recycle 又由于和 nat 胶着,为了解决非常稀有的序列号污染问题而引入了一开启就一定会出现的 syn 被默默丢弃的建连失败问题,最终取消了 tcp_tw_recycle,瞎折腾一圈。tcp_tw_recycle 的例子很像为了一盘粗,包了一顿猪肉馅饺子,结果有部分顾客是 msl,还要区分招待,自己给自己找事。

tcp timestamps 不符合高内聚性,它尝试解决很多问题,却每一个问题都解决不好。对于区分新旧连接序列号而言,timestamps 做得太过了,为这种区分根本没必要在连接内递增。

正确的做法是,为 tcp 引入一个 16bit(甚至 12bit,8bit) 的字段,相同四元组连接每新建一次递增 1 就好。松弛一下,四元组 hash 到同一个值的连接共享一个全局字段,每新建一个连接该全局字段递增 1。考虑到一个 host 的建连能力,该全局字段回绕一次的时间大概在 msl 就好了,而这是相对容易的,相当于把 timewait 时间平摊给了每一次连接。

这种方法非常常见,我们每天都在用,我们的分层计时,xx年xx月xx日xx时xx分xx秒,我们的十进制,60 进制计数,再或者我们的空间分层,xx市北大街,xx市东大街。我们可以将高一层的计数称作 “版本号”,以示区分,我们在软件更新,内核协议栈的路由表更新方面(可参考 linux kernel 实现)常用这种方式。相对而言的另一种拙劣方法就是 “等一会儿,等足够久”,让时间遗忘一切。

而 tcp timestamps 的做法是,秒针和分针,时针各自按各自的节奏进步,可想而知会多么混乱,复杂且低效。timestamps 也是要忘掉的,它不是问题的本质,它只是 workaround。本质是什么,本质就是为了区分一个序列号属于哪个连接。

如果一开始 tcp 的 seq 缩短为 16 bit,另外 16bit 作为 version,新旧连接间的序列号就区分出来了,如果觉得同一个连接内部 16bit 不够,那就 24bit,留给连接间 8bit… 总之,32bit 总空间,tcp 全部用于 seq 平坦编码,太粗了,彼时根本没有足以快速回绕的带宽,属过度设计了。

tcp 32bit 序列号空间可容纳 4g 数据,而在 msl 内传输完 4g 数据需要非常大的带宽,在 2010 年以前几乎很难满足这样的条件,即使考虑连接内回绕,最大 4g/4 的窗口约束也足足保证了当时的带宽利用率,tcp 在 1970 年代的考虑过度了,看起来当前的 ipv6 也有类似问题。

如果采用单独的全局 version,以 16bit 全局 ver 为例,连续相邻 65535 次连接才有可能冲突,显然已经超过 msl 了,如果不想占用 32bit 序列号空间就另开辟一个 16bit option 而不必复用 32bit timestampts。检查 paws 时只需要看收到报文携带的 ver 字段与当前连接 ver 是否一致即可。

没了 timewait 状态,很多复杂恼人的逻辑将彻底消失。finwait 收到 fin 并回复 ack 后方可直接关闭,对端 lastack 也不再需要坚持,类似 synack 那帮最多 retry n 次 fin 后亦可直接关闭而无后患。

设计新协议时,不要总觉得 tcp 足够久就是好的,不要什么都学 tcp。

姿势掌握了吗?

浙江温州皮鞋湿,下雨进水不会胖。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/831207.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

4G+北斗太阳能定位终端:一键报警+倾覆报警 双重保障船舶安全

海上作业环境复杂多变,海上航行充满了各种不确定性和风险,安全事故时有发生,因此海上安全与应急响应一直是渔业和海运行业关注的重点。为了提高海上安全保障水平,4G北斗太阳能定位终端应运而生,它集成了一键报警和倾覆…

Edge浏览器新特性深度解析,写作ai免费软件

首先,这篇文章是基于笔尖AI写作进行文章创作的,喜欢的宝子,也可以去体验下,解放双手,上班直接摸鱼~ 按照惯例,先介绍下这款笔尖AI写作,宝子也可以直接下滑跳过看正文~ 笔尖Ai写作:…

【数据结构】:链表的带环问题

🎁个人主页:我们的五年 🔍系列专栏:数据结构 🌷追光的人,终会万丈光芒 前言: 链表的带环问题在链表中是一类比较难的问题,它对我们的思维有一个比较高的要求,但是这一类…

AI大模型探索之路-训练篇10:大语言模型Transformer库-Tokenizer组件实践

系列篇章💥 AI大模型探索之路-训练篇1:大语言模型微调基础认知 AI大模型探索之路-训练篇2:大语言模型预训练基础认知 AI大模型探索之路-训练篇3:大语言模型全景解读 AI大模型探索之路-训练篇4:大语言模型训练数据集概…

DS:顺序表、单链表的相关OJ题训练

欢迎各位来到 Harper.Lee 的学习小世界! 博主主页传送门:Harper.Lee的博客主页 想要一起进步的uu可以来后台找我交流哦! 在DS:单链表的实现 和 DS:顺序表的实现这两篇文章中,我详细介绍了顺序表和单链表的…

使用LinkAI创建AI智能体,并快速接入到微信/企微/公众号/钉钉/飞书

​ LinkAI 作为企业级一站式AI Agent 智能体搭建与接入平台,不仅为用户和客户提供能够快速搭建具备行业知识和个性化设定的 AI 智能体的能力;还基于企业级场景提供丰富的应用接入能力,让智能体不再是“玩具”,而是真正能够落地应用…

PHP的数组练习实验

实 验 目 的 掌握索引和关联数组,以及下标和元素概念; 掌握数组创建、初始化,以及元素添加、删除、修改操作; 掌握foreach作用、语法、执行过程和使用; 能应用数组输出表格和数据。 任务1:使用一维索引数…

uniapp0基础编写安卓原生插件和调用第三方jar包和编写语音播报插件之使用jar包插件

前言 如果你不会编写安卓插件,你可以先看看我之前零基础的文章(uniapp0基础编写安卓原生插件和调用第三方jar包和编写语音播报插件之零基础编写安卓插件), 我们使用第三方包,jar包编写安卓插件 开始 把依赖包,放到某个模块的/libs目录(myTestPlug/libs) 还要到build…

R语言的学习—5—多元数据直观表示

1、数据读取 ## 数据整理 d3.1read.xlsx(adstats.xlsx,d3.1,rowNamesT);d3.1 #读取adstats.xlsx表格d3.1数据 barplot(apply(d3.1,1,mean)) #按行做均值条形图 barplot(apply(d3.1,1,mean),las3) barplot(apply(d3.1,2,mean)) #按列做均值图条形图 barplot(a…

C语言数据结构 ---- 单链表实现通讯录

今日备忘录: "折磨我们的往往是想象, 而不是现实." 目录 1. 前言2. 通讯录的功能3. 通讯录的实现思路5. 效果展示6. 完整代码7. 总结 正文开始 1. 前言 顺表实现通讯录: 点击~ 顺序表实现通讯录 在日常生活中,我们经常需要记录和管理大量的联系人信息&…

【研发管理】产品经理知识体系-组合管理

导读:新产品开发的组合管理是一个重要的过程,它涉及到对一系列新产品开发项目进行策略性选择、优先级排序、资源分配和监控。这个过程旨在确保企业能够最大化地利用有限的资源,以实现其战略目标。 目录 1、组合管理、五大目标 2、组合管理的…

第74天:漏洞发现-Web框架中间件插件BurpSuite浏览器被动主动探针

目录 思维导图 前置知识 案例一:浏览器插件-辅助&资产&漏洞库-Hack-Tools&Fofa_view&Pentestkit 案例二: BurpSuite 插件-被动&特定扫描-Fiora&Fastjson&Shiro&Log4j 思维导图 前置知识 目标: 1. 用…

基于springboot实现公司日常考勤系统项目【项目源码+论文说明】

基于springboot实现公司日常考勤系统演示 摘要 目前社会当中主要特征就是对于信息的传播比较快和信息内容的安全问题,原本进行办公的类型都耗费了很多的资源、传播的速度也是相对较慢、准确性不高等许多的不足。这个系统就是运用计算机软件来完成对于企业当中出勤率…

数据结构-链表OJ

1.删除链表中等于给定值 val 的所有结点。 . - 力扣(LeetCode) 思路一:遍历原链表,将值为val的节点释放掉 思路二:创建一个新链表,将值不为val的节点尾插到新链表中 /*** Definition for singly-linked …

2024年五一数学建模竞赛C题论文首发

基于随机森林的煤矿深部开采冲击地压危险预测 摘要 煤炭作为中国重要的能源和工业原料,其开采活动对国家经济的稳定与发展起着至关重要的作用。本文将使用题目给出的数据探索更为高效的数据分析方法和更先进的监测设备,以提高预警系统的准确性和可靠性…

智能消费记账|基于SSM+vue的大学生智能消费记账系统(源码+数据库+文档)

智能消费记账目录 基于SSMvue的大学生智能消费记账系统 一、前言 二、系统设计 三、系统功能设计 1 用户列表 2 预算信息管理 3 预算类型管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍&#xff1…

代码随想录算法训练营DAY48|C++动态规划Part9|121.买卖股票的最佳时机、122.买卖股票的最佳时机II、123.买卖股票的最佳时机III

文章目录 121.买卖股票的最佳时机思路CPP代码 122.买卖股票的最佳时机II思路CPP代码 123.买卖股票的最佳时机III思路CPP代码 121.买卖股票的最佳时机 力扣题目链接 文章讲解:121.买卖股票的最佳时机 视频讲解:动态规划之 LeetCode:121.买卖股…

Android 音视频基础知识

本系列文章会介绍两个 Android NDK Demo,拉流端会实现一个基于 FFmpeg 的视频播放器 Demo,推流端会实现一个视频直播 Demo,当然在做 Demo 之前会介绍音视频的基础知识。以下是本系列文章的目录: Android 音视频基础知识 Android 音…

抢先体验:MacOS成功安装PHP8.4教程

根据官方消息,PHP 8.4将于2024年11月21日发布。它将通过三个 alpha 版本、三个 beta 版本和六个候选版本进行测试。 这次的重大更新将为PHP带来许多优化和强大的功能。我们很高兴能够引导您完成最有趣的更新升级,这些更改将使我们能够编写更好的代码并构…

Mac brew安装Redis之后更新配置文件的方法

安装命令 brew install redis 查看安装位置命令 brew list redis #查看redis安装的位置 % brew list redis /usr/local/Cellar/redis/6.2.5/.bottle/etc/ (2 files) /usr/local/Cellar/redis/6.2.5/bin/redis-benchmark /usr/local/Cellar/redis/6.2.5/bin/redis-check-ao…