Jepsen 报告震动 Go 社区:NATS JetStream 会丢失已确认写入

本文永久链接 – https://tonybai.com/2025/12/11/jepsen-report-nats-jetstream-data-loss-acknowledged-writes

大家好,我是Tony Bai。

近日,一则重磅消息在 Go 社区引发了不小的震动。分布式系统领域的“终极拷问者”——Jepsen——发布了一份针对 Go 生态中流砥柱级消息系统 NATS 及其子系统 JetStream 的深度分析报告

报告的结论是严峻的,甚至可以说是颠覆性的:在特定的、可复现的故障模式下,NATS JetStream 可能会丢失已经被服务器确认 (acknowledged) 并声称“已成功持久化”的数据

对于一个以持久化和可靠性为核心卖点的系统而言,这无异于一声惊雷。这份报告,对于所有正在使用或考虑使用 NATS JetStream 的 Go 开发者来说,都是一份必读的“警示录”。它深刻地揭示了在一个分布式系统中,“持久化”的承诺与现实之间的微妙鸿沟。

背景科普:NATS 与 JetStream 是什么?

在深入 Jepsen 的发现之前,让我们先快速了解一下今天的主角。

  • NATS:是一个用 Go 语言编写的、开源、高性能的消息中间件。它以其极致的性能、简单的 API 和轻量级的设计,在 Go 社区乃至整个云原生领域享有盛誉。其核心(有时被称为 “Core NATS”)提供的是一种“尽力而为” (best-effort) 的消息传递,速度飞快,但不保证消息的持久性或送达。

  • NATS JetStream:这是 NATS 的一个内置子系统,旨在为需要更高可靠性的场景提供解决方案。通过引入 Raft 共识算法,JetStream 在 NATS 的核心之上,构建了一个持久化的、可复制的日志(流)。它向用户承诺提供“至少一次” (at-least-once) 的消息传递保证——即已被确认的消息,不应丢失。

正是 JetStream 的这份“不丢失”的承诺,成为了 Jepsen 本次“拷问”的核心目标。

核心发现:“懒惰”的 fsync 默认策略

Jepsen 报告中最核心、也最具普遍警示意义的发现,在于 NATS JetStream 的默认 fsync 策略

问题根源
NATS JetStream 宣称,一旦客户端的 publish 请求被服务器确认,该消息就“已成功持久化”。然而,Jepsen 的测试发现,这并不完全准确。

默认情况下,NATS JetStream 每两分钟才调用一次 fsync 将数据从操作系统的页面缓存 (page cache) 刷入物理磁盘。

这意味着,在任何两次 fsync 之间,都存在一个长达两分钟的窗口期。在这段时间内,所有被服务器立即确认的写入,实际上只存在于内存中

后果是什么?
如果在这两分钟的窗口期内,发生协调性的断电内核崩溃、或多个节点快速连续地重启,那些仅仅存在于内存中的、已经被确认为“持久化”的数据,将永久丢失

Jepsen 的测试通过一个名为 LazyFS 的工具,精确地模拟了这种“断电即失忆”的场景,并成功复现了数据丢失:在一个测试运行中,NATS 丢失了大约 30 秒的写入,共计 131,418 条已被确认的消息。

与 Raft 理论的背离
这实际上与 Raft 论文的建议相悖。Raft 明确指出,节点在响应客户端之前,必须“将新的日志条目刷入 (flush) 它们的磁盘”。MongoDB, etcd, TiDB, Zookeeper 等其他基于共识的系统,都遵循了这一“先落盘,再确认”的原则。

NATS 的选择,是一种典型的性能与持久性之间的权衡。通过异步 fsync,它获得了极高的写入吞吐量,但牺牲了对“灾难性事件”的防护能力。

NATS 团队的回应
NATS 团队已经意识到了这个问题,并在文档中补充说明了这一风险。他们建议,对于需要更强持久性保证的用户,可以将 sync_interval 设置为 always,但这会将吞吐量降低到每秒几百条消息。

更深层次的风险:文件损坏与脑裂

除了 fsync 的问题,Jepsen 还发现了几个在文件损坏场景下,可能导致更严重后果的漏洞。

数据块 (.blk) 文件损坏导致大量数据丢失

Jepsen 发现,即使只是在一个 5 节点的集群中的少数节点上,对 JetStream 的数据块文件 (.blk) 引入单个比特位的错误或截断,也可能导致集群丢失大量已确认的写入,甚至出现数据分歧(脑裂)——不同的节点返回不同的消息集,整个流的数据变得像“瑞士奶酪”一样千疮百孔。

