plantegg

java tcp mysql performance network docker Linux

关于本博

find me on twitter: @plantegg

Github: 欢迎star

知识星球:https://t.zsxq.com/0cSFEUh2J

关注基础知识,一次把问题搞清楚,从案例出发深挖相关知识。

以前觉得自己一看就懂,实际是一问就打鼓,一用就糊涂。所以现在开始记录并总结再联系案例,一般是先把零散知识记录下来(看到过),慢慢地相关知识积累更多,直到碰到实践案例或是有点领悟到于是发现这块知识可以整理成一篇系统些的文章(基本快懂了)。

“技术变化太快,容易过时”,我的看法是网络知识、操作系统、计算机原理等核心概念知识的寿命会比你的职业生涯还长。这些都是40岁之后还会还会很有用

如何在工作中学习 所有方法我都记录在这篇文章中了,希望对你能有所帮助。

所有新文章从这里可以看到,即使再简单的一篇总结我可以持续总结三五年,有新的发现、感悟都是直接在原文上增减,不会发表新的文章。

image-20220421102225491

为什么写博客而不是公众号,我见过20年前的互联网,深度依赖搜索引擎,所以还是喜欢博客。另外技术类文章更适合电脑阅读(随时摘录、实验)

精华文章推荐(2021年前)

在2010年前后MySQL、PG、Oracle数据库在使用NUMA的时候碰到了性能问题,流传最广的这篇 MySQL – The MySQL “swap insanity” problem and the effects of the NUMA architecture http://blog.jcole.us/2010/09/28/mysql-swap-insanity-and-the-numa-architecture/ 文章描述了性能问题的原因(文章中把原因找错了)以及解决方案:关闭NUMA。 实际这个原因是kernel实现的一个低级bug,这个Bug在2014年修复了https://github.com/torvalds/linux/commit/4f9b16a64753d0bb607454347036dc997fd03b82,但是修复这么多年后仍然以讹传讹,这篇文章希望正本清源、扭转错误的认识。

image-20210517082233798

CPU的制造和概念 从最底层的沙子开始用8篇文章来回答关于CPU的各种疑问以及大量的实验对比案例和测试数据来展示了CPU的各种原理,比如多核、超线程、NUMA、睿频、功耗、GPU、大小核再到分支预测、cache_line失效、加锁代价、IPC等各种指标(都有对应的代码和测试数据)。

image-20210802161410524

《Intel PAUSE指令变化是如何影响自旋锁以及MySQL的性能的》 从一个参数引起的rt抖动定位到OS锁等待再到CPU Pause指令,以及不同CPU型号对Pause使用cycles不同的影响,最终反馈到应用层面的rt全过程。在MySQL内核开发的时候考虑了Pause,但是没有考虑不同的CPU型号,所以换了CPU型号后性能差异比较大

image.png

10倍性能提升全过程 在双11的紧张流程下,将系统tps从500优化到5500,从网络到snat、再到Spring和StackTrace,一次全栈性能优化过程的详细记录和分析。

image.png

就是要你懂TCP–半连接队列和全连接队列:偶发性的连接reset异常、重启服务后短时间的连接异常,通过一篇文章阐明TCP连接的半连接队列和全连接队大小是怎么影响连接创建的,以及用什么工具来观察队列有没有溢出、连接为什么会RESET

image.png

就是要你懂TCP–性能和发送接收Buffer的关系:发送窗口大小(Buffer)、接收窗口大小(Buffer)对TCP传输速度的影响,以及怎么观察窗口对传输速度的影响。BDP、RT、带宽对传输速度又是怎么影响的

就是要你懂网络–一个网络包的旅程:教科书式地阐述书本中的路由、网关、子网、Mac地址、IP地址是如何一起协作让网络包最终传输到目标机器上。 同时可以跟讲这块的RFC1180比较一下,RFC1180 写的确实很好,清晰简洁,图文并茂,结构逻辑合理,但是对于90%的程序员没有什么卵用,看完几周后就忘得差不多,因为他不是从实践的角度来阐述问题,中间没有很多为什么,所以一般资质的程序员看完当时感觉很好,实际还是不会灵活运用

国产CPU和Intel、AMD性能PK 从Intel、AMD、海光、鲲鹏920、飞腾2500 等CPU在TPCC、sysbench下的性能对比来分析他们的性能差距,同时分析内存延迟对性能的影响

image-20220319115644219

从网络路由连通性的原理上来看负载均衡lvs的DR、NAT、FullNAT到底搞了些什么鬼,以及为什么要这么搞,和带来的优缺点:《就是要你懂负载均衡–lvs和转发模式》

LVS 20倍的负载不均衡,原来是内核的这个Bug,这个内核bug现在还在,可以稳定重现,有兴趣的话去重现一下,然后对照源代码以及抓包分析一下就清楚了。

就是要你懂TCP–握手和挥手,不是你想象中三次握手、四次挥手就理解了TCP,本文从握手的本质–握手都做了什么事情、连接的本质是什么等来阐述握手、挥手的原理

nslookup OK but ping fail–看看老司机是如何解决问题的,解决问题的方法肯定比知识点重要多了,同时透过一个问题怎么样通篇来理解一大块知识,让这块原理真正在你的只是提示中扎根下来

如何在工作中学习 一篇很土但是很务实可以复制的方法论文章。不要讲举一反三、触类旁通,谁都知道要举一反三、触类旁通,但是为什么我总是不能够举一反三、触类旁通?

举三反一–从理论知识到实际问题的推导 坚决不让思路跑偏,如何从一个理论知识点推断可能的问题

性能相关(2015-2018年)

就是要你懂TCP–半连接队列和全连接队列 偶发性的连接reset异常、重启服务后短时间的连接异常

就是要你懂TCP–性能和发送接收Buffer的关系:发送窗口大小(Buffer)、接收窗口大小(Buffer)对TCP传输速度的影响,以及怎么观察窗口对传输速度的影响。BDP、RT、带宽对传输速度又是怎么影响的 发送窗口大小(Buffer)、接收窗口大小(Buffer)对TCP传输速度的影响,以及怎么观察窗口对传输速度的影响

就是要你懂TCP–性能优化大全

就是要你懂TCP–TCP性能问题 Nagle算法和delay ack

10倍性能提升全过程 在双11的紧张流程下,将系统tps从500优化到5500,从网络到snat、再到Spring和StackTrace,看看一个性能全栈工程师如何在各种工具加持下发现各种问题的。

CPU系列文章(2021年完成)

CPU的制造和概念

十年后数据库还是不敢拥抱NUMA?

[Intel PAUSE指令变化是如何影响自旋锁以及MySQL的性能的](/2019/12/16/Intel PAUSE指令变化是如何影响自旋锁以及MySQL的性能的/)

[Perf IPC以及CPU性能](/2021/05/16/Perf IPC以及CPU利用率/)

CPU性能和CACHE

[CPU 性能和Cache Line](/2021/05/16/CPU Cache Line 和性能/)

AMD Zen CPU 架构 以及 AMD、海光、Intel、鲲鹏的性能对比

Intel、海光、鲲鹏920、飞腾2500 CPU性能对比

网络相关基础知识(2017年完成)

就是要你懂网络–一个网络包的旅程

通过案例来理解MSS、MTU等相关TCP概念

就是要你懂TCP–握手和挥手

wireshark-dup-ack-issue and keepalive

一个没有遵守tcp规则导致的问题

[kubernetes service 和 kube-proxy详解](/2020/09/22/kubernetes service 和 kube-proxy详解/)

DNS相关

就是要你懂DNS–一文搞懂域名解析相关问题

nslookup OK but ping fail

Docker中的DNS解析过程

windows7的wifi总是报DNS域名异常无法上网

LVS 负载均衡

就是要你懂负载均衡–lvs和转发模式

就是要你懂负载均衡–负载均衡调度算法和为什么不均衡

网络工具

就是要你懂Unix Socket 进行抓包解析

就是要你懂网络监控–ss用法大全

就是要你懂抓包–WireShark之命令行版tshark

netstat timer keepalive explain

Git HTTP Proxy and SSH Proxy

对姚顺宇的4小时访谈整理

节目来源:张小珺|商业访谈录 第 140 期
YouTube:https://www.youtube.com/watch?v=ttkd0t5qTD4
录制时间:2026 年 3 月
发布时间:2026 年 5 月 11 日

整理说明:本文基于 YouTube 自动字幕整理,原字幕经历了”中文语音 → 英文 AI 翻译 → 中文再翻译”的双重转译,口语化表达、术语、人名错漏较多。本文结合嘉宾公开背景资料(清华物理系本科、斯坦福理论物理博士、Anthropic 与 Google DeepMind 研究员)对关键错误做了校正,并在必要处补充背景注释。尽量忠于嘉宾原话和语气,包括其中的”小疯”言论、吐槽和批评。


关于嘉宾身份的重要澄清

硅谷 AI 圈有两位清华同届毕业、英文都叫 Shunyu Yao 的研究者,中文媒体常混淆:

姚顺雨(另一位) 姚顺宇(本期嘉宾)
本科 清华姚班(计算机) 清华物理系(基科班/学堂物理班)
博士 Princeton(NLP) Stanford(理论物理)
代表作 ReAct、Tree of Thoughts、《AI 下半场》 Non-Hermitian Skin Effect(非厄米趋肤效应)、Scramblon 理论
路径 OpenAI → 腾讯首席 AI 科学家(2025) Anthropic → Google DeepMind(2025)

本期嘉宾姚顺宇的公开履历校核:

  • 2015–2019 清华物理系本科,特等奖学金 + 叶企孙物理奖
  • 本科期间 3 篇顶刊(2 篇 PRL + 1 篇 PRB),第一作者与清华王中合作提出 非厄米系统拓扑能带理论新方法
  • 2019–2024 斯坦福大学理论与数学物理博士,导师 Douglas StanfordStephen Shenker,研究量子场论与量子引力动力学
  • 短暂加入伯克利做博士后(正式两周,节目中他说实际待了两三个月)
  • 2024 年 10 月 加入 Anthropic,从事强化学习方向,参与 Claude 3.7、4、4.5 的训练
  • 2025 年 9 月 19 日 从 Anthropic 离职,9 月 29 日 加入 Google DeepMind,Senior Staff Research Scientist
  • 参与 Gemini 3、Gemini 3 Deep Think、Gemini 3.1 Pro 的开发

字幕中所有”顺宇”与”舜宇”、”Anthropic”被译为”人类学/人本主义/人形生物/人为因素/人猿科技/安特罗皮克”等均为同一指代;”双子座/双子星”即 Gemini。


一、两个 Shunyu Yao(01:26)

姚顺宇主动介绍另一位姚顺雨:”我们的主要职业发展道路有一些重叠,所以看起来可能很难把我们区分开来。”他强调两人最大区别是:另一位从一开始就做计算机科学,而自己是物理出身,只是”某种意义上走到了这一步”

两人清华本科同届(姚顺雨在姚班,他在基科班),研究生一个去了 Princeton,一个去了 Stanford——“很奇怪,全世界都觉得 Stanford 是 CS 圣地,Princeton 才是物理圣地,我们俩恰好反着来。”

  • 两人在硅谷时每几周见一次,主要就是”瞎玩”——散步、吃饭、打扑克。
  • 对于另一位姚顺雨提出的 “AI 进入下半场”,姚顺宇坦言:”我一直不太懂上半场、下半场什么意思,这个定义我始终没搞清。”
  • 他自己的阶段定义是:“大家开始不再那么担心一件事,AI 能不能做到这个问题本身是不是定义明确,这是最大的变化。” 一年前 Anthropic 内部还担心追不上 OpenAI 的推理能力;现在 Gemini、OpenAI、Anthropic 三家没谁真担心”赶不上进度”了——难的是想清楚到底该做什么
  • 模型同质化、商品化了,纸面(benchmark)上差距缩到 1–2 个百分点,“大部分是噪声,不是信号”,真正的差异只在实际用户体验里:Claude 工具使用最强,Codex 最近追平,Gemini 日常推理更好、智能体编码还在追赶。

二、竞争与逃逸(07:15)

关于 OpenClaw(字幕原文,疑为某款 2026 年初爆火的智能体 Wrapper 产品)的产品判断

  • “圈内人其实不紧张。圈外比圈内紧张。”他认为 OpenClaw 没有证明什么新东西——Claude 4.5 Opus 发布时,工具使用能力已经领先 OpenAI 和 Gemini 3,只是当时没人包装成产品。
  • Manus 被 Meta 收购(注:节目录制后该收购已被撤销)、OpenClaw 被 OpenAI 收购,这说明”包装层”目前还无法摆脱模型公司的控制——“逃逸速度不够”
  • Wrapper 要活下来只有两条路:
    1. “成长够快”(Cursor 的打法)——在模型公司反应过来前占据足够用户心智,并训练自己的模型。他说 Cursor 现在跟 Anthropic 的关系”已经到了非常微妙的阶段”,Cursor 在训自己的 Composer,双方从亲密伙伴变成竞争对手。
    2. “市场小到模型公司看不上”(Midjourney 的打法)——“有损 Gemini 尊严的”那种细分市场。
  • 被问到 Lovart 是否算:”我觉得他们有机会。”
  • 对 2026 年的预测:模型应当实现 “训练时有限上下文,使用时无限上下文”(train with finite context, use with infinite context)——模型边和你持续交互边判断、丢弃不重要信息,成为真正的私人助理。今年肯定能做到,但有多条技术路径,还要实验验证。
  • 关于 Meta 收购 Manus:他”没完全想明白”,猜测最大好处是拿到一个强大的亚洲产品团队,”中国在产品端比美国更有天赋”;但 Meta 为什么自己做不出这种产品?他也没想清楚。

三、”Pre-train 没有到头”(25:22)

这是他最反主流的判断之一。

  • “2026 年第一季度,模型改进速度完全没有放缓。”
  • 他拒绝用 benchmark 增长来衡量:”benchmark 是定义在 [0, 100] 里的,越接近 100 增长当然越慢,但这不代表用户感受到的增长在慢。从 70% 到 75% 的价值可能比从 50% 到 60% 还大。”
  • 他的判断基于研究者的体感:模型越来越容易学——过去要花很大力气教会模型一件事,现在只要问题定义清楚 + 数据/环境构建对,模型几乎”自动就会”。
  • 预训练(pre-training)过去几个月一直在变强。”几个月前很多人说 Scaling Law 撞墙了,我的经验是没撞墙,接下来四个月也看不到到头的迹象。”
  • 为什么有人觉得撞墙了?他给出三种可能,并直指第三条最常见:
    1. 觉得这个范式本身到头了(可能但只是猜测)
    2. 觉得数据等条件不再满足
    3. “他们自己的工作里有 bug,但没意识到——我观察到绝大多数’撞墙’的人属于这一类。” 修一个 bug 带来的进步,往往比花哨的技巧多得多。
  • 遇到撞墙应该是心态问题:相信问题可解,就会系统性地做消融实验排查——“Gemini 和 Anthropic 在这件事上都做得很好。”
  • 当前主驱动:数据和算力(二者强相关)。算法更像阶段性跃迁(如 Transformer),之后是渐进提效。
  • “在相对清晰的范式(pre-train / post-train)内,主驱动是数据和算力。多模态生成算法还没收敛,仍是科学问题;但自然语言生成已经不是科学问题,只剩工程问题。”
  • “如果我估一个时间线,接下来四个月还会有进步。但 AI 领域谁也没法预测四个月以后。”
  • 谁在兴奋?”做产品的人兴奋于 OpenClaw,做模型的人兴奋于模型进展。Anthropic 和 Gemini 里的人更多在想:AI 很快会把我们取代,我们接下来该干嘛——而不是担心撞墙。”

四、Coding 的爆发(35:08)

为什么编程领域这一年半发展最快?他认为有两大结构性优势:

  1. 奖励信号(reward signal)定义清晰:SWE 任务天然可测,输入输出一匹配就是成功。
  2. 数据基座天然存在:GitHub 几十年沉淀了海量高质量代码,构建环境非常方便。

从产品角度,编码还有一个独特性:好程序员写的代码风格高度相似(简洁、结构清晰、易扩展、抽象合理),所以不需要像社交/游戏那种推荐算法去适应每个用户的口味——这大大简化了产品形态。

  • 他自己的代码产出中 90% 以上由模型生成(保守估计,实际可能 99%);但他花大量时间审 review 代码。”AI 辅助之后,最重要的变成了如何设计它、如何给它合适的 context。”
  • 被问谷歌允不允许用 Claude Code:”你这个问题差点让我丢工作了——谷歌不允许用 Claude Code。”(笑)
  • 工作效率提升 20–50 倍(相比一年半前),但他的工作时间反而更长:”因为能试的想法更多了,以前要等同事几小时才能搞懂一个文件,现在问 Claude 或 Gemini 5 秒就行。”
  • 对谷歌文化的吐槽:“谷歌已经不是那个沿岸划船(coast along)的谷歌了。GenAI 里没人摸鱼,除非你对技术彻底失去兴趣。” 他自己每天 9 点起查邮件和夜间实验,10 点到办公室,单身时干到 10–11 点,妻子在也会带回家干。
  • 下一个 Coding 级别的爆发点?“如果我看得清,我早就去创业了。”(笑)除了编程,其他方向市场都不够大——AIGC 市场受限于”人一天只有 24 小时”;最可能的大市场候选是交互式教育,但也远小于编程。
  • 关于程序员的未来:AI 最终会取代程序员,但是渐进过程;“AI 是高度集中化的技术,让少数人更强,让大多数人失去独特价值”;传统软件工程的终局可能是**”千分之一的人做完所有人的活,拿 100 倍的工资”**。”千分之一只是个比喻数字,也可能是万分之一或十万分之一……别太悲观,我是著名的悲观主义者。”
  • 活下来的那群程序员特征:技术强(充分不必要条件)+ 理解自己在大组织中的定位 + 规划能力强(能把复杂事切成小块分发给不同 AI)。
  • AI 研究本身是淘金热还是科学革命?“都有”。他说训练 AI 产品经理目前不太可能——因为”什么是好产品”没有客观标准,反馈信号太模糊

五、Seedance(50:10)

对字节跳动 Seedance(字节系视频生成模型)的评价:

  • “可能会让 DeepMind 多模态团队有压力,但不是范式级的变化。字节在多模态生成上一直相对强,主要是数据和细节做得好。”
  • 猜测原因是数据,因为多模态算法层面还没根本创新;但他”没在字节工作过,只能瞎猜”。
  • 评价从谷歌跳去字节的吴永辉:”偷偷看过他过去的代码提交和领导项目,他是我见过极少数资深但技术能力还特别强的人之一,我还不到评价他的水平。”
  • 中美模型差距:过去一年半明显在缩小,但是否会完全消失甚至反超,”是个悬而未决的问题”。
  • “中国在实际算力上处于明显劣势,但这个劣势反而催生了一些有趣的东西——中国模型公司非常擅长从其他模型蒸馏。”

六、”硬蒸”和”软蒸”(54:30)

回应 Dario Amodei 最近公开指控三家中国公司蒸馏他们模型:

  • “蒸馏本身是公开的秘密。”
  • 他把蒸馏分为两种:
    • “硬蒸”(brute-force distillation):直接拿 Claude 生成的 token 去强制训练自己的模型。“商业上不道德,智商上相当蠢——等于承认你连自己要做什么都不知道,只能模仿别人,把 benchmark 数字做得好看些。”
    • “软蒸”(smart distillation):在自己的数据 pipeline 里用其他模型做助手,或者用其他模型当 evaluator。“商业上灰色,但技术上其实很有意思——中国实验室可能是 multi-agent 训练领域的先驱:如果他们把多个不同公司、语言分布差异巨大的模型整合进统一训练系统,这才是真正的 multi-agent。”
  • 点名(后期应消音处理):硬蒸某家”之前可能做过,后来逐渐转软蒸”;“蒸得最少的是字节跳动,它的模型仍然非常独特。”
  • 关于豆包:
    • “豆包肯定不如 Gemini 或 Claude 聪明。但豆包的语音生成真的是世界最好的(直白说就是最好,委婉点说是之一)。”
    • 美国公司为什么不做这种方向?“数据问题 + 用户群差异。美国人更关注生产力,中国人才有那么多’人生问题’要问’豆包’。我自己生活很无聊,没什么有趣的人生问题——日常技术问题问 Gemini 就好。”(笑)
    • 豆包手机:”想法很好,但我不知道技术实现上开销多大——不能你让模型帮你订张高铁票,最后花的钱比票本身还贵,那是不能接受的。
    • 苹果 AI 策略:”表面看上去不在乎,其实太在乎了,只是如果太在乎又做不成,就显得自己太蠢。面子问题。

