news 2026/7/6 3:06:36

【简历进阶篇】大厂高并发利器:Single-flight机制深度解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【简历进阶篇】大厂高并发利器:Single-flight机制深度解析

🔥个人主页:代码不加冰(欢迎来访)
🎬作者简介:java后端学习者
❄️个人专栏:LeetCode刷题日记 , 苍穹外卖日记,SSM框架深入,JavaWeb
命运的结局尽可永在,不屈的挑战却不可须臾或缺!


前言:


大家好我是代码不加冰,继学完黑马点评之后,我们算是正式入门了后端,但是如果仅仅是这两个项目,那是完全不够看的,因此我这个暑假准备学两个新的项目写在简历里,然后再搞一下开源,为简历做准备,算是同步进行,算法和八股也不能落下。因此在这里开设一个新的专栏来分享一些新项目的重要技术,以及我自己的一些收获,也可以从中学到怎么入手一个新的项目。

摘要:

这里给大家分享一个技术,也不能说是技术,算是一种模式,在此之前我都没听过,不过学完之后感觉还是很有用的,一章肯定是讲解不完的,欢迎大家持续关注。

在暑期简历备战之际,本文为你解锁一个大厂高并发架构中的核心模式——Single-flight(单飞机制)。当热点数据导致缓存击穿时,Single-flight 能通过请求分组与状态跟踪,让成百上千个并发线程只由“第一个幸运儿”去冲击底层资源,其余线程原地阻塞等待并直接“共享结果”,将 DB 压力骤降至O(1)。

文章不仅深度剖析了其核心原理与应用场景,还直击痛点,揭示了单 JVM 环境下线程枯竭、OOM 以及异常共享等核心缺陷与补救措施。最后,结合分布式架构演进,类比分布式锁,引入基于 CAP 理论的“全局锁、状态机、心跳续期及 L1 降级”等分布式单飞核心设计,助你全方位攻克高并发流量穿透难题,打造差异化简历亮点!


Single-flight(单飞机制)

是一种并发控制模式,它的核心思想是:

对于同一个资源的多个并发请求,只允许第一个请求真正执行,其他请求等待第一个请求完成,然后共享同一个结果。

它的目的就是避免重复计算、重复访问数据库或远程服务,防止瞬时高并发把后端打爆。


举个例子

假设你的系统有一个接口:

GET /user/1001

正常情况下:

1000 个用户同时访问 │ ▼ 1000 次查询数据库

数据库:

SELECT * FROM user WHERE id = 1001

如果数据库一次查询需要:

100ms

那么1000个相同的SQL,实际上完全是重复劳动。


使用 Single-flight 后

流程变成:

1000 个请求 │ ▼ 发现 key = user:1001 已有人在查询 │ ├──────────────┐ │ │ 第一个请求 后面999个请求等待 │ │ ▼ │ 查询数据库 │ │ │ ▼ │ 得到结果 │ │ │ 通知所有等待者 ◄──────┘ │ ▼ 1000 个请求一起返回

数据库只查询1次


为什么叫 Single-flight

这个名字来自 Go singleflight package。

意思类似:

同一趟航班(Flight)只飞一次。

例如:

很多人都想去:

北京 → 上海

没有 Single-flight:

1000 架飞机

有 Single-flight:

1 架飞机 1000 人一起坐

请求也是一样:

同一个 key user:1001 大家共享一次执行结果

Single-flight解决什么问题

主要解决:

① 缓存击穿(最经典)

例如Redis:

user:1001

突然过期,瞬间

5000 个请求

全部发现:

Redis 没有

于是:

5000 次数据库查询

数据库直接压力暴增,加入 Single-flight

Redis miss ↓ 只有一个请求查数据库 ↓ 其他4999个等待 ↓ 数据库返回 ↓ 全部共享结果

数据库压力从:

5000 次 ↓ 1 次

② 防止重复调用远程接口

例如调用 AI:

GPT

或者支付查询,订单查询

如果:

100 个线程

都请求:

order123

其实只需要查一次即可。


③ 防止重复计算

例如:

生成 PDF,生成一次需要10秒

如果100个请求同时生成100次,浪费 CPU。

Single-flight:

只生成一次 其他请求等待 共享生成结果

核心原理

Single-flight 的原理非常简单直观:

  1. 请求分组:使用一个唯一的 key 来标识相同的请求(如缓存 key、接口参数哈希)

  2. 状态跟踪:内部维护一个 map,key 是请求标识,value 是正在执行的请求状态

  3. 结果共享当新请求到来时,先检查 map 中是否已有相同 key 的请求在执行

    1. 如果有:直接等待该请求的结果

    2. 如果没有:创建一个新的请求并执行,同时将其加入 map

  4. 结果广播:当请求执行完成后,将结果返回给所有等待的请求,并从 map 中移除该请求