在一个测试中,对两个节点的文件进行比特翻转,最终导致三个节点丢失了高达 78% 的已确认消息。

快照 (snapshot) 文件损坏导致流被删除

更令人不安的是,当快照文件损坏时,一个节点可能会错误地认为某个流已经“孤立”(orphaned),并做出删除该流所有数据的决定。在 Jepsen 的测试中,一个数据已损坏的节点,竟然成功地成为了集群的领导者,并立即删除了包含所有测试消息的流,导致了数据的完全丢失

这暴露了 NATS 在面对数据损坏时,其领导者选举和恢复机制的潜在脆弱性。

一个单一的 OS 崩溃也可能导致数据丢失和脑裂

Jepsen 还设计了一个精巧的实验,证明在异步网络环境下,仅仅一次单节点的操作系统崩溃(模拟断电),就可能导致已提交写入的丢失和持久性的脑裂

场景复现

  1. Leader 节点将一次写入复制给了 Follower A,并收到了确认。此时,写入在 Leader 和 Follower A 的内存中被认为是“已提交”的。
  2. Leader 节点在将这次写入刷入磁盘之前,也还未成功复制给 Follower B 的时候,突然发生了 OS 崩溃。
  3. Leader 节点重启后,它内存中那份“已提交”的写入已经丢失
  4. 此时,集群中存在两个“干净”的节点(重启后的 Leader 和从未收到写入的 Follower B)。它们可以组成新的多数派,选举出新的领导者,并继续处理请求。
  5. 从这个新的多数派的视角看,那次丢失的写入仿佛从未发生过

Jepsen 的测试成功地在 NATS 2.12.1 中复现了这一理论场景,并导致了持久性的副本分歧(脑裂)。

Go 开发者的核心启示

这份报告,并非对 NATS 的“死刑判决”,而是一次深刻的、关于分布式系统复杂性的现实教育。对于 Go 社区的开发者,它至少带来了三点核心启示:

  1. 魔鬼在默认配置中:永远不要盲目相信软件的默认配置。NATS JetStream 默认的sync_interval,是为了性能而优化的,而非持久性。你需要根据你的业务场景(是能容忍丢失少量近期数据,还是要求金融级别的“绝不丢失”),来审慎地做出权衡和配置。

  2. “已确认”不等于“已落盘”:在与任何分布式存储系统交互时,请仔细阅读其文档,搞清楚一个“成功的”写入响应,其背后的持久性承诺到底是什么级别的。是“已写入 Leader 内存”、“已写入多数派内存”,还是“已在多数派节点上 fsync 到磁盘”?这三者之间,差之毫厘,谬以千里。

  3. 拥抱混沌工程:Jepsen 的工作方法,正是混沌工程思想的极致体现。它告诉我们,仅仅通过单元测试和集成测试,永远无法发现分布式系统在真实世界故障模式下的脆弱性。我们需要引入更复杂的、模拟真实世界混乱(网络分区、进程暂停、磁盘错误)的测试手段。

小结

NATS 依然是一个出色、高性能的 Go 原生消息系统。Jepsen 的这份报告,如同一次严苛的“体检”,指出了它在追求极致性能的过程中,所做出的一些高风险权衡。对于我们 Gopher 而言,这不仅是一次了解 NATS 内部工作原理的机会,更是一堂关于如何批判性地思考、审慎地选择和配置我们所依赖的基础设施的必修课。

资料链接:https://jepsen.io/analyses/nats-2.12.1


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

Go 跌出 TIOBE 前十?别被排名骗了,这才是它的真实地位

本文永久链接 – https://tonybai.com/2025/12/11/is-golang-still-a-growing-programming-language

大家好,我是Tony Bai。

Go 语言是否已经触到了天花板?在 Python 借力 AI 狂飙突进、Rust 备受追捧的今天,Go 的位置究竟在哪里?近日,Twitch工程师 Melkey 结合 JetBrains、Stack Overflow 以及 GitHub 的最新数据,发布了一份关于 Go 语言现状的深度分析。结论或许并不全是“好消息”,但却极其真实地反映了 Go 在工业界的稳固地位。

谁在用 Go?—— “云原生土著”的画像

JetBrains 的年度报告揭示了 Go 开发者的主要分布领域。数据显示,排名前三的应用场景分别是:

  1. Web 服务(无 GUI)
  2. 网站后端
  3. 云服务与基础设施