七、机器人(1:04:07)

  • 春晚看过演出,还去亚马逊搜过人形机器人价格,”比我想的便宜多了”,反映了中国硬件产业链的优势
  • 但软件侧:”机器人模型还处在特征工程时代——给定场景,针对这个场景做 RL 优化,每个人都知道怎么做,但泛化能力不强。”
  • “是否具备泛化能力,实际上是 AI 很多方向的分水岭。” 确定性单一场景做好不难,十几年前就能做到;语言模型是在 Transformer / GPT 之后才越过这个阈值——“在一个层面训练就能全面提升所有能力”。机器人还远没到。
  • 参观过 Google DeepMind 自己的机器人实验室和 Physical Intelligence:”实验室比语言模型实验室有趣多了——语言模型实验室就像普通办公室,机器人实验室真的是人工遥控机器人去各种货架取东西。”
  • 机器人目前连 GPT-1 阶段都没到,和多模态生成一样,都还没找到 scale 的办法

八、在 Underdog 之地赌一把(1:08:45)——成长经历

出生在宁夏大武口(一座因煤矿而生的城市),小学到高中在上海。性格自述:”我总是喜欢做我不擅长的事情。

关键人生选择——高中择校:他本可以被上海四大名校(上中、华二、交大附中、复旦附中)的普通班录取,但为了进**”稍差一些”的格致中学的竞赛班而放弃——“赤脚的不怕穿鞋的,值得一试。”**

参加物理竞赛未能进国家集训队(没拿到保送),后来高考也考不上清华。但命运转折:高三清华夏令营期间,听说清华对北京学生有独立招生,他当场给清华招生办老师发短信——“你给北京学生考试,凭什么不让上海学生也考?”——争取到考试机会,考过后签了”第一档降分”协议,最终录取清华。

人生最大的经验:“大胆一些。如果你不争取,就永远得不到。即使你争取,也未必能得到。但如果你不争取,就肯定得不到。”

对父母的评价:”中国家长能做到让孩子’讨论’已经不错了,我一般只是通知他们。我父母最好的地方是,当他们无法理解我在做什么时,他们选择不干涉。”

性格:”在意自己想做的事,别试图阻止我,我会竭尽全力;但我不想做的事,你逼也没用。”、”我更多是和自己竞争,不太愿意和别人竞争——当然如果你也很在乎,那我一定要比你厉害。”


九、非厄米系统与量子物理(1:19:44)

选择凝聚态理论”就是命运的安排”。清华基科班传统是”学生可以做物理以外的事,鼓励早进实验室做研究”——“基科班三分之二的学生最后都不做物理。”

本科导师是王中(Zhong Wang)(字幕写作”王忠”),当时还很年轻、学生不多。王中的博士导师是 张首晟(Shoucheng Zhang)(字幕写作”张守成/寿城”,斯坦福著名凝聚态物理学家,2018 年去世)。”王老师话不多,但很擅长把问题看清楚。”

非厄米系统工作的通俗讲解(他自己给出的进度条提示:不想听可以跳过):

  • 量子力学的基本假设:孤立系统演化由 Hamiltonian(厄米算符)描述。
  • 现实中绝大多数不是孤立系统(和环境交换粒子/能量),对应的 Hamiltonian 是非厄米的
  • 他们最初研究开放量子系统的拓扑现象时,发现解析计算(周期性边界条件)与数值计算(开放边界条件)的结果完全对不上
  • 后来发现:厄米系统的基本范式——布洛赫波假设——在非厄米系统里完全崩溃。非厄米系统的能量本征态全部会堆积在系统边界(即后来广为人知的 Non-Hermitian Skin Effect,非厄米趋肤效应)。
  • 他们建立了一整套描述开放边界非厄米系统本征态和动力学的框架——这是**范式级(paradigm shift)**的工作。

为什么没继续做下去?

  • “范式转变很难 catch,已经 catch 了一次就不想再 catch 同一次。”
  • “这是人性的弱点——我总想挑战自己不知道的事。”
  • 现在回头看,”如果当时继续做下去,那工作会成为这个方向上最重要的工作,我会更有名、更多引用、更好的教职;但科研生涯会变得不那么兴奋。”
  • 所以博士阶段转去搞理论高能物理(量子场论与量子引力),这两个方向”几乎没有任何联系”。

对”挑战难事”的反思:“说得好听点是挑战自己,说得难听点就是自虐。”、”如果一个人只为受虐而受虐,那是心理问题;但如果是为了获得信息、丰富经验和能力,那值得。”

本科学物理最大的收获:“把事情想清楚、做深度阅读、不要过分相信纯理论。”——因为非厄米那个发现本身就源于”数值计算和理论不符,深入追查才找到问题”。


十、高能物理(1:36:27)

承认博士阶段”对世界没有贡献“:

  • “高能物理已经发展到实验完全跟不上理论的程度。” 没有客观评判标准,靠”领域里几位老前辈的主观判断”。
  • “人的一生并不长,何必浪费时间为老年人服务。”
  • 五年博士学到的最重要一课:“做事情要有相对客观的评价标准”,或者说 “做对世界有影响的事”
  • 自我评价:”说实话,我的博士论文没人会说不好,但对世界的影响几乎没有。我个人非常不满意,但也没糟糕到让别人说我偷懒的程度——你可以满足所有外部期望,但自己骗不了自己。”
  • 满足小圈子标准 = 训练一个模型:“一旦进了那个小圈子,你知道评价标准是什么,做好很容易,即使你不认同这些标准。”
  • 博士后两三个月实际在伯克利(正式记录只有两周)后离职,伯克利老师很好:”我告诉他们我可能要去做 AI,他们说不急,先把现有工作保住再说。”

十一、物理与 AI(1:43:09)

物理学家做 AI 的优势

  • 硬技能上帮助其实很少。
  • 真正的帮助在性格/品味:探究本质、做事系统化(无论实验还是理论方法论)。
  • “这不是物理独有——CS、化学、生物背景的人也有这种特质。”
  • Anthropic 特别多物理出身的人,”主要是联系(connection)——联合创始人里两个技术一把手都是物理背景,于是就招了这类人。但到我加入时,这个惯性已经结束了。”

关于 AI 是不是黑箱

  • “一切都是黑箱,连物理也是。” 我们也不知道最微观层面的动力学。
  • 语言模型还没到”神经外科级别”的理解(除了 Anthropic 的 Interpretability 团队在极小网络上能做)。
  • 但 Scaling Law 已经是经验定律——“经验定律和科学定律的界限是模糊的。热力学定律最初也是经验定律,后来有了微观机制的理解才变成科学定律。未来 Scaling Law 可能也会这么演化。”
  • “智能涌现”这个词本身不科学——“对我来说,这更多是主观感受。真正的质变只有一个:技术上能 scale 起来,全面提升所有能力。这是我对’涌现’的唯一定义。”

为什么最终选 AI 而不是量子计算?

  • 两者都给年轻人机会,但量子计算瓶颈在实验平台——“那是我不擅长的,和我兴趣无关的东西很多”。
  • AI 更像 “17 世纪做热力学”——那时候人们甚至还不知道”热”是什么(还相信燃素说),但这并不妨碍做实验、总结出第一定律、第二定律、Clapeyron 方程等经验定律,最终推动热机发明改变世界。
  • “理论物理到实验物理的距离,比理论物理到 AI 还要远。AI 对我来说就是数值实验——有想法,设计实验验证,本质和做物理数值计算没区别。”
  • 对实验物理的敬畏:”大家都知道怎么搭光学平台,有人能搭出来,有人六年搭不出来——这种动手能力我不理解,感觉相当神秘。”

十二、在 Anthropic 训练 Claude 3.7 和 4.5(1:52:32)

入职经过

  • 2024 年 8–9 月,通过前同事联系上 Anthropic(第一个 manager 也是理论物理背景)。
  • 同期也联系了 OpenAI 和 DeepMind——“DeepMind 当时太慢了,最后是 Anthropic 谈成。” OpenAI 没找到合适位置。
  • 面试前把能自学的课程都过了一遍,手写实现了 Andrej Karpathy 的 nanoGPT。
  • 有两个团队接洽他(评估 vs 强化学习),他选了更不确定的 RL 方向

当时 Anthropic 的状态

  • 全公司 700–800 人,他加入的 “Horizon” 大团队只有 10–11 人,几乎就是整个后来的 RL 团队前身。
  • 对 Anthropic 的第一印象:”执行力非常强,相对自上而下的公司;人与人之间没有隐瞒,氛围非常好——因为规模小大家都认识。”
  • Anthropic 为什么能自上而下? 因为技术决策人就是公司联合创始人(Jared Kaplan 和 Sam McCandlish),而且 Dario 与他们互信足够。”其他公司做不到——Ilya 在的时候 OpenAI 或许能,但他后来莫名其妙丧失了决策权,然后就走了。”
  • 他与 Jared Kaplan 合作最多。
  • Anthropic 联合创始人团队 “没有一个离开过”,”他们是真正并肩战斗过的一群人——Scaling Law 论文、GPT-3 论文都是联名作者(Jared、Sam、Dario、Tom Brown、Benjamin Mann 等)。”——这是很多公司做不到的互信基础。

Claude 3.5 → 3.6 → 3.7

  • “Claude 3.5new 被外界叫 3.6,是因为 Anthropic 早期没产品能力——两个模型都叫一个名字(3.5),后来自己被迫接受外部给的 3.6 叫法。所以实际产品线是 3.5 → 3.5new(=3.6)→ 3.7。”
  • Claude 3 发布后 Twitter 上就有人发现它编码比 GPT-4 强;“这是 Anthropic 押注编程的一个信号来源,但最初可能是随机试出来的——纯粹技术原因,先自下而上冒出来,后来自上而下 all-in。”
  • 3.7 是 Anthropic 后训练(post-training)的分水岭:之前 post-training 是”打补丁”模式;3.7 之后才真正大规模 RL。
  • “在我加入时,大家已经知道要做大规模 RL,但不知道具体怎么做。” 2024 年 8–9 月,o1 还没发布,只知道 OpenAI 有个神秘项目叫 Strawberry。
  • 真正的秘诀(他能公开谈的部分):“把简单的事做得比所有人都干净。” RL 最简单的算法是 policy gradient,有很多复杂的算法但会带来 infra 难题;如何 trade-off 这些 detail 才是真正的 expertise
  • 他的一个重要观察:“很多 trick 其实没用。” 不同公司 sampler 和 trainer 的 numerical 差异依赖各自 infra,所以”你照抄别人的算法不一定有用——算法是整个系统的一部分”。”这就是我为什么不爱回答别人问 Anthropic / Gemini 怎么做——回答会误导他们。”

3.7 → 4.5

  • 他离开时 Anthropic 已经接近 2000 人(比他加入时翻倍以上)。
  • “我赶上了小公司的尾声”——三四个月后公司突然变大,文化开始混乱,”有些从外面进来的人带来和原文化的冲突”。
  • 他不喜欢的人“我觉得 ‘ideas are cheap’。真正难的是 implementation。我不喜欢那种每天大部分时间泡在 Slack 里谈 grand principles 的人——没什么用。”(笑)

离职原因

  • 主因:想学不一样的东西。”Anthropic 非常聚焦,只做语言模型相关,不做多模态生成、不太做底层工程和 infra——我想学这些。”
  • 约 40% 原因:不认同 Dario 的反华立场。”作为 CEO 个人他怎么想都可以,但把这种观点推到如此极端,是非常情绪化的反应。”
  • 40% 不是主因,但也不是无关紧要,更不是**”控股股东的原因”**。(笑)
  • 对 Anthropic 未来的看法(离开时):悲观——“API 卖 token 是门烂生意,价格战会来,只有谷歌能赢(供应链优势)。”但后来证明他太悲观了,Anthropic 在产品层面做得非常好(Claude Code、Cowork 等)。
  • 被问会不会后悔:”不太会。我的动机是换位置学东西。”
  • Claude Code 的诞生:“那几乎是当代少有的、还展现个人英雄主义的时刻。” 创始人 Boris Cherny(字幕译为”鲍里斯·切尔尼”)本来只是想给自己和同事提效,最后变成了整个产品。”很可能是和抖音同级别的交互层面变革产品。”

关于”英雄主义已经过去了”

这是贯穿访谈的核心观点之一:

“个人英雄主义在语言模型领域可能已经过去了——也就是 Transformer 那个时刻之后。”

“现在大家都是冲浪的人,本质上是那个浪,而不是你那个冲浪的人。”

“没有英雄,有时候甚至觉得旧时代的英雄有点蠢。”

“我对任何模型的贡献,我的 statement 永远是:我自己对那件事没那么重要;更多是我很幸运,有机会在那时候加入了一个重要项目,做了一些事。”

他特别指出:编程上 Anthropic 的成功确实还有”公司级英雄主义”(敢不敢赌、赌得够不够快),但模型内部的每个技术细节都是集体的。

对 AI Safety 的批评(非常犀利):

  • Anthropic 成立的初衷是 AI safety,但又要训练前沿模型——Anthropic 自己的解释是”必须做最强的模型才有话语权推动 safety 议程”。
  • **”这个想法非常天真——**现在看来这不可能发生。更可能的结果是所有人都有强大前沿模型,没人能阻止任何事。”
  • 真正的机制类比是 核武器多方持有、互相威慑——“靠一家公司自我立法去规制是不可控的——它只能自我规制,但自我规制等于没规制。”
  • 对 Anthropic 可解释性团队:只在非常稀疏、小的网络上有有趣进展,实用语言模型层面还没达到”神经外科级别”。

十三、”AI 本质是简单的”(2:35:03)

核心命题“AI 本质是简单的。”(他强调这是 statement 不是 conclusion)

解释:

  • 因为你可以做实验。相比物理(能量尺度限制了实验数据),AI 不受这种约束——想做什么实验都能做,只是需要时间扩算力、准备 infra,但没有根本性困难。
  • “AI 不会给人撞墙的感觉,不是因为方法穷尽了,而是因为想法太多了,挨个试不过来。”
  • 未来 6–12 个月 AI 会开始自己做实验——不是只写代码,而是运行实验 → 分析结果 → 提出新假设 → 设计新代码 → 跑新实验,这条链会逐渐闭合。

十四、在 Google DeepMind 训练 Gemini 3(2:41:10)

加入 DeepMind 的理由

  • 反对那种”研究员离开大厂加入小厂”的惯性——他反其道而行,因为他当时想要”学更多、更广”
  • “如果你真想把某个想法塞进最终产品模型里,谷歌可能是非常烂的地方;但如果你要的是研究自由、广阔视野,世界上找不到比 Gemini 更强的第二名。”
  • 加入时点(2025 年 9 月底)已经看好 Gemini——Gemini 2.5 那代让业内意识到”Google 正在搞明白”。
  • 他是因为个人联系被挖进去的,双向选择。
  • 为什么没去 OpenAI?“文化让我非常担心。直白说,真正能把事做成的人没 Gemini 那么多,甚至比 Anthropic 还少。”(笑)内部政治斗争也开始显现。
  • xAI:“我不理解。”(笑)”接触过的人后来都走了,我也不知道他们现在怎么样。”

Gemini 3 的转折点

  • Gemini 3 和 Nano Banana 两次叠加才是真正的转折点:Nano Banana 把很多新用户引到 Gemini App,Gemini 3 把他们留住。”只有 Gemini 3 不够——市场份额低于 10% 时,模型再好传播也慢。”
  • Gemini 当前市场份额可能在 20% 左右(他还没精确核查)。
  • “从局外人角度看,是 OpenAI 救了谷歌的命。” 如果 ChatGPT 当时真的完全吞掉了搜索,谷歌就完蛋了;但 OpenAI 做到了”让谷歌意识到重要性,但没做到吞掉搜索”,让谷歌得以反扑。
  • Chatbot 为什么没完全吞掉搜索?
    1. 搜索有大量”非常蠢”的需求——“我就搜一下在哪买米、哪里点好,不想等聊天机器人转半天最后给个链接还要再点一次。”
    2. Chatbot 形态还没达到终点。
  • “聊天机器人凭什么就是终极形态?过了这么多年,居然还只有一个聊天框,我真的觉得很蠢。”——“需要一个产品经理来解锁模型的全部能力。”(笑)

谷歌内部发生了什么

  • 外部看到模型性能大跳;内部是组织逻辑开始清晰
    • 预训练阶段已经有清晰框架——谁负责哪个 node 非常明确(以前非常混乱)。
    • 谷歌工程管理能力极强,预训练已经进入”谷歌的舒适区”,能可控地知道下一代不会坏,甚至能预估好到什么程度
  • Anthropic 走自上而下;谷歌仍然相对自下而上,但比过去更偏自上而下。
  • “不同文化都能 work”——大公司和创业公司的打法本质不同。
  • 谷歌的杀手锏:“找到一个极简的产品表达形式,所有人看起来都一样,然后在技术层面无情地碾压你,你根本竞争不过。” 搜索就是典型例子。
  • OpenAI 的位置:“现在没人的位置是稳固的。” Chatbot 是否是 super app 的终极形态?—“我完全没有理性答案,但感觉事情还没结束。”
  • 对国内”超级应用”叙事的吐槽:“我真的不懂——大家在抢一个 super app,前提是 chatbot 就是 super app 的形态。但我真的觉得 chatbot 很蠢,终极形态凭什么非是这个?”

谷歌的”英雄”

  • 后台的英雄:Sergey Brin(”重大决定最终还得他拍板”)。
  • 前线的英雄:Koray Kavukcuoglu(Google DeepMind CTO / 谷歌高级副总裁)。
  • Demis Hassabis 更偏科学方向(Isomorphic Labs 等),Gemini 日常他见到最多的是 Koray。

十五、技术预测和组织搭建(3:01:28)

预训练 vs 后训练

  • 纯技术上两者本质区别不大——最大区别在数据分布:预训练要 广(不需要 quality 特别高);后训练要 窄而精(quality 要求极高)。
  • 不同实验室组织方式:
    • Anthropic / Gemini:pre-train 和 post-train 分两支队伍。
    • OpenAI:更混乱——最早三队(pre-train、RL “Strawberry”、post-train),而且他们的 post-train 本身就是产品团队,”训模型的人也参与产品”。

对”下一个范式转变”的判断

  • 大概率不是范式级变化,但对谷歌特别有价值的两件事:
    1. 机器学习编码(ML coding):让 AI 能加速 AI 自身的研究闭环——谷歌是 AI 研究最完整平台(硬件 + 连接 + 模型),这件事对谷歌价值巨大。
    2. 长远规划 / 长时程(long horizon):每个人都觉得重要。
  • 对实现方向:
    • 预训练侧:sparse attention(稀疏注意力,DeepSeek 和学术界都在做)。
    • 后训练侧:类似 Cursor 那种外部上下文管理(让模型选择保留或扔掉哪部分)。
    • 两者本质相同——上下文 token 的 KV cache 也是一种权重。
  • “**一万个人有一万种’世界模型’**的定义。Gemini 的世界模型更像端到端训练(条件生成下一刻场景);李飞飞那种是另一回事——我不太懂她们实验室在做什么。”
  • Continual learning(持续学习)和 long horizon 本质没区别。
  • 主要精力在后训练方法(预训练不做正式工作)。
  • “Gemini 在 long context 上的一些技巧真的让我惊讶。”(笑)

AI 人才稀缺性质疑

  • 高薪是因为大家觉得稀缺,但**”可能没那么稀缺——训练一个人不难,只是你需要遇到做这件事的环境。过去有这种机会的人不多,所以市场上相对稀缺。另一方面,可能对某些人的吹捧也过头了,大家特别爱神话某些人。”**

他设计的面试题(可公开)

  • 要求候选人 24 小时从零做一个 RL 项目——自己选模型、数据、算法,然后和他讨论一小时。
  • 两个目的:
    1. 看候选人与 AI 合作的能力(现在写代码本身不再稀缺)——有个陷阱:如果完全把活丢给 AI 自己不理解,讨论一小时就暴露了
    2. 24 小时限制是看他重不重视这个机会——能不能熬夜。不重视的人连这 24 小时都熬不住。“(笑)”这里面还有些阴暗的小巧思。”

工程 vs 科学

  • “谷歌的预训练现在已经变成工程项目——自上而下、节点清晰、可评估。这是谷歌的强项。”
  • 后训练不确定性更大,仍是自下而上、每个人尝试不同方法。

组织的核心原则

  • “系统稳固 + 个人英雄不闪耀”“允许个人英雄闪耀但系统脆弱” 的 trade-off。
  • 他倾向前者——“系统不稳固的一个例子就是 OpenAI:一个人走,整个结构就可能塌。”
  • 对自己的要求:“研究员必须为整体考虑,不然不是好研究员。在学术界是’一人吃饱全家不愁’;在公司里你要对公司负责——这是两种完全不同的心态。”
  • 他承认:”我可能就是拉不下脸——既然签了合约,我觉得不按合约做没什么道理。”

TPU vs GPU

  • 大规模商业部署上没有优劣差异。开源生态 GPU 更好,但这对大规模部署不是瓶颈。
  • 设计理念不同:
    • GPU(尤其 Hopper 一代):单 pod 内 NVLink 带宽极高,但 pod 内卡少(8 张)。
    • TPU:放弃卡间两两互联,用 3D Torus 拓扑把更多卡组成一个大 rack,每张卡只与 3 个最近邻相连。如果编译器/分片写得好,总内存容量更大、通信瓶颈更少
  • TPU 缺点:小规模用不灵活、通用性差

对 xAI 的评价

简短、尖锐:“我不理解。他们一直都挺动荡的。”(笑)


十六、集体主义胜利(3:23:33)

对新实验室潮的吐槽

  • 最近硅谷一堆新 AI 实验室:”绝大多数新实验室会倒闭。
  • Thinking Machines 还在持续出新东西;但某些新实验室(后期消音)——“我完全不知道他们想干嘛,创始人其实已经离开赛场很久了。”

中美路线分化

  • 中美已分道扬镳。中国优势在消费侧
    • “中国能想出非常复杂、看起来很不自然的产品结构,让利润滚雪球——抖音你看视频不收 0.2 美元,但偷偷加广告、直播、电商。”
    • 美国这种玩法玩不转——“生产力软件:我帮你写代码,150 成本,200 卖给你,我赚 50,就这么简单。”
  • “Meta 就应该直接抄字节跳动——它又找不到自己的定位,做消费产品的能力又远不如字节。但美国过去十年有个正反馈循环:B2B 太容易赚钱,大家都不想烧脑研究如何赚消费端的钱。”

AI 人工神话

  • “我进这个行业的时候,个人英雄主义时代已经过去了——所以没有英雄。”
  • “没有哪个老登是你的亲戚——所以你觉得他傻,他就是傻,可以直接说他傻,无所谓。”(笑)
  • 为什么敢这么讲?
    1. “我在这个行业没有什么导师,没有什么旧友,我当然想喷谁就喷谁。”
    2. “这个领域足够客观——你在这个领域做得怎么样是有客观评价标准的,最终大家会尊重你。只要你观点自洽、不是乱喷,不用太担心因为观点得罪谁。”
  • 为什么来 AI:“AI 这个事本来也不太需要脑子,真的不太需要脑子。这个行业最重要的特质就是靠谱、做事细、对自己做的事情负责任。” 在物理里,他见过比自己聪明得多的人(比如他的博士导师 Douglas Stanford)——“他在那里,哪还需要我?”
  • 对旧时代 AI”英雄”的评价(点名后期消音,但线索明显):
    • XXX(某位以模糊表述见长的人)“我觉得他一直都挺蠢的”——“用 Pauli 的话说,他甚至不能算错,因为他说的东西都没有明确定义——我最讨厌这种模糊的人,模糊的东西没有意义。
    • 他愿意承认的英雄:
      • Haldane(霍尔丹,凝聚态物理拓扑态的奠基人)——“他第一次提出 Haldane model 和分数量子霍尔相关的东西,离后来整个领域搞明白拓扑态还隔了几十年,但他当时就能感觉到这件事重要,一直推动。”
      • Geoffrey Hinton(字幕译为”杰弗里·辛顿”)——“在大家都觉得 AI 这条路不确定时,他一直朝这个方向。这或许是英雄级别的人物。”
      • Transformer 集体(Noam Shazeer、Ashish Vaswani、Niki Parmar 等)——“这可能是一个英雄集体。”
  • 对”老登”(中文网络对守旧老年男性的贬称)的态度:
    • “大多数老登其实挺好的——人老了会分成两种:一种是德高望重、不再挑刺、真正指导年轻人;另一种是根本不知道自己在说什么,还特别爱挑刺和对人指手画脚。变老不一定就是老登。
    • 他不是一开始就这么直接的——“学生时代比较克制,但后来发现克制对自己没好处,对别人也没好处。进 AI 之后变得更直接——没有任何东西会阻挡我,而且这个领域足够客观。”

给年轻人的建议

  • 纯语言模型方向:“蓝海已经不是蓝海了,我赶上了末班车。”
  • 但 AI 是非常大的领域——多模态生成、机器人、用 AI 解决实际科学问题(如量子控制)都还是蓝海。
  • “对足够年轻的人,做现在最热的事未必是对的;做没人做的事,可能是更好的选择。”

关于自己的未来

  • 不会在谷歌长留(”如此公开地表达这一点——我觉得可能不会。”)。
  • “我还是会去挑战自己,需要折磨自己,只是得先找到值得折磨自己的东西。”
  • 不太可能再跳大厂;也没想做 AI for Physics——“很多人已经在做,多我一个不多,少我一个不少。”
  • 当前首要任务:把 ML coding 和 long horizon 推到相对稳定的状态。

推荐

  • 改变人生的书:“说实话我没有。” 最近读的是 汤川秀树(Hideki Yukawa,1949 年诺贝尔物理学奖)自传《旅人》(Tabibito)——“能看到一位后来非常成功的科学家,年轻时真实的挣扎。”
  • 休闲读物:《来自新世界》(贵志佑介,日本小说)。
  • 最喜欢的地方:夏威夷(因为喜欢大海)。
  • 食物:寿司。
  • 他认为最有影响力的 AI 论文:
    • Seq2Seq
    • Scaling Law 论文(Jared Kaplan 等 OpenAI 那篇)——“虽然具体方法可能不完全对,但它是第一篇把这种系统性研究方法引入领域的论文,至关重要。”
  • MBTI?“不知道。”

最后一问:”关键的赌注是什么?”

“Long horizon.(长时程)”


补充:几个交叉验证与背景注释

  1. 离职 Anthropic 原因的对照:姚顺宇在个人博客(alfredyao.github.io)的说法与访谈一致——强调”不想让自己的经验被特定实验室局限,尤其现在核心研究很少发表论文”。访谈中他直接说出 约 40% 是反对 Dario 反华立场,这在其博客和 36kr、新智元等公开报道中也有交叉证据。
  2. 参与的模型的可靠性:36kr 报道证实他参与了 Claude 3.7(agentic coding)和 Claude 4 family(RL numerics);Gemini 3 Deep Think 的参与也有谷歌自家公告确认。
  3. 非厄米趋肤效应:访谈中他描述的”周期/开放边界结果完全对不上、本征态全部堆积在边界”正是 PRL 论文 Edge States and Topological Invariants of Non-Hermitian Systems(Yao & Wang 2018)的核心发现,与本人描述完全吻合——字幕里的”王忠”实为王中(Zhong Wang)张守成/寿城实为张首晟(Shoucheng Zhang)
  4. 博士导师:Douglas Stanford 和 Stephen Shenker 是 Stanford Institute for Theoretical Physics 的顶级高能/量子引力学家,访谈中他特别说 Douglas Stanford “比我聪明得多”——是真诚的敬畏。
  5. “Claude 3.6 其实是 3.5 new”:这点与 Anthropic 官方命名历史一致,外部社区确实因 Claude 3.5 出了两个版本而自发叫后者”3.6”。
  6. 节目录制时间(2026 年 3 月)与发布时间(2026 年 5 月)之间已发生:Meta 对 Manus 收购被撤销、Cursor 可能被 SpaceX 收购、xAI 并入 SpaceX——文中相关表述按录制时状态保留,访谈中嘉宾对 xAI 的吐槽(”一直挺动荡”)反而被事态坐实。

核心观点速览

维度 姚顺宇的判断
预训练 远没到头,过去几个月一直在变强;觉得撞墙多半是代码 bug 没找到
后训练 真正大规模化始于 Claude 3.7;关键在数据分布是窄而精
Coding 爆发源于奖励信号清晰 + GitHub 数据基座;已是 AI-native 唯一大规模成功场景
机器人/多模态生成 都还没到 GPT-1 阶段,还在特征工程时代
Chatbot 形态 蠢,远不是终极形态,需要产品经理解锁
Wrapper 生存 要么成长够快(Cursor),要么市场够小(Midjourney);否则都被收购
AI 安全 Anthropic 的”造最强模型才有话语权”太天真;真正的机制类比是核武器多方威慑
蒸馏 硬蒸可耻且蠢;软蒸是 multi-agent 训练的先驱,技术上有趣
组织 系统稳固 > 个人英雄闪耀;OpenAI 是反例
英雄主义 语言模型领域已经过去;现在都是冲浪者,本质是那个浪
AI 本质 简单——因为可以做实验,受限的只是算力和 infra,无根本困难
给年轻人 语言模型蓝海已过;做没人做的事
个人风格 直接、可以喷人、”老登不是你亲戚”、拒绝模糊表述

AWS 云计算:全球第一的光环下,藏着怎样的真相?

AWS 是全球云计算市场占有率第一的厂商,这一地位已持续十余年。但”第一”是否等于”最好”?当我们抛开品牌光环,从架构设计、工程实践、性能数据、价格四个维度进行实测和分析后,得出的结论可能会颠覆很多人的认知。

本文所有结论均基于一手测试数据和抓包分析,不做任何主观外推。


一、设计理念:高可用的代价,用户买单

1.1 强制跨可用区:每次写入都要跨机房

AWS 的 RDS MySQL 默认部署模式是 Multi-AZ(多可用区),主备实例强制分布在不同的可用区。这一设计的出发点是高可用——单个机房故障时可以自动切换。但代价是什么?

每一次写操作,至少需要跨可用区至少 1 次:

  1. 应用写入主库 → EBS 通过网络同 AZ落盘
  2. 半同步复制 → 跨 AZ 将 binlog 发送到备库
  3. 备库确认收到 → 跨 AZ 返回 ACK

实测 AWS 可用区间 RTT 约 0.75ms 。这意味着仅网络延迟这一项,每次写操作就要额外付出 0.75ms 的开销,这在数据库上是无法忍受的慢慢慢!

以上是理论计算,我们来看一下实际业务体感:

  • AWS 上一次最简单的 INSERT:3.32ms(业务实测)
  • 同样的业务在 IDC 物理机:微秒级(0.x ms)

差距不是百分之几十,而是 数倍到一个数量级

1.2 对比:阿里云的灵活选择

阿里云 RDS 提供集群模式,允许将 2 个节点部署在同一可用区,在对延迟极度敏感的场景下实现接近 IDC 的性能。用户可以根据自身业务特点在”极致高可用”和”极致低延迟”之间做选择。

AWS 和华为云目前不提供这种灵活性,用户被强制接受跨 AZ 的延迟开销。

1.3 云盘延迟:贵不等于快

AWS 的 EBS 云盘走网络存储,延迟远高于本地盘。实测数据(fio 4K 随机读写,iodepth=1):

云盘类型 读延迟 写延迟
AWS io2(最贵) 393 us 306 us
AWS io1 588 us 868 us
AWS gp3 686 us 994 us

gp3 写延迟接近 1ms ,而阿里云 ESSD 在同等场景下可以做到 0.1~0.2ms 级别。AWS 最高档的 io2 写延迟(306us)仍然是阿里云高性能云盘的 2-3 倍

对于数据库这种对 IO 延迟极度敏感的负载,这意味着每一个 commit 都在额外等待。


二、工程实践:350 秒连接静默丢弃事件

如果说设计理念的问题还可以归结为”理念之争”,那么以下这个事件则暴露了 AWS 在工程实践和事故响应上的严重问题。

2.1 问题现象

业务迁移到 AWS 第 8 代实例(M8/C8/R8,Nitrov6 架构)后,Java 服务每隔 20~30 分钟出现批量连接超时:

1
Connection is not available; request timed out after 5006ms

网络延迟稳定在 ~8ms,0% 丢包,MySQL 健康。

2.2 根因:ENI 连接跟踪超时从 5 天骤降至 350 秒

通过 80 分钟、84595 个包的系统性抓包分析,定位到根因:

AWS 第 8 代实例的 ENI(弹性网卡)安全组连接跟踪,将 TCP Established 默认超时从 432000 秒(5 天)悄然改为 350 秒。

实例代次 Nitro 版本 TCP Established 默认超时
第 7 代及以下 Nitrov5 及以下 432000s(5 天)
第 8 代(M8/C8/R8) Nitrov6 350s

这是一个 1234 倍的缩减 ,且行为极为恶劣——超时后 ENI 静默丢弃数据包,不发送 RST,不通知任何一方。抓包中 84595 个包 0 个 RST

客户端和服务端都以为对方还在,TCP 连接变成”僵尸”——直到下次使用时才发现已死,此时应用只能等待重传超时(数十秒到数分钟),表现为”突然卡住然后超时”。

2.3 AWS 的事故复盘令人失望

这一事件中 AWS 的表现:

  1. 文档滞后:用户 4 月初碰到问题,4 月 7 日定位到中间设备释放连接,4 月 15 日还在抓包验证。而 AWS 直到 4 月 11 日才在文档中加入警告段(通过 Wayback Machine 快照对比确认)

  2. 变更未通知:从 432000s 改到 350s 这种破坏性变更,C8gn GA 公告(2025-06)中未提及超时变更。用户升级实例后莫名遇到连接问题,排查成本极高

  3. 比 NAT Gateway 更”哑”

    • NAT Gateway / NLB 超时后至少一侧会收到 RST,应用能感知”对端断了”
    • ENI conntrack 超时:双侧都收不到 RST ,包被静默丢弃,应用只能靠 OS 重传超时来发现
  4. 复盘质量:AWS 官方的事件复盘未能清晰阐述根因,定位路径模糊

2.4 “350 秒”——AWS 的系统性问题

350 秒这个数字在 AWS 生态中反复出现:

组件 空闲超时 超时后行为
NAT Gateway 350s(固定) 发 RST
NLB(2024-09 前) 350s(固定) 发 RST
GWLB 350s 发 RST
ENI Conntrack(Nitrov6) 350s(默认) 静默丢弃

社区早在 2021 年就有人踩坑(Paramount Tech Blog),2022 年 DBA 博客记录了 JDBC 挂起问题,2023 年 urllib3 专门开了 Issue。这不是新问题,但 AWS 在 ENI 层面重蹈覆辙,且行为更恶劣(不发 RST)。


三、性能数据:Sysbench 实测全面落后

以下数据来自 10 个环境的标准化 Sysbench 测试,使用 16 表 x 1000 万行(约 50GB 数据),MySQL Buffer Pool 16GB,故意制造 IO 压力以考验真实磁盘性能。

3.1 只写场景(oltp_write_only)—— 单线程 QPS

这是最能体现”每次写操作延迟”的场景:

环境 1 线程 QPS 对比 IDC
IDC(物理机) 19,282 基准
IDC(trx1) 15,367 80%
阿里云 12,484 65%
阿里云(trx1+repl) 5,832 30%
AWS io2 8,881 46%
AWS io2(trx1) 3,575 19%
AWS gp3 1,689 9%

AWS gp3 单线程写入性能仅为 IDC 的 9%,仅为阿里云的 14%。 即使用最贵的 io2 云盘(价格是 gp3 的数倍),开启 trx1 后也只有 IDC 的 19%。

3.2 读写混合场景(oltp_read_write)—— 64 线程 QPS

环境 64 线程 QPS 对比阿里云
阿里云 83,569 基准
IDC 69,255 83%
AWS io2 51,002 61%
AWS gp3 64,869 78%

3.3 点查询场景(oltp_point_select)—— 64 线程 QPS

环境 64 线程 QPS 对比阿里云
阿里云 328,098 基准
IDC 299,555 91%
AWS io2 157,480 48%
AWS gp3 228,321 70%

AWS io2 在纯读场景下也只有阿里云的 48% ,令人诧异。

3.4 延迟对比(95 分位,单线程)

场景 IDC 阿里云 AWS io2 AWS gp3
点查询 0.04ms 0.07ms 0.09ms 0.67ms
只写 0.52ms 0.99ms 1.61ms 5.99ms
读写混合 2.81ms 3.30ms 3.89ms 15.00ms

AWS gp3 的只写延迟是 IDC 的 11.5 倍,是阿里云的 6 倍。

3.5 小结

即便使用 AWS 最贵的 io2 云盘(2T 云盘价格是 8C32G 机器的 8 倍),性能仍然大幅落后于阿里云使用普通云盘的配置。云盘延迟是 AWS 数据库性能的致命瓶颈。


四、价格:花更多的钱,买更差的性能

4.1 AWS RDS MySQL 成本

以 16C64G、GP3 2TB 20000 IOPS、3 节点(1 主 1 Multi-AZ 备 1 只读副本)为例:

Intel(db.m5d.4xlarge):

  • 计算:¥204,964/年(折后)
  • 存储(GP3 2TB x3):¥83,589/年(折后)
  • 监控(CloudWatch):¥25,713/年(折后)
  • 合计:约 ¥314,266/年

ARM(db.m6gd.4xlarge):

  • 计算:¥183,718/年(折后)
  • 存储:¥83,589/年(折后)
  • 合计:约 ¥267,307/年(不含监控)

最新一代 Intel(m7i.4xlarge,ap-southeast-1):价格更高。

4.2 性价比对比

维度 AWS(io2,最贵) AWS(gp3) 阿里云
只写 64 线程 QPS 79,754 43,519 110,923
读写混合 64 线程 QPS 51,002 64,869 83,569
云盘写延迟(iodepth=1) 306 us 994 us ~100-200 us
价格档位 极高

AWS 用最贵的云盘(io2),花了最多的钱,性能仍然不如阿里云用普通云盘。

io2 的 2T 云盘年费约为同规格机器的 8 倍——付出如此高昂的代价,换来的却是垫底的性能表现。

4.3 隐性成本

除了直接的资源费用,AWS 还有大量隐性成本:

  • 排障成本:350 秒静默丢连接这种问题,排查周期以周计,需要系统性抓包分析
  • 架构妥协成本:被迫跨 AZ 部署,无法选择同 AZ 低延迟模式
  • 升级风险成本:实例升代时默认行为发生破坏性变更,无事先通知
  • 学习曲线成本:需要深入了解 ENI 连接跟踪、NAT Gateway 固定超时等独有”坑点”

五、结论:惯性认知 vs 客观事实

AWS 能成为全球第一,有其历史原因:起步最早(2006 年)、生态最完善、全球覆盖最广。但”市场占有率第一”不等于”技术最优”,更不等于”性价比最高”。

从本文的实测数据来看:

维度 表现
设计理念 强制跨 AZ,牺牲延迟换高可用,不给用户选择权
工程实践 350s 超时静默丢包,变更不通知,复盘不透明
性能 全场景 Sysbench 垫底,gp3 只写仅为 IDC 的 9%
价格 同等配置显著高于竞品,io2 价格是机器的 8 倍
性价比 花最多的钱,得到最差的性能

很多企业选择 AWS 的原因是”大家都在用””全球第一应该不会错”——这是典型的幸存者偏差品牌惯性。当我们真正用数据说话时,会发现这个”全球第一”的光环,更多是依靠先发优势和生态锁定维持的,而非技术和性价比的领先。

对于数据库这类对延迟和 IO 性能极度敏感的工作负载,在有选择的情况下,AWS 恐怕是最不应该选的那一个。

当然站在 AWS 立场有一个必杀技:AWS 的设计理念就是……


注:本文所有性能数据均来自实际测试环境,测试工具为 sysbench,测试代码开源。网络分析基于 84595 个包的系统性抓包。价格数据来自官方控制台和报价器。文档变更时间线通过 Wayback Machine 快照验证。

AWS 连接超时根因分析

问题现象

业务从本地机房迁移到 AWS 后,Java 服务访问跨机房 MySQL 数据库(AWS EC2 → 专线 → 本地机房 DB),每隔 20~30 分钟出现批量连接超时:

1
2
Failed to validate connection (No operations allowed after connection closed.)
Connection is not available; request timed out after 5006ms

关键特征:

  • 网络延迟稳定在 ~8ms,0% 丢包
  • MySQL 健康(wait_timeout=86400s, Threads_connected 正常)
  • 调整 HikariCP maxLifetime 从 30 分钟改为 20 分钟后,报错间隔也跟着变成 20 分钟
  • 旧服务(本地机房内部)无此问题,只有跨机房访问才出现

排查过程

第一轮:HikariCP 连接池分析

初始怀疑是 HikariCP 3.x 的 maxLifetime 机制导致连接集中过期。

验证方法:搭建 HikariCP 3.4.5 + MySQL 5.7 的独立 Demo,配置 poolSize=10, minimumIdle=maximumPoolSize, maxLifetime=90s,观察连接过期行为。

发现:HikariCP 在 maxLifetime 到期时主动异步替换连接,每个替换仅需 3-8ms:

1
2
10:32:23.996 Closing connection @6d21071: (connection has passed maxLifetime)
10:32:24.004 Added connection @60401ca4 ← 8ms 后替换完成

结论:在 MySQL 可达且网络正常(RTT < 20ms)的环境下,纯 maxLifetime 批量过期无法导致连接超时。HikariCP 的异步替换机制工作正常。问题的根因不在 HikariCP 本身。

第二轮:TCP keepalive 与中间设备分析

AWS → 本地机房的网络路径中存在防火墙(空闲会话 30 分钟清除),可能还有 NAT Gateway 等中间设备。

关键验证:反编译 MySQL Connector/J 5.1.49 字节码,确认 tcpKeepAlive 默认值:

1
2
3
// ConnectionPropertiesImpl.class 字节码
3970: ldc_w #519 // String tcpKeepAlive
3973: ldc_w #514 // String true ← 默认值 = true(从 5.0.7 开始)

同时通过 ss -tnpei 验证运行中的 JDBC 连接确实开启了 SO_KEEPALIVE:

1
ESTAB 127.0.0.1:62718 → 127.0.0.1:3316 timer:(keepalive,5.519ms,0)

AWS EC2 的 tcp_keepalive_time = 1200s(20 分钟)。如果中间设备的空闲超时 < 1200s,keepalive 探测会来不及续命,连接被静默丢弃。

第三轮:抓包分析定位精确超时

在 AWS EC2 上抓取了约 80 分钟的 MySQL 连接网络包(84595 个包,145 个连接),进行系统性分析。

核心发现

1. 零 RST —— 中间设备静默丢弃连接

84595 个包中没有一个 RST 包。中间设备删除会话后不通知任何一方,TCP 连接变成”僵尸”——客户端和服务端都以为对方还在。

2. 精确定位中间设备超时:340~350 秒

按连接空闲时间统计 Server 是否响应了客户端的 FIN:

空闲时间 Server 响应 结论
333.9s (5.6min) ✅ 正常响应 连接存活
334s ~ 358s 临界区
357.7s (6.0min) ❌ 无响应 连接已死
  • Server 正常响应 FIN 的 27 个连接:最大空闲时间均 ≤ 334s
  • Server 未响应 FIN 的 98 个连接:最大空闲时间均 ≥ 358s

中间设备空闲超时 ≈ 340~350 秒,后确认为 AWS EC2 Nitrov6(第 8 代实例)ENI 连接跟踪默认超时 350 秒。

3. 僵尸连接的死亡模式

正常连接关闭(空闲 < 350s):

1
Client → COM_QUIT → Server 响应 FIN+ACK → 四次挥手完成 ✅

僵尸连接关闭(空闲 > 350s):

1
2
3
4
5
Client → COM_QUIT    → 被中间设备静默丢弃 → 无响应
Client → 重传 (0.2s) → 丢弃 → 无响应
Client → 重传 (0.4s) → 丢弃 → 无响应
Client → 重传 (0.8s) → 丢弃 → 无响应
Client → FIN → 丢弃 → 永远无响应

根因

2026-04-15 更新:经查 AWS 官方文档 确认,350 秒超时的真正来源是 EC2 第 8 代实例(Nitrov6 架构)的 ENI 安全组连接跟踪(Connection Tracking)默认超时,而非此前推测的 NAT Gateway。

实例代次 Nitro 版本 TCP Established 默认超时
第 7 代及以下 Nitrov5 及以下 432000s(5 天)
第 8 代(M8/C8/R8 等) Nitrov6 350s

可通过 aws ec2 describe-network-interfaces --network-interface-ids <eni-id> --query 'NetworkInterfaces[0].ConnectionTrackingConfiguration' 查询,返回 null 表示使用默认值。控制台路径:EC2 → Network Interfaces → 选择 ENI → 空闲连接跟踪超时。

1
2
3
4
5
6
7
                340~350s                    1200s
ENI 连接跟踪(Nitrov6) keepalive
空闲超时 首次探测
─────────────────┼──────────────────────────────┼──────────
连接空闲 │连接跟踪条目清除 │探测发出
│连接变僵尸 │但已经晚了
│双端不知情 │

三个因素叠加导致问题:

  1. EC2 Nitrov6 ENI 连接跟踪超时 350 秒:第 8 代 EC2 实例(M8/C8/R8 等,Nitrov6 架构)的安全组连接跟踪将 TCP Established 默认超时从 432000s(5天)降至 350s。连接空闲超过 350 秒后,ENI 连接跟踪条目被清除,后续数据包被安全组静默丢弃(不发 RST)
  2. OS tcp_keepalive_time = 1200 秒:远大于连接跟踪超时,keepalive 探测在连接死后 850 秒才发出,来不及续命
  3. HikariCP 3.x 无应用层 keepalive:3.x 版本没有 keepaliveTime 功能,不会主动检测空闲连接的存活状态

maxLifetime 的角色:不是根因,而是暴露问题的时间点。改 maxLifetime 只改变了”何时发现尸体”,而不是”何时死亡”。

旧服务不受影响的原因:旧服务在本地机房内部访问数据库,不经过 AWS EC2,不受 Nitrov6 ENI 连接跟踪超时影响。

验证实验

在 AWS EC2 上对比测试(原始 keepalive vs 调优后的 keepalive):

原始配置(tcp_keepalive_time=1200s):

maxLifetime 结果
5min (300s) ✅ 成功(< NAT 超时 350s)
10min ❌ 失败
15min ❌ 失败
20min ❌ 失败
30min ❌ 失败

调优后(tcp_keepalive_time=20s, intvl=10s, probes=3):

maxLifetime 结果
5min ✅ 成功
10min ✅ 成功
15min ✅ 成功
20min ✅ 成功
30min ✅ 成功

低 keepalive_time 让 OS 每 20 秒发送一次探测包,持续重置 NAT Gateway 的空闲计时器,连接永远不会被丢弃。

修复方案

方案 0:修改 ENI 连接跟踪超时(根因级修复,推荐)

直接调大 EC2 ENI 的 TCP Established 超时,从根源解决问题:

1
2
3
4
aws ec2 modify-network-interface-attribute \
--network-interface-id <eni-id> \
--connection-tracking-specification TcpEstablishedTimeout=432000 \
--region <region>

或在 EC2 控制台:Network Interfaces → 选择 ENI → Actions → Change connection tracking → 设置 TCP established timeout。

优点:根因级修复,恢复到与旧代实例一致的行为(432000s / 5天),无需改 OS 参数或应用配置。
注意:仅对新建连接生效,已有连接不受影响。

方案 1:降低 OS tcp_keepalive_time(最快生效)

1
2
3
4
5
6
7
8
9
10
sysctl -w net.ipv4.tcp_keepalive_time=120    # 2 分钟,远小于 NAT 350s
sysctl -w net.ipv4.tcp_keepalive_intvl=30
sysctl -w net.ipv4.tcp_keepalive_probes=5

# 持久化
cat >> /etc/sysctl.conf << 'EOF'
net.ipv4.tcp_keepalive_time = 120
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 5
EOF

优点:全局生效,所有 TCP 连接(MySQL、Redis、MQ 等)都受益,无需改代码。
注意:120s 远小于 350s,留足安全余量。

方案 2:升级 HikariCP 4.x+ 启用 keepaliveTime(应用层修复)

1
2
3
4
spring.datasource.hikari:
keepalive-time: 120000 # 2 分钟,应用层主动 ping 空闲连接
max-lifetime: 1800000 # 30 分钟
connection-test-query: SELECT 1

优点:不依赖 OS 配置,应用层独立控制。
限制:需要升级 HikariCP(4.0+ 才有 keepaliveTime),可能需要升级 JDK。

方案 3:不升级 HikariCP 的临时方案

1
2
3
4
5
6
7
spring.datasource.hikari:
maximum-pool-size: 32
minimum-idle: 10 # 必须 < maximum-pool-size
idle-timeout: 120000 # 2 分钟淘汰多余空闲连接
max-lifetime: 300000 # 5 分钟(< NAT 350s)
connection-test-query: SELECT 1 # 借出时验证
connection-timeout: 10000 # 给更多时间创建替换连接

原理:maxLifetime=5min < NAT 超时 350s,确保连接在被 NAT 丢弃前主动替换。
缺点:5 分钟的 maxLifetime 较短,连接轮换频繁,增加数据库连接创建负担。

推荐组合:方案 0(根因修复)+ 方案 1 + 方案 2(ENI 层 + OS 层 + 应用层三重保险)。

经验教训

1. 跨网络访问必须关注中间设备的空闲超时

本地机房内部的 TCP 连接可以长期空闲而不被打断。但跨机房、跨云的网络路径上往往存在 NAT Gateway、防火墙、LVS 等有状态设备,它们都有空闲会话超时(通常 5~30 分钟)。

迁移到云上时,即使 ping 延迟正常、丢包率为 0,仍然需要检查中间设备的空闲超时配置。

设备 典型空闲超时
AWS EC2 Nitrov6 ENI 连接跟踪 350s(第 8 代实例默认)
AWS EC2 旧代 ENI 连接跟踪 432000s(5 天)
AWS NAT Gateway 350s(~6 分钟)
防火墙 1800s(30 分钟)
LVS (IPVS) 900s(15 分钟)
云厂商 SLB/NLB 300~900s

2. tcp_keepalive_time 必须小于路径上最短的空闲超时

操作系统默认的 tcp_keepalive_time 通常是 7200s(2 小时),AWS 默认是 1200s(20 分钟)。这些默认值在存在中间设备的场景下往往过大。

建议值:60~120 秒,覆盖绝大多数中间设备的超时配置。

3. SO_KEEPALIVE 必须开启才有效

tcp_keepalive_time 是系统级默认值,但只对设置了 SO_KEEPALIVE 的 socket 生效

组件 SO_KEEPALIVE 默认值
MySQL Connector/J 5.1.x true(从 5.0.7 开始)
MySQL Connector/J 8.x true
应用直接创建 Socket false
Druid 连接池 不控制(依赖驱动)

验证方法:

1
2
ss -tnpei dst <db_ip>:<db_port> | head -3
# 看 timer:(keepalive,...) → 有则开启,无则关闭

4. 静默丢弃是最难排查的连接故障

本案中 NAT Gateway 不发 RST,直接丢弃不匹配的包。这导致:

  • 客户端发送数据后只能等待重传超时(数十秒到数分钟)
  • 没有任何”连接已断开”的信号
  • 从应用层看就是”突然卡住然后超时”

排查手段:在客户端抓包,关注两个信号:

  • 发送数据后长时间无 ACK(→ 中间设备丢包)
  • FIN 发出后无响应(→ 连接在中间设备已不存在)

5. “修改 maxLifetime 后报错时间跟着变”不能排除中间设备问题

这个现象容易误导排查方向。直觉上会认为”报错时间跟 maxLifetime 走,说明是 HikariCP 的问题”。实际上:

  • maxLifetime < 中间设备超时 → 连接在死之前被主动替换 → 不报错
  • maxLifetime > 中间设备超时 → 连接已死 → maxLifetime 到期时操作已死连接 → 报错

报错时间跟 maxLifetime 走,恰恰说明存在一个固定的中间设备超时阈值。

6. 连接池不是万能的

连接池(HikariCP、Druid 等)管理的是 JDBC Connection 对象的生命周期,但底层 TCP 连接的存活状态取决于 OS 和网络。连接池无法感知”TCP 连接已被中间设备静默丢弃”——除非主动发送数据去探测。

这就是 HikariCP 4.x 引入 keepaliveTime 的原因:定期向空闲连接发送 SELECT 1,主动打破沉默,让死连接尽早暴露。

7. ENI为什么只丢掉进来的包,而不丢掉出去的包?

这个问题直接触及 AWS 安全组的工作原理。

核心原因:出站靠的是显式规则,入站靠的是连接跟踪。

安全组通常这样配置:

1
2
3
出站规则 (Outbound):  0.0.0.0/0  All traffic  → ALLOW   ← 默认就是放行全部
入站规则 (Inbound): 10.0.0.0/8 TCP 22 → ALLOW ← 只开放特定端口
(没有 "允许来自 172.20.64.240:3306 的回包" 这条规则)

连接跟踪活着的时候(空闲 < 350s):

1
2
Client 出站 → 匹配出站规则 (allow all) → 放行 ✅ → 同时创建跟踪条目
Server 回包 → 匹配跟踪条目 (return traffic) → 放行 ✅ ← 不看入站规则,靠跟踪放行

连接跟踪过期后(空闲 > 350s):

1
2
Client 出站 → 匹配出站规则 (allow all) → 放行 ✅   ← 规则还在,照样放行
Server 回包 → 无跟踪条目 → 回退检查入站规则 → 无匹配规则 → 丢弃 ❌

所以不对称的根源是:出站有兜底的 allow-all 规则,入站没有。Server 的回包以前全靠连接跟踪
“搭便车”进来,跟踪条目一过期,便车没了,入站规则又没有显式放行这个流量,就被丢了。

如果你在入站规则里加一条 allow from 172.20.64.240/32 port 3306,理论上即使连接跟踪过期,
回包也能通过显式规则放行——但这就变成无状态过滤了,一般不建议这么做。

附录

抓包统计数据

指标 数据
抓包时长 4796 秒(~80 分钟)
总包数 84595
总连接数 145
RST 包数 0
Server 正常响应 FIN 27 个(最大空闲 ≤ 334s)
Server 未响应 FIN 98 个(最大空闲 ≥ 358s)
中间设备空闲超时 340~350s(与 EC2 Nitrov6 ENI 连接跟踪默认 350s 吻合)

测试代码

测试 Demo 代码位于同目录,修改 db.propertiesbash run.sh 即可运行,无需编译。

TCP 排障入门指南

本文从团队知识库中提炼而来,面向刚接触网络排障的新同学。不讲大而全的理论,只讲排障时真正用得上的东西。

第一课:排障的核心思维

记住三句话,比记住任何工具都重要:

  1. 一个错误现象可能对应多个完全不同的根因 —— 不要看到报错就下结论
  2. 不要相信报错信息的字面意思 —— 比如 net_write_timeout 报错不一定是超时
  3. 拿证据推进问题 —— 每一步推理都要有抓包、日志、堆栈等证据支撑

排障工具的优先级:

1
2
3
4
5
6
7
抓包(tcpdump/wireshark)  ← 网络层面的终极证据,优先用

堆栈/火焰图(perf/jstack) ← 定位代码热点

日志分析 ← 但要警惕日志被吃掉的情况

监控指标 ← 宏观趋势,不够精确

第二课:你必须知道的 TCP 基础

三次握手

1
2
3
4
Client              Server
|--- SYN ---------->| Client 进入 SYN_SENT
|<-- SYN+ACK -------| Server 进入 SYN_RECV(半连接队列)
|--- ACK ---------->| 双方进入 ESTABLISHED(全连接队列)

握手失败的常见原因:

现象 原因 怎么查
精确 1s/3s/7s 超时 SYN 被丢弃后重传 全连接队列满?防火墙 DROP?
Connection refused 端口没人监听 ss -lntp 看端口
偶发连接超时 半连接/全连接队列满 netstat -s | grep listen
NAT 下偶发不通 tcp_tw_recycle 丢 SYN netstat -s | grep "time stamp"

新人必记:碰到精确的 1s、3s、7s 超时,几乎可以断定是 SYN 丢包重传。SYN 重传间隔是 1s→2s→4s→8s 指数退避。

四次挥手

1
2
3
4
5
主动方              被动方
|--- FIN ---------->| 主动方: FIN_WAIT_1
|<-- ACK -----------| 被动方: CLOSE_WAIT ← 最常见的堆积点
|<-- FIN -----------| 被动方: LAST_ACK
|--- ACK ---------->| 主动方: TIME_WAIT(等 60 秒)
状态堆积 说明 排查
大量 CLOSE_WAIT 你的应用没调 close() ss -tp 看是哪个进程
大量 TIME_WAIT 短连接太多,通常无害 tcp_tw_reuse 缓解

新人必记:CLOSE_WAIT 是被动关闭方的状态,问题一定在你这边的应用代码。

传输性能公式

1
理论最大吞吐 ≈ min(发送窗口, 接收窗口, 拥塞窗口) / RTT

速度上不去时检查:

  • Buffer 太小ss -tm 看 skmem,检查 tcp_rmem / tcp_wmem
  • RTT 太大:RTT 越大,慢启动越久,丢包恢复越慢
  • 丢包:一旦丢包 RTO 指数退避(最大 120 秒),速度断崖式下降

第三课:五个必会的排障命令

1. ss —— 看连接状态(替代 netstat)

1
2
3
4
5
6
7
8
# 看监听端口的全连接队列(Recv-Q 是当前排队数,Send-Q 是队列上限)
ss -lnt

# 看所有 TCP 连接的详细信息(含 buffer、RTT、拥塞窗口)
ss -tinp

# 看连接统计
ss -s

2. netstat -s —— 看协议栈统计

1
2
3
4
5
6
7
8
9
10
11
# 全连接队列溢出(数字在增长就是有问题)
netstat -s | grep "listen queue"

# SYN 被丢弃
netstat -s | grep "SYNs to LISTEN"

# tcp_tw_recycle 导致的丢包
netstat -s | grep "passive connections rejected because of time stamp"

# 丢包/重传汇总
netstat -s | egrep -i "drop|retran|overflow|reject"

3. tcpdump —— 抓包

1
2
3
4
5
6
7
8
9
10
11
# 抓指定端口,保存为文件(用 wireshark 打开分析)
tcpdump -i eth0 port 3306 -s0 -w mysql.pcap

# 抓所有网卡(别忘了 lo,nginx→tomcat 走的是 lo)
tcpdump -i any port 8080 -s0 -w all.pcap

# 只抓 RST 包
tcpdump 'tcp[tcpflags] & (tcp-rst) != 0'

# 只抓 SYN 包(排查握手问题)
tcpdump 'tcp[tcpflags] & (tcp-syn) != 0'

新人必记:抓包时一定要抓 所有网卡-i any),不要只抓 eth0。很多内部通信走 lo 网卡,只抓 eth0 会漏掉关键包。

4. tshark —— 命令行分析抓包

1
2
3
4
5
6
7
8
# 统计每个连接的 RT
tshark -r file.pcap -q -z io,stat,1

# 过滤 MySQL 错误
tshark -r file.pcap -Y "mysql.error_code != 0"

# 看 TCP 重传
tshark -r file.pcap -Y "tcp.analysis.retransmission"

5. 内核参数快速检查

1
2
3
4
5
6
7
# 一键查看关键 TCP 参数
sysctl net.ipv4.tcp_tw_recycle # 必须是 0!
sysctl net.core.somaxconn # 全连接队列上限,建议 ≥ 2048
sysctl net.ipv4.tcp_max_syn_backlog # 半连接队列
sysctl net.ipv4.tcp_retries2 # 重传放弃次数,内网建议 5-10
sysctl net.ipv4.tcp_rmem # 接收 buffer
sysctl net.ipv4.tcp_wmem # 发送 buffer

第四课:按现象查问题(速查表)

连不上

现象 第一步 第二步
Connection refused ss -lntp 看端口是否在监听 检查进程是否存活
超时 1s/3s/7s netstat -s | grep listen 看队列溢出 抓包确认 SYN 是否被丢
偶发超时(NAT 环境) sysctl net.ipv4.tcp_tw_recycle 如果是 1 立即改 0
部分机器不通 traceroute + 两端同时抓包 检查路由/ARP/交换机

连上了但是断开

现象 第一步 第二步
Connection reset 抓包看 RST 是谁发的 检查防火墙/中间设备
大量 CLOSE_WAIT ss -tp 找到对应进程 检查代码是否漏了 close()
服务切换后长时间不恢复 检查 tcp_retries2 调小到 5-10

连上了但是慢

现象 第一步 第二步
RT 偶发 40ms 毛刺 抓包看是否 Delayed ACK 设置 TCP_NODELAY
传输速度上不去 ss -ti 看 cwnd/ssthresh/rto 检查 rmem/wmem 是否太小
速度突然下降 抓包看是否有重传 检查 RTO 是否飙到 120s

第五课:四个真实案例(必读)

案例 1:报错说 net_write_timeout,其实是被 kill 了

迁移工具报 Consider raising value of 'net_write_timeout',调大参数无效。抓包发现 MySQL Server 在传数据途中夹带了 FIN 包,查 DB 日志发现是用户自己的监控脚本 kill 了慢查询。

教训:JDBC streaming 模式下任何连接异常都报 net_write_timeout,不要被字面意思骗了。抓包看谁先发 FIN 是铁证。

详见:历时 5 年的 net_write_timeout 分析

案例 2:Sysbench 性能只有预期的 10%

processlist 全是 Opening tables,调大 table_open_cache 无效。最后发现是 --tables=64 写错了(实际只有 32 张表),加上 --mysql-ignore-errors=all 把 Error 1146 全吞了。

教训:抓包能看到 Error 1146 和异常 RT(2200ms vs 正常 0.1ms),即使不知道问题在哪,抓包也能发现异常。

详见:Sysbench Opening Tables 卡慢

案例 3:数据库重启后业务 15 分钟才恢复

数据库 crash 重启后,业务长时间报错。原因是 tcp_retries2 默认 15,TCP 需要约 924 秒(15 分钟)才能感知到连接断开。

教训:内网把 tcp_retries2 改成 5-10。应用层心跳比 TCP Keepalive 更可靠。

详见:长连接黑洞

案例 4:开了 tcp_tw_recycle,NAT 下偶发连不上

服务端开了 tcp_tw_recycle,NAT 后面多台客户端的 TCP timestamp 不一致,导致 SYN 被 PAWS 校验丢弃。

教训:永远不要开 tcp_tw_recycle。4.12 内核已删除此参数。用 netstat -s | grep "time stamp" 诊断。

详见:tcp_tw_recycle + NAT 导致 SYN 丢包

第六课:新人上手清单

拿到一台新机器,先跑一遍这些命令建立基线:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. 看内核版本(4.12 以下要特别注意 tcp_tw_recycle)
uname -r

# 2. 检查危险参数
sysctl net.ipv4.tcp_tw_recycle 2>/dev/null # 必须是 0 或不存在
sysctl net.core.somaxconn # 太小(128)要调大

# 3. 看当前连接状态分布
ss -s

# 4. 看是否有队列溢出(记下数字,过一会再看是否增长)
netstat -s | egrep -i "listen|overflow|drop|retran"

# 5. 看监听端口的队列使用情况
ss -lnt

延伸阅读

本指南的所有内容都来自团队知识库 ~/case/ 下的原始文档,想深入学习可以按以下路径:

  1. TCP 连接原理网络/就是要你懂TCP--连接和握手.md网络/就是要你懂TCP--半连接队列和全连接队列.md
  2. TCP 性能网络/就是要你懂TCP--性能和发送接收Buffer的关系.md网络/就是要你懂TCP--最经典的TCP性能问题.md
  3. 抓包技巧工具/就是要你懂抓包--WireShark之命令行版tshark.md网络/如何从几百万个抓包中找到一个异常的包.md
  4. 排障方法论网络/举三反一--从理论知识到实际问题的推导.md网络/程序员如何学习和构建网络知识体系.md

本文由 LLM 基于 wiki 知识库自动生成,最后更新:2026-04-07

普京的克里米亚 —— 高晓松谈俄乌局势(2014年)

本文根据高晓松2014年《晓松奇谈》节目音频转录整理,原视频约54分钟。


一、克里米亚为什么重要

在西方人心中的地位

克里米亚对中国人来说不算特别著名,大概只有军迷比较熟悉——中国第一批航母飞行员就在克里米亚的陆上模拟航母基地训练过。但对西方人来说,克里米亚可太著名了。欧洲人提到克里米亚、塞瓦斯托波尔,比提到基辅(乌克兰首都)还要熟悉。巴黎有一条重要大街就叫”塞瓦斯托波尔大街”——法国这么骄傲的国家,用一个俄国地名来命名街道,正是因为法军攻克塞瓦斯托波尔是法国军事史上最光荣的战役之一。

克里米亚战争:现代战争的雏形

1853-1856年的克里米亚战争是英法联军加奥斯曼土耳其帝国对阵沙俄。这场战争创下了大量的”世界第一”:

  • 第一次用电报指挥和发战报的战争——欧洲人第一次实时看到战争,相当于一场”直播的战争”
  • 第一次有照片的战争——摄影术刚发明,克里米亚战争留下了最早的战地照片
  • 第一批战地记者诞生于此
  • 第一次使用线膛枪(莱福枪)的战争
  • 第一次使用铁路运输的战争
  • 第一次有战地救护的战争——著名的南丁格尔就在克里米亚战场上首次开展护理工作,护士节因此纪念南丁格尔
  • 第一次蒸汽战舰参战
  • 天气预报图首次被应用于军事
  • Red Line“(红线)这个成语的起源——英军步兵画了一条红线对抗哥萨克骑兵冲锋

可以说,克里米亚战争奠定了现代战争的雏形,是人类历史上第一场真正意义上的现代化战争(美国南北战争是几年后的第二场)。

对俄国的战略意义

俄国历代沙皇梦寐以求一个出海口。彼得大帝找到了圣彼得堡的出海口,但那只通往北欧,容易被封锁。俄国拼命向南扩张,终于见到了黑海,打到了克里米亚。这是全体俄国人”痛哭流涕”的大事——终于可以进入地中海,接触欧洲文明的中心了。

克里米亚对俄国的军事地位极为重要:有了克里米亚,黑海舰队就有了自己的基地(塞瓦斯托波尔);没有克里米亚,就得租用乌克兰的基地,而租用的基地永远是不靠谱的——乌克兰随时可以涨价或收回。

二战中的克里米亚

二战德军第一能打的统帅曼施坦因元帅的成名作就是进攻克里米亚。他在缺乏坦克的情况下,带着德国步兵和一批罗马尼亚军队,面对拥有坦克、飞机和黑海舰队的苏军,艰苦地打下了克里米亚。围攻塞瓦斯托波尔时,德军调来了800毫米口径的超级大炮轰击要塞,创下人类战争史的纪录。曼施坦因在前线被升为元帅,从此一战成名。


二、普京——强人领导弱国

普京是什么人?用一句话概括:一个强人领导了一个弱国

俄国不管从GDP还是其他方面来看,都不能算一个强国。不能说有原子弹就算强国——朝鲜还有原子弹呢。一辆像样的汽车都制造不出来的国家(拉达已经非常古老了),不能算一个强国。

这种情况非常像一战和二战时期的德国——二战前德国也没有美国和苏联强,但有了强人领导,就敢于冒险:占领苏台德地区、吞并奥地利、入侵波兰。日本当时也不是最强国,但有强人领导,就敢冒险发动战争。

普京的冒险路径:车臣 → 格鲁吉亚(南奥塞梯)→ 克里米亚,一步步试探西方底线。


三、克里米亚的法理之争

普京的理由

克里米亚一直到1954年还是俄罗斯的。赫鲁晓夫是乌克兰人,他上台后把克里米亚划给了乌克兰——当时都在苏联这一个国家内,只是行政区划变动,谁都没当回事。就像中国解放后撤销热河省、察哈尔省一样,大家反正都在一个国家里。

而且你去问欧洲人,所有人都会说克里米亚是俄罗斯的——因为从小读到的文学作品、看到的战争英雄,都是跟俄国打仗。

普京没有提到的事实

1991年苏联解体时,克里米亚人民举行了公投——54%的多数决定跟着乌克兰走。这次公投从国际法和基本法理来说都是合理的:一个大国分裂,局势未定,由人民公投决定归属——就像德国统一时,东德解散后五个州各自公投加入德意志联邦。

一个已经在一起20多年的国家,其中一部分地区能不能随时公投决定离开?这在国际上是一个复杂问题。

各国公投的不同命运

  • 苏格兰:经过议会斗争,获得英国议会同意后公投,完全合法合理
  • 魁北克:加拿大同意公投,但约定了公投间隔年限
  • 加泰罗尼亚:西班牙不同意公投,所以全世界都不能承认
  • 科索沃:西方支持公投独立,但西班牙和罗马尼亚因自身”麻筋”没有承认

普京抓得最准的一点就是拿科索沃做类比:你们支持科索沃公投独立,为什么不能支持克里米亚?


四、各国的态度与利益博弈

德国:最值得敬佩的表态

高晓松表示最敬佩的是德国。因为德国本身是最多领土在外面的国家——东普鲁士首府柯尼斯堡(现在的加里宁格勒)在二战后割给了俄罗斯,康德就在那里出生长大。如果德国支持克里米亚回归俄罗斯的逻辑,那柯尼斯堡要不要公投回德国?波兰西部原来也是德国的领土……这将引发连锁反应。

但德国总理默克尔第一个站出来坚决反对普京吞并克里米亚,等于堵住了未来德国追讨失去领土的后路。这是非常伟大的:再次向全世界表态,承认二战以后的所有边界,不再追求”历史上的领土”。

法国:暧昧

法国经济差,俄罗斯向法国订购了两艘”西北风”级两栖攻击舰(高晓松误说为四艘),给法国造船厂提供了大量就业机会。

英国:暧昧

俄国寡头大量住在伦敦,买了切尔西足球队,洗钱成本20%归了英国银行,投资房产推高了伦敦房价。

其他欧洲国家

对俄罗斯天然气和石油的依赖,让他们不敢太”闹”。


五、日内瓦协议:像极了慕尼黑协定

2014年签署的日内瓦协议由俄罗斯、乌克兰、欧盟和美国四方达成。高晓松震惊地发现,这个协议只字未提克里米亚——等于默认归俄罗斯了。协议只要求乌克兰其他地方的非正规武装解除武装。

这和1938年的慕尼黑协定惊人地相似:当年英法默认苏台德地区归德国,希特勒答应”没有别的需求了”——然后转眼就吞并了奥地利,紧接着入侵波兰。

“历史上没有一次绥靖真的让对方消停。什么时候才真消停?兵临城下,你再往前一步我就开炮。”


六、联合国投票的微妙格局

联合国大会(非安理会,无法律效力)对克里米亚问题的投票结果:

  • 100国赞成谴责(以美欧为首)
  • 11国反对(基本是反美的国家:白俄罗斯、委内瑞拉、朝鲜、古巴等)
  • 58国弃权(最值得关注)
  • 24国缺席

弃权的58国中包括金砖四国(除俄罗斯外的中国、印度、巴西、南非),这是给西方一个明确信号:这个世界来了新玩家,不是你们几个大国商量完就完了。

美国宣布胜利:100对11。俄罗斯也宣布胜利:93国没有支持美国(58弃权+11反对+24缺席)。


七、谁是最大受益者

中国:第一大受益者

高晓松认为中国是克里米亚事件的最大受益者,理由是”国运”论:

  1. 冷战后期,西方为了拉拢中国对抗苏联,给了大量援助
  2. 苏联解体后,西方刚要对付中国,拉登来了(911),于是又需要拉拢中国一起反恐
  3. 好不容易击毙拉登,回头一看中国已经庞大极了
  4. 刚要说”不能让你再大了”,俄罗斯又冲上去了——替中国挡住了西方的注意力

俄罗斯:短期受益、长期堪忧

克里米亚”装兜里了”,但被孤立的伤害在全球化时代比一战二战时期要严重得多。


八、”俄国对中国的伤害不亚于日本”

高晓松直言:

  • 俄国从沙俄到苏联到今天,从没遵守过协议
  • 日俄战争期间双方在中国东北都没少犯罪
  • 二战末苏联把东北所有工厂、铁路全部拆走,银行黄金拉回苏联,发行废纸般的红军票
  • 华人在俄国备受歧视,在莫斯科的市场被抢了不止一两次
  • 在所有大国中,”对中国最好的就是美国”——建了清华大学、协和医院,给了大量援助,华人在美国可以当部长、州长、参议员

“不知道为什么网上的愤青天天骂美国、要跟俄国站一块。”



第二部分:事实校对

以下对节目中涉及的具体历史事实逐一查证,标注准确性。

校对1:克里米亚1950年代划归乌克兰

✅ 正确。 赫鲁晓夫于1954年2月19日签署法令,将克里米亚从俄罗斯苏维埃联邦社会主义共和国划归乌克兰苏维埃社会主义共和国。

校对2:”1991年公投54%决定跟乌克兰走”

⚠️ 部分正确,表述有误导性。 实际上1991年发生了两次公投:

  • 1991年1月20日:克里米亚自治公投,问的是”是否恢复克里米亚自治苏维埃社会主义共和国”,94.3%赞成——这次公投的本意是让克里米亚恢复为苏联的直接主体,而非留在乌克兰。
  • 1991年12月1日:乌克兰全国独立公投,克里米亚地区54.19%投赞成乌克兰独立。

“54%”这个数字来自后者。这不是克里米亚单独举行的”跟乌克兰还是跟俄罗斯”的公投,而是乌克兰全国公投在克里米亚地区的投票结果。

校对3:巴黎塞巴斯托波尔大街

✅ 正确。 巴黎确有 Boulevard de Sébastopol,长1,332米,宽30米,位于巴黎第1、2、3、4区之间,1855年以克里米亚战争中的塞瓦斯托波尔围攻命名。

校对4:克里米亚战争的多个”第一次”

更准确的说法是”最早之一”(one of the first),而非绝对第一:

说法 判定 说明
第一次用电报指挥 ⚠️ 最早之一 美墨战争(1846-48)中也使用过电报
第一次有照片 ⚠️ 最早之一 美墨战争有零星达盖尔银版照片;克里米亚是第一次大规模系统性摄影记录
第一批战地记者 ✅ 基本正确 William Howard Russell为《泰晤士报》做系统战地报道,被公认为现代战地记者先驱
第一次使用蒸汽战舰 ❌ 不准确 第一次鸦片战争(1840年)英国”复仇女神号”蒸汽船已参战;克里米亚是第一次使用铁甲蒸汽战舰
南丁格尔与战地救护 ✅ 基本正确 南丁格尔开创了系统化、专业化的现代护理体系

校对5:”Red Line源自克里米亚战争”

❌ 不准确,有两处错误:

  1. 正确名称是 “Thin Red Line”(细红线),不是 “Red Line”(红线作为”底线”的含义另有来源)
  2. 1854年巴拉克拉瓦战役中,是93苏格兰高地兵团以两列纵深抵挡俄国骑兵(非专指哥萨克骑兵),记者Russell描述为 “a thin red streak topped with steel”

校对6:”曼施坦因一辆坦克都没有”

❌ 不准确。 塞瓦斯托波尔围攻期间,第11集团军拥有约150辆坦克,编成中包括第22装甲师和约65辆三号突击炮。曼施坦因确实以步兵为主力、装甲力量相对薄弱,但说”一辆坦克都没有”是错误的。

校对7:800毫米口径大炮

✅ 正确。 指的是**”古斯塔夫重炮”(Schwerer Gustav)**,口径800毫米,是有史以来实战使用过的最大口径线膛武器。1942年在塞瓦斯托波尔围攻中发射了47发炮弹。另有三门600毫米卡尔臼炮参战。

校对8:”法国订购四艘大型登陆舰”

❌ 数量不准确。 实际是两艘(不是四艘)”西北风”级(Mistral-class)两栖攻击舰,分别命名为”符拉迪沃斯托克号”和”塞瓦斯托波尔号”。合同金额12亿欧元。

校对9:联合国投票100:11:58

✅ 完全正确。 2014年3月27日联合国大会第68/262号决议投票结果:100票赞成、11票反对、58票弃权、24国缺席。金砖四国(中印巴南)均弃权。

校对10:苏联策动外蒙古独立公投

✅ 基本正确。 1945年10月20日举行公投,官方结果100%赞成独立(487,409票赞成,0票反对),投票率98.47%。公投是在苏联压力下、中国被迫签署《中苏友好同盟条约》后进行的,100%的结果显然不可能是自由投票。

校对11:”美国援助超过中国赔款总和的数十倍”

❌ 夸大。 中国近代主要赔款(《南京条约》《马关条约》《辛丑条约》等)折合约7-13亿美元;美国二战租借法案援华约16.27亿美元加上其他援助约20-30亿美元,大约为赔款的2-4倍量级,远非”数十倍”。


校对总结

说法 判定
克里米亚1954年划归乌克兰 ✅ 正确
1991年公投54%跟乌克兰 ⚠️ 数字对,性质描述不够准确
巴黎塞巴斯托波尔大街 ✅ 正确
克里米亚战争多个”第一次” ⚠️ 多数是”最早之一”而非绝对第一
Red Line源自克里米亚 ❌ 应为Thin Red Line
曼施坦因没有坦克 ❌ 有约150辆坦克
800毫米大炮 ✅ 正确
法国卖四艘军舰 ❌ 是两艘
联合国投票数字 ✅ 完全正确
苏联策动外蒙古公投 ✅ 基本正确
美援超赔款数十倍 ❌ 实约2-4倍

第三部分:十年后验证——2014年预测 vs 2026年现实

高晓松在2014年做了若干关于未来的预测和判断。12年后,哪些被证实了?

预测1:”克里米亚这件事远远没完” ★★★★★

完全正确,甚至超出预期。

  • 2014年起,顿巴斯地区爆发武装冲突
  • 2014年7月,马航MH17被俄制导弹击落,298人遇难
  • 2022年2月24日,俄罗斯发动全面入侵乌克兰——二战以来欧洲最大规模地面战争
  • 战争造成数十万人伤亡,数百万难民

高晓松说得对:克里米亚只是一个开始。

预测2:”日内瓦协议就像慕尼黑协定” ★★★★★

慕尼黑类比精准。 日内瓦协议签字墨迹未干,顿巴斯冲突就全面升级。2015年明斯克协议同样未能约束俄罗斯。默克尔后来承认,明斯克协议在某种程度上只是为乌克兰争取了准备时间。绥靖确实没有让普京停下。

预测3:”中国是最大受益者” ★★★☆☆

部分正确,但有重大保留。

获益面:

  • 以大幅折扣购买俄罗斯石油天然气
  • 中俄关系中中方主导地位更加明确
  • GDP从2014年10.7万亿美元增长到2024年18.7万亿美元

代价面:

  • 中美关系急剧恶化,面临技术脱钩、芯片禁令
  • 被视为俄罗斯”沉默盟友”,在欧洲声誉下降
  • 经济增速从7%+降至~4.5%,房地产危机等内部问题
  • 与美国GDP差距以美元计反而从6.9万亿扩大到10.5万亿

“最大受益者”过于乐观。

预测4:”俄国长远被孤立受伤害” ★★★★☆

基本正确。

2022年后俄罗斯遭受史无前例的制裁:

  • 约3,000亿美元央行外汇储备被冻结
  • 超过1,000家跨国公司撤出
  • SWIFT切断
  • 国际刑事法院对普京发出逮捕令
  • 芬兰、瑞典加入北约(30→32国),”安全缓冲区”反而缩小

但俄罗斯经济在战时体制下并未崩溃,通过中印等国部分规避制裁,韧性超出预期。

预测5:”叙利亚反对派彻底失败” ★☆☆☆☆

严重误判。这是高晓松最大的错误。

  • 2015年俄罗斯直接军事介入后,阿萨德政权确实稳住了
  • 2016-2023年反对派退缩到伊德利卜等有限区域
  • 2024年12月——惊天逆转:反对派发动闪电攻势,12月8日推翻阿萨德政权。阿萨德出逃,反对派组建过渡政府

历史证明,”彻底”二字往往靠不住。

预测6:”等普京时代过去,中国几乎跟美国一样强大” ★★☆☆☆

与现实有较大偏差。

指标 中国(2024) 美国(2024)
GDP(美元计) 18.7万亿 29.2万亿
人均GDP ~1.3万 ~8.5万
军费 ~2,960亿 ~8,860亿

普京仍在位(2024年”连任”至2030年,修宪可执政到2036年)。中美差距以美元计反而扩大,人口老龄化、房地产危机、半导体”卡脖子”等使追赶放缓。

预测7(事实验证):法国军舰交易

交易最终被取消。 2014年9月法国暂停交付,2015年8月正式取消,退款约9.5亿欧元。两艘舰转售埃及。

预测8(事实验证):切尔西与俄国寡头

2022年后遭清算。 阿布拉莫维奇被英国制裁,切尔西以25亿英镑强制出售给美国财团。伦敦”Londongrad”时代终结,大量俄寡头资产被冻结。

预测9(事实验证):苏格兰独立公投

公投举行但独立被否决。 2014年9月18日,55%反对、45%支持。2022年英国最高法院裁定苏格兰无权自行举行第二次公投。

预测10:”不能一方用坦克一方用冰糖雪梨” ★★★★★

极具前瞻性。 2022年后西方政策发生根本转变:

  • 美国援乌超1,150亿欧元,包括防空导弹、HIMARS等
  • 德国设立1,000亿欧元特别国防基金
  • 从”只给防弹衣”升级到提供豹2坦克、F-16战斗机
  • 芬兰、瑞典加入北约

从”冰糖雪梨”转向大规模军事援助——虽然这个觉醒晚了8年。


总体评价

预测 准确度
克里米亚远远没完 ★★★★★
绥靖不会让普京停下 ★★★★★
中国是最大受益者 ★★★☆☆
俄国长远被孤立 ★★★★☆
叙利亚反对派失败 ★☆☆☆☆
中国将与美国一样强大 ★★☆☆☆
西方”冰糖雪梨”无法应对坦克 ★★★★★

高晓松在地缘政治大势上展现了相当敏锐的洞察力——对俄罗斯扩张意图和西方绥靖政策的批评极为准确。主要失误在于对叙利亚的判断(低估历史不确定性)和对中国崛起速度的过于乐观。

12年后回看,他在2014年的分析水准明显超出了当时大多数中文媒体评论者。最核心的判断——“绥靖不会带来和平,克里米亚只是开始”——被2022年的全面战争彻底证实。

从 0 到 1 复刻一个 Claude Code 这样的 Agent

dev-agent

基于 DBA 运维 Agent 的实战开发过程,结合 ReAct 论文原理,帮助你理解 Claude Code 这类 Agent 的工作本质,并具备自己动手构建一个专属 Agent 的能力。


为什么要了解 Agent

我们日常使用 Claude Code 这样的工具时,可能觉得它很神奇——丢一个问题进去,它就能帮你定位问题、修改代码、甚至操作服务器。但如果你不理解它背后的运行原理,就很难把 AI 真正融入自己的工作流。

了解 Agent 的意义有两个层面:

  1. 理解原理,提升使用效率:知道 Claude Code 怎么工作的,你就知道怎么更好地跟它协作,什么该交给它,什么需要你来把控。
  2. 自己动手,定制专属工具:当你理解了 Agent 的本质之后,你完全可以基于公司提供的 API 和模型,开发一个专属于自己业务场景的 Agent——比如一个 MySQL 运维 Agent、一个监控告警分析 Agent。

本文的目标就是:通过开发一个极简的 MySQL 运维 Agent,彻底搞懂 Claude Code 这类工具是怎么工作的。以后再看到小龙虾/Claude code/kiro 这样的 agent/智能体就犹如庖丁解牛


一、从”一问一答”到”自主解决问题”

网页聊天 vs Agent 的本质区别

以前我们在网页上使用大模型,交互方式是一问一答:你丢一个问题,模型基于训练数据吐一个答案,仅此而已。模型不知道你的服务器状况,不知道你的数据库配置,也没办法帮你执行任何命令。

Claude Code 的方式完全不同。它拿到你的问题之后,会带着一堆工具(比如执行 bash 命令、读写文件、查看 CPU 等),反复跟大模型交互:

  1. 把你的问题 + 工具列表发给大模型
  2. 大模型分析后说:”帮我执行一下 top 命令”
  3. Claude Code 执行 top,把结果塞回去
  4. 大模型看到结果,又说:”再帮我看一下磁盘”
  5. 继续执行,继续把结果塞回去
  6. 反复迭代十几轮,直到大模型说:”信息够了,我来给你最终结论”

对用户来说,你只输入了一句话,然后等着就行。 但背后 Agent 可能已经跟模型来回跑了十几轮。

2025 年 AI 为什么突然”厉害了”

很多人感觉从 2025 年下半年开始,AI 工具突然变得非常实用——能帮你写代码、部署服务、定位故障。但这里有一个常见的误解:不是模型本身变强了多少,而是 Agent 这个”客户端”变强了。

以前的模型只能基于训练数据回答问题,现在的 Agent 可以不断地给模型”喂”新信息——实时的系统状态、数据库查询结果、日志内容。模型不再是闭卷考试,而是变成了”开卷 + 有助手帮你翻书”的模式。


二、两个必须记住的基本原则

原则一:模型没有记忆

这一点非常关键,虽然很多人在各种文章中看到过,但可能理解不够深刻。

大模型是没有任何记忆的。 不管你是同一个账户、同一次会话,前后两次提问之间,模型不会记住或关联它们。你觉得它”记住了”上一轮的内容,那是因为 Agent 帮它做了一件事:把前面所有的对话历史、工具执行结果,全部打包成一个巨大的 prompt,每次都完整地发给模型。

所以你会看到,每一轮交互,Agent 发给模型的内容会越来越长——第一轮可能 1000 字,第五轮可能 5000 字,第十轮可能上万字。这就是为什么 token 消耗会这么快。

原则二:模型永远不会执行工具

大模型自己不会不能执行任何工具。它只做一件事:根据你的问题和已有信息,告诉 Agent 应该调用什么工具、参数是什么

真正去执行 SSH 命令、跑 MySQL 查询的是 Agent 程序本身。执行完之后,Agent 也不理解这些返回结果(可能成功了、可能报错了),它只是原样把结果丢给模型,让模型来判断下一步该怎么做。


三、什么是 Agent

Agent(智能体)= 让模型持续思考、持续调用外部工具、直到解决用户问题的程序。

Claude Code、OpenCode 这些都是 Agent,它们只是一个客户端工具,背后需要一个大模型来完成推理工作。

用一张图来理解:

1
2
3
4
5
6
7
8
9
10
11
12
13
       你的代码(Agent 框架)
┌──────────────────────────────────────────┐
│ │
用户 ─►│ 循环 { │
│ 1. 把问题 + 工具列表 发给 LLM │
│ 2. LLM 返回: 我要调用 XX 工具 │
│ 3. Agent 执行工具,拿到结果 │
│ 4. 把结果喂回给 LLM │
│ 5. LLM 判断:信息够了吗? │
│ - 不够 → 回到 1 │
│ - 够了 → 输出 Final Answer │
│ } │
└──────────────────────────────────────────┘

核心区别:

  • 普通 LLM 调用:一问一答,模型只能靠训练数据回答
  • Agent 模式:模型可以主动调工具获取实时信息,多轮推理后给出答案

这里还有一个细节值得注意:Agent 启动时会把所有工具的定义(名称、用途、参数说明)都一次性发给模型。比如你配了 GitHub、MCP、bash 等几十个工具,不管你的问题跟哪个工具有没有关系,全部都会带上。这就是为什么你一打开 Claude Code,上下文消耗就已经很高了——因为光工具定义就占了几万字。


四、ReAct:Agent 的核心工作模式

ReAct(Reasoning + Acting)是目前 Agent 最主流的工作模式,来自 2022 年发表的论文 ReAct: Synergizing Reasoning and Acting in Language Models

核心循环

1
2
3
4
5
6
7
8
9
10
┌─────────────────────────────────────────────────────┐
│ ReAct 循环 │
│ │
│ Thought ──► Action ──► Observation ──► Thought │
│ (思考) (行动) (观察) (再思考) │
│ │ │ │
│ └─────── 信息不够,继续循环 ◄──────────┘ │
│ │
│ 信息够了 ──► Final Answer │
└─────────────────────────────────────────────────────┘

核心理念是:大模型先思考(Thought)当前需要什么信息,然后决定一个行动(Action)让 Agent 去执行,Agent 执行后返回观察结果(Observation),模型再根据新信息继续思考。这个循环不需要你写任何 if-else 逻辑——模型自己决定调什么工具、调几次、什么时候停。

以前我们写自动化程序,靠的是模板匹配和条件判断,需要穷举各种场景,所以做起来很麻烦、动不动就要改。现在 Agent 把所有判断逻辑交给了模型,模型来决定下一步做什么。

实际运行示例

以”检查 MySQL 主从复制状态”为例,Agent 的实际思考过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[LLM #1]
Thought: 需要检查主从状态,先看 SHOW SLAVE STATUS
Action: mysql_query
Action Input: {"query": "SHOW SLAVE STATUS"}
→ 工具返回: [无结果集](说明不是从库)

[LLM #2]
Thought: 不是从库,看看是不是主库
Action: mysql_query
Action Input: {"query": "SHOW MASTER STATUS"}
→ 工具返回: mysql-bin.000007 | 180681919 | ... | GTID:1-1833162

[LLM #3]
Thought: 是主库。再看有没有从库连上来
Action: mysql_query
Action Input: {"query": "SHOW SLAVE HOSTS"}
→ 工具返回: [无结果集](没有从库连接)

[LLM #4]
Thought: 主库正常但无从库,再查半同步状态和错误日志
Action: ssh_command
Action Input: {"command": "tail -50 /data0/mysql_3306/log/error.log"}
...

[LLM #6]
Thought: I now know the final answer
Final Answer: ## 诊断报告 ...

在这个过程中,模型自己判断了:先查从库状态 → 发现不是从库 → 转查主库状态 → 确认是主库 → 检查从库连接 → 查日志。你完全不需要预设这些逻辑,模型根据每一步的返回自行决策。


五、Agent 开发三要素

1
2
3
4
5
6
7
8
9
┌────────────────────────────────────────────┐
│ Agent = LLM + Tools + Prompt │
│ │
│ ┌─────────┐ ┌─────────┐ ┌───────────┐ │
│ │ LLM │ │ Tools │ │ Prompt │ │
│ │ 大模型 │ │ 工具集 │ │ 角色定义 │ │
│ │ (大脑) │ │ (手脚) │ │ (指令) │ │
│ └─────────┘ └─────────┘ └───────────┘ │
└────────────────────────────────────────────┘
要素 你需要做什么 本项目示例
LLM 选模型、配 API 地址 Claude Sonnet 4.5 via API 网关
Tools 写 Python 函数,让模型能调用 ssh_command / mysql_query / write_file
Prompt 告诉模型它是谁、能做什么 “你是 DBA 专家,只读诊断…”

80% 的开发工作在写 Tools。 LLM 和 Prompt 通常很快就定了。


六、Step by Step 开发流程

Step 1:明确场景,定义工具边界

先回答三个问题:

  • Agent 要解决什么问题?→ MySQL/Linux 远程只读诊断
  • 需要哪些工具?→ SSH 执行命令、MySQL 查询、写报告文件
  • 安全边界是什么?→ 只读,不能执行写操作
1
2
3
4
场景:DBA 日常诊断
├── 需要 SSH 执行命令 → ssh_command 工具
├── 需要查 MySQL → mysql_query 工具
└── 需要保存报告 → write_file 工具

工具代码中的注释(description)非常重要——模型就是靠这些描述来决定什么时候调用哪个工具、传什么参数。这些注释不是给人看的,是给模型看的。

为了安全起见,我们还需要给工具加上黑白名单,比如 MySQL 工具只允许 SHOWSELECT 等只读操作,禁止 DROPDELETETRUNCATE 等危险命令。

Step 2:搭项目结构

1
2
3
mkdir -p ~/q/agent/tools
touch ~/q/agent/{config.yaml,main.py,crew.py,requirements.txt}
touch ~/q/agent/tools/{__init__.py,ssh_tool.py,mysql_tool.py,write_file_tool.py}

Step 3:写工具(核心工作量)

每个工具就是一个 Python 类,继承 BaseTool,实现 _run 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from crewai.tools import BaseTool
from pydantic import BaseModel, Field

class MySQLQueryInput(BaseModel):
query: str = Field(description="要执行的 SQL 查询语句")

class MySQLQueryTool(BaseTool):
name: str = "mysql_query"
description: str = "执行 MySQL 只读查询..." # 模型靠这段话决定什么时候用这个工具
args_schema: Type[BaseModel] = MySQLQueryInput

def _run(self, query):
# 1. 安全检查(只读白名单)
# 2. 执行查询
# 3. 返回格式化结果(字符串)
return "结果文本"

工具开发要点:

  • description 写清楚——模型靠它判断何时调用
  • _run 返回纯文本——模型只能处理文本
  • 做好安全拦截——模型可能尝试危险操作
  • 加超时控制——防止 tail -f 等命令无限阻塞

Step 4:配置 LLM 连接

1
2
3
4
5
# config.yaml
llm:
model: "openai/claude-sonnet-4-5-20250929"
base_url: "https://your-api-gateway/v1"
api_key: "sk-xxx"
1
2
3
4
5
6
from crewai import LLM
llm = LLM(
model="openai/claude-sonnet-4-5-20250929",
base_url="https://your-api-gateway/v1",
api_key="sk-xxx"
)

注意:如果 API 网关是 OpenAI 兼容协议,模型名需要加 openai/ 前缀让 litellm 走 OpenAI 通道。

Step 5:组装 Agent

1
2
3
4
5
6
7
8
9
10
from crewai import Agent, Task, Crew

agent = Agent(
role="DBA 运维专家",
goal="诊断 MySQL 和 Linux 运行状况",
backstory="你是资深 DBA,精通 MySQL 5.7/8.0...",
tools=[ssh_tool, mysql_tool, write_tool],
llm=llm,
verbose=True,
)

Step 6:跑起来

1
2
3
4
5
6
7
8
task = Task(
description="用户问题: %s" % user_input,
expected_output="诊断结果和建议(中文)",
agent=agent,
)
crew = Crew(agents=[agent], tasks=[task])
result = crew.kickoff()
print(result)

七、实战:一次完整的诊断过程

我们给 Agent 一个实际任务:”分析 SQL 响应时间以及内存资源”。

Agent 开始工作后,debug 模式下可以看到完整的交互过程:

第 1 轮:模型收到问题,决定先查慢查询配置

1
2
Action: mysql_query → SHOW GLOBAL VARIABLES LIKE '%slow%'
Observation: slow_query_log=ON, long_query_time=0.5

第 2 轮:模型知道了慢查询阈值是 0.5 秒,继续查慢查询数量

1
2
Action: mysql_query → SHOW GLOBAL STATUS LIKE 'Slow_queries'
Observation: Slow_queries=21

第 3 - 8 轮:模型继续查询 QPS、线程状态、锁信息、查询缓存…

第 9 - 12 轮:模型觉得还需要看系统资源,自动通过 SSH 执行 topfree 等命令

第 18 轮:模型终于认为信息足够了,输出 Final Answer:

  • 慢查询数量:21 条,阈值 0.5 秒
  • QPS 统计和慢查询占比
  • 锁等待分析
  • 内存使用状况
  • 综合评分和优化建议

整个过程中,你只输入了一行命令,但 Agent 已经自动完成了 18 轮诊断。 这就是 Agent 的魅力所在。


八、踩坑记录

实际开发中遇到的问题和解决方案(这部分经验非常重要,第一次把代码写出来能直接跑通的概率几乎为零):

问题 原因 解决
MySQL root 连接被拒 root 只允许 socket 连接 改为 SSH + mysql CLI 方式
模型报 prefill 错误 部分后端不支持 assistant prefill 换用支持的模型版本
找不到 litellm openai/ 前缀需要 litellm 做路由 pip install 'litellm<1.60'
chromadb 报 sqlite3 版本太低 系统自带 sqlite 版本不够 pip install pysqlite3-binary + monkey-patch
numpy 不兼容 CPU numpy 2.x 需要新指令集 pip install 'numpy<2'
tail -f 导致工具永远不返回 paramiko recv_exit_status() 无限阻塞 改用 channel 级非阻塞读取 + deadline 超时
SHOW SLAVE STATUS\G 报错 \G 是 mysql CLI 交互命令,batch 模式不支持 模型自动修正去掉 \G 重试
debug 日志不输出 框架覆盖了自定义 logger monkey-patch 保护自定义 logger

关键经验:模型第一次生成的代码几乎不可能直接跑通。 你需要提供一个真实的调试环境(一台可以 SSH 的机器、一个可以连的 MySQL 实例),让 AI 在真实环境中反复调试。这个调试和验证的过程,才是开发 Agent 中最关键的一步。你需要做的是给 AI 搭好舞台——准备好机器、配好免密、提供连接信息,然后让它自己去试、去修、去迭代。


九、调试技巧

加 –debug 看完整的 LLM 交互

1
python3 main.py --host 10.0.0.1 --debug "检查MySQL版本"

输出每次发给模型的完整 prompt 和模型的完整回复,能清楚看到:

  • 模型在”想”什么(Thought)
  • 模型决定调什么工具(Action)
  • 工具返回了什么(Observation)
  • Token 消耗量

先单独测试工具

不要一上来就跑完整 Agent,先验证每个工具独立可用:

1
2
3
4
5
6
7
from tools.ssh_tool import SSHCommandTool
ssh = SSHCommandTool(host="10.0.0.1", cmd_timeout=10)
print(ssh._run("uptime"))

from tools.mysql_tool import MySQLQueryTool
mysql = MySQLQueryTool(host="10.0.0.1", mysql_password="xxx")
print(mysql._run("SELECT VERSION()"))

关键公式

1
Agent 效果 = 模型能力 × 工具质量 × Prompt 清晰度
  • 模型不够强 → 换更大的模型
  • 工具返回乱码 → 格式化输出
  • 模型不知道用哪个工具 → 改 description
  • 模型反复出错重试 → 加 –debug 看 prompt,调 backstory

十、进阶思考:从个人效率到团队赋能

第一阶段:用好现有工具

把 Claude Code 这样的工具融入日常工作,让以前花两三个小时的任务,现在 5 分钟搞定。这是最基础的提效。

第二阶段:定制专属 Agent

结合自己的业务场景,开发专属 Agent。比如 DBA 运维 Agent,可以进一步接入更多数据源:

  • 监控数据:接入 Prometheus,让 Agent 能查看历史指标趋势
  • 日志平台:接入 SLS 等日志服务,让 Agent 能自动拉取和分析错误日志
  • 元数据库:接入 DBA 平台的元数据,让 Agent 通过实例名自动查到机器、端口、配置
  • 即时通讯:接入飞书、Telegram 等,让团队成员直接在群里向 Agent 提问

工具越丰富,Agent 能做的事情就越多。 你最了解自己的日常工作,最清楚哪些环节可以让 Agent 来接手。

第三阶段:理解原理,看透产品

当你真正理解了 Agent 的运行原理之后,再去看市面上各种 AI 产品,你会发现:

  • 它们的核心原理都是一样的——ReAct 循环 + 工具调用
  • 产品之间的差异主要在于:提供了哪些工具、交互界面做成什么样、安全策略怎么设计
  • 有些产品把命令行工具做成了白屏化的界面,降低了使用门槛,所以对非技术人员更友好
  • 有些产品默认不做授权确认,用起来更”丝滑”,但在生产环境需要注意安全风险

理解了本质,你就能站在更高的视角去评估和选择工具,而不是被产品的外表所迷惑。


完整提示词参考

如果你想自己复刻这个 MySQL 运维 Agent,只需要将以下提示词依次交给 Claude Code:

起始提示词(创建项目):

1
2
3
4
5
我想基于 CrewAI 来实现一个我自己的 DBA 运维 agent,~/q/agent/
我提供 ip+端口+账户+密码,agent 能通过 ssh 访问 ip 所在的机器,
也能够通过 mysql client 拉取所要的信息(只能是读,不能对实例做任何修改),
请帮我实现这样一个 agent,用 python 代码,可以提供一个配置文件配置好默认的账号+密码/端口;
我想在控制台完整输出 agent 发给 LLM 的提示词,以及完整的 LLM 返回内容,以便我学习

调试提示词(非常关键):

1
2
3
4
<目标IP> 是我的部署机器,ssh root 免密了,请帮我部署并调试,
需要被调试的 mysql 机器是 <MySQL IP> <端口>
mysql -uroot -S /data0/mysql_${port}/data/mysql.sock -p<密码>
从部署机器 ssh root@<MySQL IP> 也是免密了

修复 Bug 示例:

1
2
请帮我修复当执行 ssh_command 比如 tail -100 /data0/mysql_3306/log/slow-queries.log
因为没有足够多 slow query 的产生导致 tool 一直不返回,请增加超时时间比如 10 秒(可配置)

增加工具示例:

1
2
非常好,现在帮我加一个写文件的 tool,然后可以将大模型的输出写入到某个文件中;
同时帮我生成一份 README.md 里面要有 --debug 时输出的解读

项目架构

1
2
3
4
5
用户输入 → main.py (CLI) → crew.py (CrewAI Agent)
├── SSHCommandTool (paramiko → 目标机)
└── MySQLQueryTool (paramiko SSH → mysql CLI → unix socket)

LLM: Claude Sonnet 4.5 via API 网关

使用方式:

1
2
3
4
5
6
7
8
9
10
cd /data0/scripts/agent

# 交互式模式
python3 main.py --host <目标IP> --mysql-port 3306

# 单次命令
python3 main.py --host <目标IP> --mysql-port 3306 "检查主从复制状态"

# 调试模式(查看完整 LLM 交互)
python3 main.py --host <目标IP> --mysql-port 3306 --debug "分析慢查询"

总结

你以为的 实际上的
大模型自己变强了 Agent 不断喂信息让模型”开卷考试”
模型会记住上下文 每次都把完整历史重新发一遍
模型会执行命令 模型只返回”要执行什么”,Agent 去执行
开发 Agent 很难 核心就是写好工具 + 描述清楚 + 调试验证
代码必须人写 提示词 → AI 生成 → 人验证迭代

一句话概括:Agent 就是一个死循环,把你的问题和工具带给模型,模型指挥 Agent 执行,执行结果再喂回模型,直到模型说”够了,这是最终答案”。

理解了这个本质,你就理解了 Claude Code、以及市面上所有 AI Agent 产品的工作原理。

TCP 网络性能排查实战:两个经典案例的深度学习总结

概述

本文总结了两个真实的 TCP 网络性能问题排查案例,涉及 Kafka 消息队列在跨机房和同机房场景下的延迟问题。两个案例从不同角度揭示了 TCP 缓冲区、拥塞控制、内核参数对应用性能的深远影响。


案例一:跨机房 Kafka 消费延迟高达 10 分钟

问题描述

每天上午 9:30 开盘后,位于 Region-B 的 Kafka 消费者从 Region-A 的 Kafka Broker 拉取消息时,延迟不断增高到 10 多分钟,持续数小时才恢复。而 Region-A 同机房的消费者拉取同一 Topic 完全正常。

排查过程

整个排查经历了多个阶段,逐步逼近根因:

阶段一:排除基础设施问题

  • Broker/Client 进程状态、机器资源(CPU/内存/磁盘)均正常
  • 网络带宽充足,丢包率正常,wget 测试带宽足够
  • 初步怀疑方向:网络链路本身

阶段二:发现拥塞窗口异常(TCP 层面)

在客户端机器上抓包分析,发现关键线索:

1
2
3
4
5
6
# 查看 TCP 连接的拥塞窗口
ss -itmpn dst "x.x.x.x"

# 关键输出(问题连接)
cwnd:2 ssthresh:2 ← 拥塞窗口极小,只有 2 个 MSS
send 170.0Kbps ← 发送速率极低

RTT 约 130ms,拥塞窗口只有 2(约 2.9KB),理论吞吐量:2 × 1448 / 0.13 ≈ 22KB/s,远不够传输开盘时的行情数据。

尝试通过 wget 大文件把 ssthresh 撑大,然后重启客户端新建连接,问题暂时缓解。但第二天又复发。

阶段三:发现内核虚假重传(深入内核层面)

通过 Wireshark 分析抓包文件,发现一个异常现象:

Broker 发送响应后,如果 10ms 内没收到 ACK,就触发重传。而正常的 RTO 应该是 200ms+。

这种 10ms 的重传远低于 RTO,也不是快速重传或 TLP。最终定位到 Linux 3.10 内核的 tcp_early_retrans 参数:

1
2
3
4
5
6
# 查看当前值
sysctl net.ipv4.tcp_early_retrans
# 输出: net.ipv4.tcp_early_retrans = 3

# 这是 3.10 内核 backport 新版本 early retrans 功能时引入的 bug
# 导致大量虚假重传,进而让拥塞控制算法误判网络拥塞,不断缩小 cwnd

修复方法:

1
sysctl -w net.ipv4.tcp_early_retrans=0

修改后,全网 TCP 重传率从万分之 5 降到正常水平。

阶段四:发现 Send Buffer 限制

解决虚假重传后,抓包发现新的瓶颈:

Broker 发送一批数据包后,在途字节(Bytes in flight)达到约 50KB 就停止发送,等一个 RTT(~130ms)收到 ACK 后才继续。

原因:Kafka Broker 默认配置 socket.send.buffer.bytes=102400(100KB),内核实际分配约一半(~50KB),限制了发送窗口。

阶段五:定位根因 — 客户端接收 Buffer

将 Broker Send Buffer 限制去掉后仍然不行。最终在客户端日志中找到关键配置:

1
receive.buffer.bytes = 65536    ← Kafka 客户端默认只有 64KB 接收缓冲区

TCP 三次握手时,客户端根据 receive.buffer.bytes 通告接收窗口(rwnd)。64KB 的 rwnd 意味着:

1
最大吞吐量 = rwnd / RTT = 64KB / 130ms ≈ 490KB/s

而开盘高峰期需要数十 MB/s 的吞吐量,64KB 的接收窗口成为致命瓶颈。

根因与解决方案

根因:Kafka 客户端默认接收缓冲区 64KB 太小,叠加跨机房 130ms 的 RTT,导致 TCP 吞吐量被严重限制。

解决方案

1
2
3
4
5
6
7
8
9
# Kafka Consumer 配置
receive.buffer.bytes = 2097152 # 从 64KB 调整到 2MB(或设为 -1 让 OS 自动调优)

# Kafka Broker 配置
socket.send.buffer.bytes = -1 # 去掉 100KB 限制,让 OS 自动调优
socket.receive.buffer.bytes = -1

# Linux 内核参数(3.10 内核)
net.ipv4.tcp_early_retrans = 0 # 关闭有 bug 的 early retrans

效果:传输延迟从 10-60 分钟降低到 1-4 秒,性能提升约 1000 倍。

调整前后的 Wireshark 抓包对比:

1
2
调整前:485KB 数据需要 8 个 RTT(8 × 130ms = 1040ms)分批传输
调整后:485KB 数据在 3ms 内一次性传输完毕

案例二:同机房 TCP 订阅客户端异常缓慢

问题描述

同机房 4 台机器部署了相同的行情订阅服务,其中 1 台拉取行情数据异常缓慢。

排查过程

第一步:抓包发现 TCP Zero Window

在客户端抓包,发现大量 TCP Zero Window 通告——客户端在告诉服务端”我的接收缓冲区满了,别再发了”。

第二步:确认 Recv Buffer 堆满

1
2
netstat -ant | grep <server_port>
# 发现 Recv-Q 持续满载

第三步:发现 CPU 异常

1
2
top -Hp <java_pid>
# 发现一个线程 CPU 持续接近 100%,像死循环

第四步:定位代码问题

1
2
3
4
5
# 用 top 看到的线程 ID(十进制)转十六进制
printf '%x\n' <thread_id>

# 在 jstack 中查找对应线程堆栈
jstack <java_pid> | grep -A 30 <hex_thread_id>

找到问题代码:一个 for 循环中调用 read(),每次只读很少的数据(参数配置过小),导致:

  1. 应用层读取速度跟不上网络数据到达速度
  2. OS TCP Recv Buffer 被填满
  3. TCP 通告 Zero Window,服务端停止发送
  4. 该线程 CPU 100%(不停地循环读取微量数据)

根因与解决方案

根因:业务代码中 read() 的缓冲区参数配置过小,导致应用层消费速度远低于网络数据到达速度,TCP Recv Buffer 堆满触发 Zero Window。

解决方案:修复代码,增大 read() 的缓冲区大小。

效果

  • 网络吞吐量恢复正常(流量曲线从”平台”变为正常波动)
  • CPU 使用率从 40% 降到 20%

两个案例的关联与对比

维度 案例一(跨机房延迟) 案例二(同机房 Zero Window)
场景 跨机房,RTT ~130ms 同机房,RTT <1ms
表现 消费延迟 10+ 分钟 TCP Zero Window,数据停滞
瓶颈层 TCP 接收窗口 + 内核参数 应用层读取速度
根因 Kafka 默认 receive buffer 64KB 太小 业务代码 read() 缓冲区配置过小
为什么同机房没问题 RTT 小,64KB 窗口也够用 其他机器代码/配置正常
解决方式 调大 buffer + 修复内核参数 修复业务代码

两个案例本质上都是 TCP 接收端处理能力不足 导致发送端被限速:

1
2
案例一:接收窗口太小 → 发送端每个 RTT 只能发 64KB → 跨机房 RTT 大放大了问题
案例二:应用层读取太慢 → Recv Buffer 堆满 → Zero Window → 发送端完全停止

TCP 缓冲区与窗口的核心原理

1
2
3
4
5
6
7
8
9
10
11
发送方应用 write()

Send Buffer (sk_sndbuf)
↓ 受发送窗口限制
发送窗口 = min(拥塞窗口 cwnd, 接收窗口 rwnd)

网络传输 (in-flight data)

Receive Buffer (sk_rcvbuf)
↓ 通告 rwnd = buffer_size - 已占用空间
接收方应用 read()

关键关系:

  • 接收窗口 rwnd:由接收端 Recv Buffer 剩余空间决定,通过 ACK 通告给发送端
  • 拥塞窗口 cwnd:由发送端拥塞控制算法(如 CUBIC)动态调整
  • 发送窗口:取 rwnd 和 cwnd 的较小值
  • 最大吞吐量min(rwnd, cwnd) / RTT

为什么 RTT 大时 Buffer 小的问题会被放大?

1
2
同机房 (RTT=1ms):   吞吐量 = 64KB / 1ms   = 64MB/s   ← 够用
跨机房 (RTT=130ms): 吞吐量 = 64KB / 130ms = 490KB/s ← 严重不足

这就是案例一中”同机房正常、跨机房延迟”的根本原因。


关键排查命令速查

TCP 连接状态分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 查看 TCP 连接详细信息(拥塞窗口、RTT、重传等)
ss -itmpn dst "x.x.x.x"

# 关键字段解读
# cwnd:10 拥塞窗口(MSS 数量)
# ssthresh:2 慢启动阈值
# rtt:130/0.5 RTT 均值/方差(ms)
# rto:330 重传超时(ms)
# send 850Kbps 当前发送速率
# unacked:38 未确认的包数量
# retrans:0/3 当前重传/累计重传

# 查看 TCP 缓存指标
ip tcp_metrics show | grep <ip>

# 查看连接队列
netstat -ant | grep <port>
# Recv-Q: 接收队列(应用未读取的数据)
# Send-Q: 发送队列(已发送未确认的数据)

网络重传监控

1
2
3
4
5
# 实时观察 TCP 重传
watch -n 1 'nstat -az | grep TcpRetransSegs'

# 检查 early retrans 参数(3.10 内核)
sysctl net.ipv4.tcp_early_retrans

抓包分析

1
2
3
4
5
6
7
# 抓取指定端口的包
tcpdump -i eth0 port 9092 -w capture.pcap

# Wireshark 中关键过滤器
tcp.analysis.zero_window # Zero Window 事件
tcp.analysis.retransmission # 重传包
tcp.analysis.bytes_in_flight # 在途字节数

Java 应用排查

1
2
3
4
5
6
7
8
# 查看 Java 进程中各线程 CPU 使用
top -Hp <java_pid>

# 线程 ID 转十六进制
printf '%x\n' <thread_id>

# 导出线程堆栈并查找
jstack <java_pid> | grep -A 30 <hex_thread_id>

经验教训

1. 不要信任中间件的默认配置

Kafka 客户端默认 receive.buffer.bytes=64KB、Broker 默认 socket.send.buffer.bytes=100KB,这些值在同机房低延迟环境下够用,但在跨机房高 RTT 场景下会成为致命瓶颈。

建议:跨机房部署时,将 buffer 相关配置设为 -1(让 OS 自动调优),或根据 BDP = 带宽 × RTT 计算合理值。

2. 内核参数可能是隐藏的定时炸弹

Linux 3.10 内核的 tcp_early_retrans=3 导致大量虚假重传,拉高全网重传率到万分之 5,掩盖了真实的网络问题。这种问题平时不显现,只在高负载时爆发。

建议:关注内核版本差异,定期检查 TCP 重传率是否异常。

3. 学会用 Wireshark 做对比分析

排查网络问题最有效的方法是:抓一份有问题的包、一份正常的包,在 Wireshark 中对比分析。关注:

  • Bytes in flight 的变化曲线
  • ACK 之间的间隔(是否有等待平台)
  • 是否有异常重传

4. 应用层的 Bug 也会表现为网络问题

案例二中,业务代码 read() 缓冲区配置过小导致 TCP Zero Window,表面看是”网络问题”,实际是应用层 Bug。排查时不要只盯着网络层,要结合 top -Hp + jstack 看应用层行为。

5. 理解 BDP(带宽延迟积)

1
BDP = 带宽 × RTT

这是网络管道中能容纳的最大数据量。TCP Buffer 至少要等于 BDP 才能充分利用带宽。例如:

1
2
3
4
5
带宽 100Mbps, RTT 130ms:
BDP = 100Mbps × 0.13s = 13Mb = 1.6MB

→ TCP Buffer 至少需要 1.6MB 才能跑满带宽
→ 64KB 的 Buffer 只能利用 64KB/1.6MB ≈ 4% 的带宽

6. 排查要有层次感

1
2
3
4
5
6
7
8
9
应用层 → 是否有代码 Bug、配置错误

中间件层 → Kafka/MySQL 等的 Buffer 配置是否合理

TCP 层 → 拥塞窗口、接收窗口、重传情况

内核层 → tcp_early_retrans 等内核参数

网络层 → 带宽、丢包、RTT

从上到下逐层排查,每一层都可能是瓶颈。

网络知识学习方法与技巧

一、学习路径:从理论到实战

1. 系统化学习框架

plantegg 博客提供了三大核心系列,构建完整的网络知识体系:

  • Understanding TCP 系列 - TCP 协议全方位解析
  • Understanding Network 系列 - 网络基础概念深入
  • Understanding Load Balancing 系列 - 负载均衡策略与实践

学习建议:不要孤立学习理论,而是将理论与生产案例结合。plantegg 的内容强调从实际问题出发,通过案例理解原理。

2. 问题驱动的学习方法

plantegg 博客的核心特点是问题导向

  • 从生产环境的真实故障入手
  • 通过排查过程学习工具使用
  • 在解决问题中理解底层原理
  • 积累可复用的诊断方法论

实践路径

  1. 遇到问题 → 2. 抓包分析 → 3. 定位根因 → 4. 理解原理 → 5. 总结方法

二、核心知识领域

1. TCP 连接管理

连接队列监控

理解 TCP 连接的两个关键队列:

  • SYN 队列(半连接队列):存储 SYN_RECV 状态的连接
  • Accept 队列(全连接队列):存储 ESTABLISHED 但未被 accept() 的连接

实时监控工具

1
2
# 使用 bpftrace 工具包中的 tcpaccept
tcpaccept

输出示例解读:

  • PID/COMM:接受连接的进程信息
  • RADDR/RPORT:远程地址和端口
  • LADDR/LPORT:本地地址和端口
  • Accept Queue:当前队列大小/最大队列大小

关键洞察

  • 队列满时会导致连接被丢弃(SYN 丢弃或 ACK 丢弃)
  • 通过监控队列状态可以提前发现性能瓶颈
  • 队列大小受 somaxconn 和应用层 backlog 参数影响

Socket 选项优化

SO_REUSEPORT - 多进程负载均衡:

1
2
3
4
int listenfd;
int reuse = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEPORT,
(const void *)&reuse, sizeof(int));

核心价值

  • 允许多个进程绑定同一 IP:Port
  • 内核通过哈希分发连接,实现负载均衡
  • 解决”惊群效应”(thundering herd)
  • 提升多核 CPU 利用率

适用场景

  • Nginx 多 worker 进程同时监听
  • 高并发服务器提升连接接收能力
  • 避免单一监听 socket 成为瓶颈

SO_REUSEADDR vs SO_REUSEPORT

  • SO_REUSEADDR:允许 TIME_WAIT 状态下快速重启服务
  • SO_REUSEPORT:多进程负载均衡,性能优化

2. Buffer 与内存管理

Socket 内存信息解读

使用 ss -m 查看 socket 内存状态:

1
ss -m

输出字段含义:

  • r:接收缓冲区已分配内存
  • rb:接收缓冲区大小(sk_rcvbuf)
  • t:发送缓冲区已分配内存
  • tb:发送缓冲区大小(sk_sndbuf)
  • f:forward allocation(预分配内存)
  • w:发送队列中的数据
  • o:选项内存(如 TCP options)
  • bl:backlog 队列长度
  • d:丢弃的包数量

内核实现(参考):

1
2
3
4
5
6
7
8
9
10
11
12
void sk_get_meminfo(const struct sock *sk, u32 *mem)
{
mem[SK_MEMINFO_RMEM_ALLOC] = sk_rmem_alloc_get(sk);
mem[SK_MEMINFO_RCVBUF] = sk->sk_rcvbuf;
mem[SK_MEMINFO_WMEM_ALLOC] = sk_wmem_alloc_get(sk);
mem[SK_MEMINFO_SNDBUF] = sk->sk_sndbuf;
mem[SK_MEMINFO_FWD_ALLOC] = sk->sk_forward_alloc;
mem[SK_MEMINFO_WMEM_QUEUED] = sk->sk_wmem_queued;
mem[SK_MEMINFO_OPTMEM] = atomic_read(&sk->sk_omem_alloc);
mem[SK_MEMINFO_BACKLOG] = sk->sk_backlog.len;
mem[SK_MEMINFO_DROPS] = atomic_read(&sk->sk_drops);
}

诊断技巧

  • r 接近 rb:接收缓冲区快满,应用层消费慢
  • t 接近 tb:发送缓冲区快满,网络发送慢或对端接收慢
  • d 持续增长:socket 丢包,需检查缓冲区大小和应用处理速度
  • bl 持续非零:backlog 队列有积压,应用 accept() 速度慢

内核参数调优

关键参数

1
2
3
4
5
# 查看网络软中断预算
sysctl -a | grep net.core.netdev_budget

# 临时调整(重启失效)
sysctl -w net.core.netdev_budget=400

常见调优参数

  • net.core.netdev_budget:单次软中断处理的最大包数
  • net.core.somaxconn:listen() 的最大 backlog
  • net.ipv4.tcp_rmem:TCP 接收缓冲区(min/default/max)
  • net.ipv4.tcp_wmem:TCP 发送缓冲区(min/default/max)
  • net.ipv4.tcp_max_syn_backlog:SYN 队列最大长度

调优原则

  • 先监控,后调优(避免盲目调整)
  • 理解参数含义和影响范围
  • 在测试环境验证效果
  • 记录调优前后的性能指标

3. TCP 性能指标

关键性能指标

RTT(Round-Trip Time)

  • 衡量网络延迟的核心指标
  • 影响 TCP 吞吐量:Throughput ≈ Window Size / RTT
  • 通过 tcp.analysis.ack_rtt 字段分析

重传率

  • 反映网络质量和拥塞情况
  • 类型:超时重传、快速重传
  • 高重传率可能原因:网络丢包、接收端处理慢、拥塞

窗口大小

  • 接收窗口(rwnd):接收端通告的可用缓冲区
  • 拥塞窗口(cwnd):发送端的拥塞控制窗口
  • 实际窗口 = min(rwnd, cwnd)

丢包与重传分析

  • tcp.analysis.retransmission:重传包
  • tcp.analysis.fast_retransmission:快速重传
  • tcp.analysis.duplicate_ack:重复 ACK
  • tcp.analysis.lost_segment:丢失的段

TCP 选项优化

TCP_CORK

1
2
3
当设置 TCP_CORK 时,会将非满帧排队,直到清除该选项。
适用场景:先发送 HTTP 头部,再用 sendfile() 发送数据体。
TCP_CORK 可与 TCP_NODELAY 同时设置,且优先级更高。

应用场景

  • 减少小包发送,提升网络效率
  • 适合批量数据传输
  • sendfile() 配合使用

4. 负载均衡与高可用

SO_REUSEPORT 实现负载均衡

工作原理

  • 内核通过哈希算法分发连接到不同进程
  • 每个进程独立 listen() 和 accept()
  • 避免进程间锁竞争

性能提升

  • 多核 CPU 并行处理连接
  • 消除单一监听 socket 瓶颈
  • 提升高并发场景下的吞吐量

Nginx 配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
worker_processes 4;
worker_cpu_affinity 00000000000000000000000000001111;

events {
use epoll;
accept_mutex off; # 关闭 accept 互斥锁
worker_connections 102400;
}

http {
access_log off;
sendfile on;
sendfile_max_chunk 512k;
tcp_nopush on;
keepalive_timeout 60;
keepalive_requests 100000000000;

# 短连接 RPS 优化
open_file_cache max=10240000 inactive=60s;
open_file_cache_valid 80s;
open_file_cache_min_uses 1;
}

优化要点

  • accept_mutex off:配合 SO_REUSEPORT 使用
  • sendfile:零拷贝技术,减少 CPU 消耗
  • tcp_nopush:与 TCP_CORK 类似,批量发送
  • open_file_cache:缓存文件描述符,提升短连接性能

三、实战诊断方法论

1. 性能问题排查流程

第一步:确定问题现象

  • 延迟高?吞吐量低?连接失败?
  • 收集监控数据:CPU、内存、网络流量、连接数

第二步:抓包分析

  • 使用 tcpdump 捕获流量
  • 用 tshark/Wireshark 分析关键指标

第三步:定位瓶颈

  • 网络层:RTT、丢包率、重传率
  • 传输层:窗口大小、队列状态
  • 应用层:响应时间、处理速度

第四步:验证假设

  • 调整参数或代码
  • 对比调整前后的性能数据
  • 确认问题是否解决

2. 常见问题模式

模式 1:高延迟

可能原因

  • 网络 RTT 高(物理距离、路由跳数)
  • 应用层处理慢(数据库查询、计算密集)
  • 队列积压(accept 队列、backlog 队列)

诊断方法

  • 分析 tcp.analysis.ack_rtt 确定网络延迟
  • 分析应用层响应时间(如 MySQL query time)
  • 检查队列状态(tcpaccept、ss -l)

模式 2:高重传率

可能原因

  • 网络丢包(链路质量差、拥塞)
  • 接收端处理慢(窗口满、应用消费慢)
  • 发送端突发流量(超过网络容量)

诊断方法

  • 统计重传类型(超时 vs 快速重传)
  • 检查窗口大小变化
  • 分析丢包位置(发送端、中间网络、接收端)

模式 3:连接失败

可能原因

  • SYN 队列满(半连接队列溢出)
  • Accept 队列满(全连接队列溢出)
  • 防火墙/安全组规则
  • 端口耗尽

诊断方法

  • 检查 netstat -s | grep -i listen
  • 监控队列状态(tcpaccept)
  • 检查可用端口范围

3. 分层诊断策略

应用层

  • 响应时间分布(P50/P95/P99)
  • 慢查询分析
  • 业务逻辑性能

传输层(TCP)

  • 连接建立时间
  • 数据传输效率
  • 连接关闭状态(TIME_WAIT 数量)

网络层(IP)

  • 路由路径
  • MTU 设置
  • 分片情况

链路层

  • 网卡队列
  • 软中断分布
  • 丢包统计

四、工具链与技能树

1. 必备工具

抓包与分析

  • tcpdump:流量捕获
  • tshark:命令行分析
  • Wireshark:图形化深度分析

连接监控

  • ss:socket 统计(替代 netstat)
  • tcpaccept:连接队列监控(bpftrace)
  • netstat:传统网络统计

性能分析

  • perf:CPU 性能分析
  • sar:系统活动报告
  • iftop:实时流量监控

内核调试

  • sysctl:内核参数查看/设置
  • bpftrace/eBPF:内核动态追踪
  • SystemTap:内核探测

2. 技能进阶路径

初级(理解基础)

  • TCP 三次握手、四次挥手
  • 常见状态(ESTABLISHED、TIME_WAIT、CLOSE_WAIT)
  • 基本抓包和过滤

中级(诊断问题)

  • 重传、丢包、窗口分析
  • 内核参数调优
  • 应用层协议解析(HTTP、MySQL)

高级(性能优化)

  • 拥塞控制算法
  • 零拷贝技术(sendfile、splice)
  • 内核网络栈优化
  • eBPF 自定义追踪

专家级(架构设计)

  • 高性能网络架构设计
  • 负载均衡策略
  • 容错与降级方案
  • 大规模分布式系统网络优化

五、学习资源与实践建议

1. plantegg 博客特色

理论与实践结合

  • 每个概念都有生产案例支撑
  • 提供完整的命令和代码示例
  • 强调可复现的实验方法

问题驱动

  • 从真实故障出发
  • 展示完整的排查过程
  • 总结可复用的方法论

工具导向

  • 详细的工具使用指南
  • 参数含义和适用场景
  • 输出结果的解读方法

2. 实践建议

搭建实验环境

  • 使用虚拟机或容器模拟网络场景
  • 用 tc(traffic control)模拟延迟、丢包
  • 搭建简单的客户端-服务器程序

动手实验

  • 复现博客中的案例
  • 修改参数观察效果
  • 记录实验结果和心得

建立知识库

  • 整理常用命令和参数
  • 记录典型问题的排查步骤
  • 积累自己的案例库

持续学习

  • 关注内核版本更新(新特性、新参数)
  • 学习新工具(eBPF、XDP)
  • 阅读内核源码(理解实现细节)

3. 避免的误区

误区 1:只学理论不实践

  • 网络知识必须通过实验验证
  • 理论与实际环境可能有差异

误区 2:盲目调优参数

  • 先理解参数含义和影响
  • 在测试环境验证效果
  • 记录调优前后的对比数据

误区 3:忽视应用层

  • 很多”网络问题”实际是应用层问题
  • 要结合应用日志和业务逻辑分析

误区 4:过度依赖工具

  • 工具是手段,理解原理才是目的
  • 学会从工具输出推导底层行为

六、总结

plantegg 博客的核心价值在于:

  1. 系统化:完整的知识体系,从基础到高级
  2. 实战化:真实案例,可复现的实验
  3. 工具化:详细的工具使用指南
  4. 方法论:可复用的问题排查流程

学习网络知识的最佳路径

  • 理论学习 → 动手实验 → 问题排查 → 性能优化 → 架构设计

持续提升的关键

  • 保持好奇心,深入理解原理
  • 多动手实践,积累经验
  • 建立自己的知识体系和工具链
  • 关注技术演进,学习新技术

文档生成时间:2026-01-18
来源:plantegg.github.io (Context7 库)
适用对象:系统工程师、SRE、后端开发、网络工程师

MySQL PreparedStatement Performance Issue Reproduction Report

1. Executive Summary

1.1 Issue Description

A severe performance issue was reported when MySQL processes PreparedStatement IN queries with a large number of parameters (50,000) using useServerPrepStmts=true. According to the original report, server-side prepared statements were 190-207 times slower than client-side prepared statements.

1.2 Issue Source

1.3 Root Cause (Original Report)

When MySQL server processes PreparedStatement with large number of parameters:

  1. Excessive memory reallocation: 50,000 parameter replacement operations
  2. String operation complexity: O(SQL length) × number of parameters
  3. Memory fragmentation: Frequent large memory block allocation and deallocation

2. Test Environment

2.1 AWS Resource Information

Resource Configuration
AWS Account 872515255872
Region ap-southeast-1
VPC vpc-084114e405054a5b7

2.2 RDS MySQL 8.0 Instance

Configuration Value
Instance Identifier mysql-prepared-test
Instance Type db.t3.medium (2vCPU, 4GB)
Storage 50GB gp3
Engine Version MySQL 8.0.43
Endpoint mysql-prepared-test.cfsoq6muu0jv.ap-southeast-1.rds.amazonaws.com

2.3 RDS MySQL 5.7 Instance

Configuration Value
Instance Identifier mysql57-prepared-test
Instance Type db.t3.medium (2vCPU, 4GB)
Storage 50GB gp3
Engine Version MySQL 5.7.44-rds.20240408
Endpoint mysql57-prepared-test.cfsoq6muu0jv.ap-southeast-1.rds.amazonaws.com

2.4 EC2 Test Client

Configuration Value
Instance ID i-0b26f3cb781bae059
Instance Type t3.medium
AMI Amazon Linux 2023
Public IP 18.141.185.36
Java Amazon Corretto 17
Maven 3.8.4

3. Test Methodology

3.1 Test Code

1
2
3
4
git clone https://github.com/plantegg/MySQLPrepared.git
cd MySQLPrepared
./run_test.sh --host <mysql-host> --port 3306 --database test \
--user admin --password '<password>' --rounds 3

3.2 Test Parameters

Parameter Value
IN query parameter count 50,000
Parameter type 15-digit large integers
SQL length (spaces=128) ~6.5MB
Test rounds 3

3.3 AWS CLI Commands

Create RDS MySQL 8.0 Instance

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
aws rds create-db-instance \
--profile default --region ap-southeast-1 \
--db-instance-identifier mysql-prepared-test \
--db-instance-class db.t3.medium \
--engine mysql \
--engine-version 8.0 \
--master-username admin \
--master-user-password '<password>' \
--allocated-storage 50 \
--storage-type gp3 \
--db-subnet-group-name mysql-benchmark-subnet-group \
--vpc-security-group-ids sg-01541b078e0b483d0 \
--no-multi-az \
--publicly-accessible \
--backup-retention-period 0 \
--no-auto-minor-version-upgrade

Create RDS MySQL 5.7 Instance

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
aws rds create-db-instance \
--profile default --region ap-southeast-1 \
--db-instance-identifier mysql57-prepared-test \
--db-instance-class db.t3.medium \
--engine mysql \
--engine-version 5.7.44-rds.20240408 \
--master-username admin \
--master-user-password '<password>' \
--allocated-storage 50 \
--storage-type gp3 \
--db-subnet-group-name mysql-benchmark-subnet-group \
--vpc-security-group-ids sg-01541b078e0b483d0 \
--no-multi-az \
--publicly-accessible \
--backup-retention-period 0 \
--no-auto-minor-version-upgrade

Create EC2 Test Instance

1
2
3
4
5
6
7
8
aws ec2 run-instances \
--profile default --region ap-southeast-1 \
--image-id ami-0d1c0ec9903f7b01f \
--instance-type t3.medium \
--key-name renxijun-ec2-key \
--security-group-ids sg-0706d5fbe75649370 \
--subnet-id subnet-09d864b724dce6434 \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=mysql-prepared-test-ec2}]'

4. Test Results

4.1 MySQL 8.0.43 Test Results

Compact Format (spaces=0, SQL length ~100KB)

Configuration Average Execution Time Com_stmt_prepare
useServerPrepStmts=false 129.6ms 0
useServerPrepStmts=true 115.6ms 1
Performance Difference true is 1.1x faster -

With Spaces Format (spaces=128, SQL length ~6.5MB)

Configuration Average Execution Time Com_stmt_prepare
useServerPrepStmts=false 400.7ms 0
useServerPrepStmts=true 101.0ms 1
Performance Difference true is 4.0x faster -

4.2 MySQL 5.7.44 Test Results

With Spaces Format (spaces=128, SQL length ~6.5MB)

Configuration Average Execution Time Com_stmt_prepare
useServerPrepStmts=false 600.0ms 0
useServerPrepStmts=true 90.0ms 1
Performance Difference true is 6.7x faster -

4.3 Comparison with Original Report

Version Original Report (5.7.29) This Test (5.7.44) This Test (8.0.43)
false avg time ~52ms 600ms 400.7ms
true avg time ~27,839ms 90ms 101ms
Performance Diff true 535x slower true 6.7x faster true 4.0x faster

5. Conclusions

5.1 Reproduction Results

The performance issue described in the original report could NOT be reproduced on MySQL 5.7.44 and 8.0.43.

Test results show:

  • On both versions, useServerPrepStmts=true is actually faster than false
  • MySQL 5.7.44: Server-side prepared statements are 6.7x faster
  • MySQL 8.0.43: Server-side prepared statements are 4.0x faster

5.2 Possible Explanations

  1. MySQL Version Differences

    • Original issue was discovered on MySQL 5.7.29
    • This test used MySQL 5.7.44 and 8.0.43
    • The issue may have been fixed in versions after 5.7.29
  2. AWS RDS Optimizations

    • AWS RDS may include specific performance optimizations
    • Behavior may differ from native MySQL installations
  3. JDBC Driver Version

    • Test used mysql-connector-j-8.0.33
    • Driver may have optimized parameter handling logic

5.3 Recommendations

  1. To Reproduce the Original Issue

    • Use MySQL 5.7.29 or earlier versions
    • Use native MySQL instead of AWS RDS
  2. Production Environment Recommendations

    • On newer MySQL versions, useServerPrepStmts=true performs better
    • Conduct performance testing with actual business scenarios
    • For IN queries with large parameter counts, consider batch queries or temporary table approaches

6. Appendix

6.1 Test Logs

MySQL 8.0.43 Complete Output

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
=== MySQL PreparedStatement Performance Comparison Test ===
Connection: mysql-prepared-test.cfsoq6muu0jv.ap-southeast-1.rds.amazonaws.com:3306/test
Parameter count: 50000
Test rounds: 3

Configuration: useServerPrepStmts=false
Parameter spaces: 128
SQL length: 6500023 characters
Executing query 1...
Query 1: 571ms (0 records returned)
Executing query 2...
Query 2: 317ms (0 records returned)
Executing query 3...
Query 3: 314ms (0 records returned)

=== useServerPrepStmts=false Test Results ===
Total execution time: 1202ms
Average execution time: 400.7ms
Records returned: 0
Com_stmt_prepare: 0 -> 0

Configuration: useServerPrepStmts=true
Parameter spaces: 128
SQL length: 6500023 characters
Executing query 1...
Query 1: 138ms (0 records returned)
Executing query 2...
Query 2: 92ms (0 records returned)
Executing query 3...
Query 3: 73ms (0 records returned)

=== useServerPrepStmts=true Test Results ===
Total execution time: 303ms
Average execution time: 101.0ms
Records returned: 0
Com_stmt_prepare: 0 -> 1

MySQL 5.7.44 Complete Output

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
=== MySQL PreparedStatement Performance Comparison Test ===
Connection: mysql57-prepared-test.cfsoq6muu0jv.ap-southeast-1.rds.amazonaws.com:3306/test
Parameter count: 50000
Test rounds: 3

Configuration: useServerPrepStmts=false
Parameter spaces: 128
SQL length: 6500023 characters
Executing query 1...
Query 1: 639ms (0 records returned)
Executing query 2...
Query 2: 681ms (0 records returned)
Executing query 3...
Query 3: 480ms (0 records returned)

=== useServerPrepStmts=false Test Results ===
Total execution time: 1800ms
Average execution time: 600.0ms
Records returned: 0
Com_stmt_prepare: 0 -> 0

Configuration: useServerPrepStmts=true
Parameter spaces: 128
SQL length: 6500023 characters
Executing query 1...
Query 1: 117ms (0 records returned)
Executing query 2...
Query 2: 77ms (0 records returned)
Executing query 3...
Query 3: 76ms (0 records returned)

=== useServerPrepStmts=true Test Results ===
Total execution time: 270ms
Average execution time: 90.0ms
Records returned: 0
Com_stmt_prepare: 0 -> 1

6.2 Original Issue Stack Trace (from original report)

The original report included a pstack analysis showing the server spending excessive time in string replacement operations:

1
2
3
4
5
6
7
8
9
10
11
Thread 1 (Thread 0x7feeb8043640 (LWP 2508284)):
#0 __memmove_avx512_unaligned_erms () from /lib64/libc.so.6
#1 my_realloc () at mysys/my_malloc.c:112
#2 String::mem_realloc () at sql-common/sql_string.cc:128
#3 String::replace () at sql-common/sql_string.cc:804
#4 String::replace () at sql-common/sql_string.cc:783
#5 Prepared_statement::insert_params () at sql/sql_prepare.cc:924
#6 Prepared_statement::set_parameters () at sql/sql_prepare.cc:3496
#7 Prepared_statement::execute_loop () at sql/sql_prepare.cc:3559
#8 mysqld_stmt_execute () at sql/sql_prepare.cc:2582
...

This stack trace indicates the server was performing extensive memory reallocation and string manipulation operations during parameter substitution.

6.3 References

7. Submission Notes for MySQL Community

7.1 Summary for Bug Report

Title: Performance regression with useServerPrepStmts=true for large IN queries appears to be fixed in MySQL 5.7.44+

Description:
A previously reported performance issue where server-side prepared statements (useServerPrepStmts=true) were significantly slower than client-side prepared statements for IN queries with 50,000 parameters could not be reproduced on MySQL 5.7.44 and 8.0.43.

Original Behavior (MySQL 5.7.29):

  • useServerPrepStmts=true: ~27,839ms average
  • useServerPrepStmts=false: ~52ms average
  • Performance difference: 535x slower with server-side

Current Behavior (MySQL 5.7.44 / 8.0.43):

  • useServerPrepStmts=true: ~90-101ms average
  • useServerPrepStmts=false: ~400-600ms average
  • Performance difference: 4-6.7x faster with server-side

Request:
Could the MySQL team confirm if this issue was intentionally fixed in a specific version? If so, please document the fix in the release notes for user awareness.


Report Generated: 2026-01-12
Test Executor: Kiro CLI
AWS Account: 872515255872

0%