可以用一个生活中的例子来理解:多个人同时想点同一家外卖,与其每个人都打开 APP 下单,不如大家凑在一起,由一个人下单,然后大家共享这份外卖。这就是 Single-flight 的工作方式。


单 JVM 环境下的核心缺陷与隐患

虽然单 JVM 避免了分布式网络 I/O,但由于所有线程都在同一个内存堆(Heap)中,它的缺陷会直接反映在 线程模型 和 内存管理 上:

1. 线程大面积阻塞与线程池耗尽(Thread Starvation)
  • 隐患:在单 JVM 中,Tomcat/Jetty 等 Web 服务器的业务线程池(如 200 个线程)是有限的。

  • 后果:如果底层数据库(DB)变慢,执行单飞任务的那个线程迟迟不返回,导致后续所有请求该 Key 的 JVM 业务线程全部进入WAITINGTIMED_WAITING状态。如果热点 Key 较多,整个 JVM 的线程池会在瞬间被榨干,导致整个服务无法响应其他任何请求。后果还是很严重的。

2. 内存突增风险(OOM 隐患)
  • 隐患:虽然多个线程共享了一个结果对象,但在等待期间,每个停留在future.get()或锁等待处的线程,都会占用一定的JVM 栈内存(Thread Stack)(通常每个线程默认 1MB)。

  • 后果:高并发下,大量线程积压会导致 JVM 线程栈内存开销激增。如果单飞返回的数据量非常大(例如一个巨大的 JSON 字符串或大列表),虽然对象只有一份,但如果引用的上下文中处理不当,可能会导致对象在堆中存活时间过长,频繁引发小范围的 GC 抖动

3. 异常共享(一错皆错)与缓存空穿透
  • 隐患:如果那个幸运的 JVM 线程在执行loader.get()时,遭遇了临时的数据库连接超时,抛出了RuntimeException

  • 后果:单 JVM 内所有等待这个Future的线程都会同时收到ExecutionException。这种“错误共享”会导致本该只有 1 个用户报错的偶发问题,瞬间扩散到所有并发访问的用户。

4. 无法应对集群扩展
  • 隐患:单 JVM 的单飞机制只在当前进程内有效

  • 后果:如果你的服务未来为了抗流,从单 JVM 扩展到了 10 台机器的集群。在同一时刻,10 台机器上会分别有一个线程去冲击数据库。虽然每台机器做到了单飞,但对于后端 DB 来说,依然承受了 $10 \times 1$ 的并发压力,因此就要引出分布式的单飞机制。


单 JVM 下的最佳实践与补救

为了在单 JVM 下安全地使用单飞,建议采取以下防范措施:

  1. 严格设置 Future 的 Get 超时时间

    绝对不要使用无限等待的future.get(),而是使用future.get(500, TimeUnit.MILLISECONDS)。一旦超时,快速降级(返回熔断数据或旧缓存),防止耗尽 JVM 线程池。

  2. 使用 Guava / Caffeine 內建的单飞

    Java 中不建议自己手写单飞,Caffeine 缓存的cache.get(key, k -> loadFromDB(k))原生在底层就实现了单 JVM 内的单飞机制(基于ConcurrentHashMap的锁分段和Node锁),并且针对垃圾回收和并发性能做到了极致优化。

  3. 结合异步刷新(Refresh After Write)

    让老数据先返回给用户,后台启动一个异步线程去单飞加载新数据。这样用户线程永远不会阻塞,彻底根治线程木僵和超时问题


分布式Single-flight

其实学这个单体和分布式,和我们在点评中学的锁机制感觉有异曲同工之妙,单体锁和分布式锁,都是为了应对负载均衡,集群部署的问题

单机能力集群后为什么失效演进方案
synchronized锁只能作用于当前 JVM分布式锁
ReentrantLock只能锁本机线程分布式锁
Single-flight只能去重本机请求分布式 Single-flight

根本原因都是:

负载均衡后,请求被分发到了不同的 JVM,本地内存状态无法共享。

唯一的区别是,它们扩展的是不同的能力

  • 扩展的是互斥能力(整个集群只能有一个执行者)。
  • Single-flight扩展的是请求去重能力(整个集群相同请求只执行一次,其他节点共享结果)。

所以,演进原因相同,扩展目标不同。

因此明白了上面的类比,我们再学习分布式的Single-Flight就很简单了

用一句话来说,就是为了解决在多台机器组成的集群环境下,防止热点缓存失效时高并发流量穿透到后端,确保整个集群在同一时刻仅有唯一一个请求去冲击数据库,从而彻底避免数据库被冲垮,其实就是通过共享那一次的查询结果,来避免数据库被冲垮,因果关系。


再深入一下:

分布式系统的CAP理论:

在分布式系统中,一致性、可用性和分区容错性三者不能同时完全满足,系统设计必须在其中做出权衡。

C (Consistency - 一致性):每次读取要么获得最新写入的数据,要么报错。在分布式系统中,这意味着所有节点在同一时间的数据必须完全一致,就像访问单机单台数据库一样。

A (Availability - 可用性):每次请求都能获得一个(非错误)的响应,但不保证获取的是最新写入的数据。系统必须一直处于“可提供服务”的状态。

P (Partition Tolerance - 分区容错性):尽管网络会丢失或延迟节点之间的任意数量的消息(即发生网络分区),系统仍能继续运行。

所以,为了实现在分布式环境下,系统能够实现高可用,基于CAP理论,我们的分布式Single-flight分布式做了如下的设计

核心设计理念与 CAP 取舍:

  • 全局锁与状态机(偏向 CP):使用 Redis Lua 脚本保证争抢执行权的原子性。全网多个实例同时发起相同请求时,系统强制保证只有一个 Leader 节点突围。此时为了防止“僵尸节点”脑裂,引入Fencing Token(防护令牌)机制,一旦原 Leader 假死超时,立即剥夺其回写结果的权利。保证了在并发控制上对强一致性(C)。

  • 心跳续期与主动接管(保证 A):如果 Leader 节点真宕机了,其他处于等待共享状态的 Follower 节点不能被永远阻塞。通过 Owner Heartbeat 机制,一旦 Leader 心跳丢失,Follower 迅速超时并重新发起选举接管请求。这保证了哪怕发生单点故障,整个面试链路的可用性(A)依然不受影响。

  • 本地 L1 Cache 终极降级(AP 兜底):当遭遇极端网络故障(严重的 P),Redis 集群整体不可用时,框架自动退化回本地单机 Single-flight 模式。此时系统主动放弃了全局一致的请求合并(C),但死保住了用户的核心面试流程不中断(A)。

至于什么是状态机,heartbeat机制等等,我们放在后面研究。

结语:

这里仅仅是简单的带大家了解了一下这种单飞机制,下面我会继续深入的讲解这些底层原理,以及一些其他的技术。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/6 2:59:39

sealos安装k8s 1.31.11

参考网址&#xff1a;https://sealos.run/docs/k8s/quick-start/deploy-kubernetes首先确认k8s的版本镜像否可以拉取。脚本安装#!/bin/bashsudo cat > /etc/yum.repos.d/labring.repo << EOF [fury] namelabring Yum Repo baseurlhttps://yum.fury.io/labring/ enable…

作者头像 李华
网站建设 2026/7/6 2:58:58

AI Agent Skills:从代码补全到智能开发的效率革命

&#x1f680; 30款热门AI模型一站整合&#xff0c;DeepSeek/GLM/Qwen 随心用&#xff0c;限时 5 折。 &#x1f449; 点击领海量免费额度 如果你还在用 AI 编程助手只是让它帮你补全代码行&#xff0c;那你可能只发挥了它 10% 的潜力。真正的效率革命&#xff0c;发生在你教…

作者头像 李华
网站建设 2026/7/6 2:58:10

沙盒内外——杭州《AI OPC入市陪伴手册》解读

引子 你不在杭州&#xff0c;但你的问题在杭州 成都&#xff0c;一个人做 AI 数字人直播。AI 客服、AI 剪辑、AI 选品&#xff0c;全链路一个人跑。营收做到八位数。 市监局的询问函到了。事由&#xff1a;直播间 AI 客服推荐商品时做了不实功效描述&#xff0c;消费者截屏投诉…

作者头像 李华
网站建设 2026/7/6 2:58:07

STM32与M95M04实现嵌入式数据持久化存储方案

1. 项目背景与核心需求 在嵌入式系统开发中&#xff0c;用户偏好、日程设置和自定义配置的持久化存储是一个经典而关键的需求。以智能家居控制面板为例&#xff0c;系统需要可靠地保存以下三类数据&#xff1a; 用户偏好 &#xff1a;包括界面主题&#xff08;12种可选&#…

作者头像 李华
网站建设 2026/7/6 2:57:23

模型可解释性:特征重要性/SHAP/LIME

模型可解释性&#xff1a;特征重要性/SHAP/LIME 1. 特征重要性 from sklearn.ensemble import RandomForestClassifier import pandas as pd# 树模型内置特征重要性 rf RandomForestClassifier(n_estimators100, random_state42) rf.fit(X_train, y_train)importance pd.Seri…

作者头像 李华