Melkey指出,尤其是第三点——云服务,最能代表 Go 的核心竞争力。这与行业内的普遍印象高度一致:专业的 Go 开发者往往不仅仅是在编写业务逻辑,更多时候是在与 Kubernetes 集群、微服务架构、CI/CD 管道以及各类 CLI 工具打交道。

如果说 Python 是数据科学的通用语,那么 Go 已经牢牢确立了自己作为云时代 C 语言的地位——它是构建现代基础设施的首选工具。

新手不再爱 Go?—— 一个值得注意的信号

在解读 Stack Overflow 2025 开发者调查时,Melkey敏锐地发现了一个略显尴尬的趋势。

虽然在所有受访者中,Go 的使用率约为 16.4%,但在“正在学习编程的人”(Learning to Code)这一群体中,Go 的排名出现了显著下滑。绝大多数编程新手的入门首选依然是 Python 或 JavaScript。

然而,这并不意味着 Go 的衰落。相反,数据显示,在“专业开发者”群体中,Go 的使用率上升到了 17%

Melkey分析认为,这意味着 Go 正逐渐成为一种“第二语言”。它不再是很多人的“初恋”语言,而是开发者在掌握了编程基础后,为了追求高性能、高并发和工程化能力而进阶选择的“成熟伴侣”。

薪资高,但别被“头衔”骗了

分享中提到,在美国,Go 开发者的年薪上限可达 50 万美元,平均薪资也极具竞争力。

但Melkey对此提出了冷静的见解。他指出,如果在 LinkedIn 等招聘平台上搜索,会发现纯粹招募“Golang Developer”的岗位并没有想象中那么多。大多数高薪岗位实际上招募的是“资深后端工程师”“云基础设施专家”

这传递了一个明确的信号:市场不缺会写 if err != nil 的程序员,缺的是懂分布式系统、懂架构、能解决复杂问题,并且恰好使用 Go 作为工具的工程师。真正值钱的不是 Go 的语法,而是用 Go 解决工程问题的能力。

TIOBE 排名下滑 vs GitHub 活跃度上升

数据层面出现了一个有趣的“冲突”。

在老牌的 TIOBE 指数2025年11月份数据中,Go 从去年的第 7 名下滑至今年的 第 11 名,跌出了前十。这似乎是一个危险的信号。

但如果转向 GitHub 的数据,Go 依然是开源项目活动增长最快的前三名语言(仅次于 Python 和 TypeScript)。GitHub 的趋势图显示,Go 的生态活跃度保持着陡峭的上升曲线,没有减速迹象。

Melkey认为,TIOBE 可能反映了大众搜索的热度,但 GitHub 反映的是开发者用脚投票的结果。Go 的生态依然在蓬勃发展,只是不再像早期那样具有话题性和炒作度,而是进入了成熟期和深耕期。

AI 时代:Go 是“铲子商”,不是“淘金者”

在 AI 席卷全球的当下,Go 的位置在哪里?Melkey给出了精准的定位:“Go 在构建 AI 基础设施方面表现出色,但缺乏原生的机器学习解决方案。”

Melkey结合自己在 Twitch 构建 ML 基础设施的经历印证了这一点:在 AI 领域,Python 用于模型训练(得益于 PyTorch, TensorFlow 等库),而 Go 则用于部署模型、构建大规模并发的推理服务以及搭建底层的 ML 基础设施

Go 不会取代 Python 成为 AI 训练的语言,但在 AI 落地、服务化、工程化的“最后一公里”,Go 是绝对的主力。

小结:Go 的未来是“稳态”

基于上述数据,Melkey给出了自己的最终结论:

Go 不会消失,但也别指望它能像火箭一样再次爆发式增长。

它不会取代 Python 或 TypeScript 成为统治一切的通用语言。它正在进入一个“稳态”。在云原生、后端服务和基础设施领域,Go 已经建立了坚不可摧的壁垒。对于追求职业发展的工程师而言,它依然是一个稳定、高效且回报丰厚的选择。

Go 的未来,或许不再是“无处不在”,但注定是“不可或缺”

资料链接:https://www.youtube.com/watch?v=QjGduiCFHY4


你的体感如何?

数据是宏观的,但体感是微观的。

在你所在的公司或团队,Go 语言的使用是在扩张还是收缩?你认为 Go 在 AI 时代最大的机会是什么?

欢迎在评论区分享你的观察,让我们一起拼凑出更真实的 Go 生态图景!


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言进阶课 AI原生开发工作流实战 Go语言精进之路1 Go语言精进之路2 Go语言第一课 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats