LRU?SingleFlight?Flink?Spark?20260614杂八股
filebeat是beats的一个组件。
GMP相关
同一时刻:一个 M 只能绑定一个 P,一个 P 也只能被一个 M 使用;
生命周期上:M 和 P 不是永久一对一绑定,会因阻塞、抢占、空闲切换动态解绑、重新配对;
核心约束:M 执行 G 的前提是临时持有 P,而非终身绑定。
slice 不是线程安全的
多个 goroutine 并发读写同一个 slice,一定会出现数据竞争、结果异常、panic。
这首歌好听,推荐一下啊【ナースロボ_タイプT】あの会話の覚書【漣音】
redis 排行榜应该用哪个数据结构
ZSet【有序集合】,天然适配排序、分值、去重、分页、排名查询,是 Redis 做榜单的最优解。
元素唯一:成员(member)不可重复,天然防重复上榜
按分值排序:根据 score 自动升 / 降序排列,对应分数、热度、时间
高效排名查询:查询名次、区间分页、查某人排名时间复杂度极低
支持分数更新:直接修改 score,集合自动重排
1 | # 1. 添加/更新成员分数(上榜/加分) |
LRU 详解(最近最少使用)
一、核心概念
LRU (Least Recently Used):最近最少使用缓存淘汰算法。
规则:当缓存满了,优先删掉最久没被使用的数据。
二、实现思路(经典组合)
主流方案:哈希表 + 双向链表
- 双向链表
- 头部:最近使用的数据
- 尾部:最久未使用(优先淘汰)
- 优势:头尾增删、中间节点移动都是 $O(1)$
- 哈希表(HashMap)
- key → 链表节点
- 优势:查找节点 $O(1)$
整体时间复杂度:查、增、删、更新 均为 $O(1)$
三、操作流程
- 访问数据
- 存在:移到链表头部
- 不存在:新增节点放头部
- 缓存已满
- 删除链表尾部节点 + 哈希表对应记录
四、Go 极简实现(可直接运行)
1 | package main |
五、常见变种 & 对比
- LRU-K:访问 K 次才进入热点队列,抵御突发冷热数据
- LFU:按访问频次淘汰(区别:LRU 看时间,LFU 看次数)
- Redis 近似 LRU:不严格遍历链表,随机采样淘汰,性能更高
总结
1. 哈希表(map)
只负责:快速查找
特点:无序,不记录访问顺序
能力:给一个 key,
O(1)
找到对应的链表节点
2. 双向链表
只负责:维护访问时序(有序)
特点:严格有序
链表头部:最近刚使用
链表尾部:最久没使用(要被淘汰)
只有 len(s) == cap(s) 时,再执行 append 才会触发扩容。
len < cap:直接在原底层数组末尾写,不扩容。
len == cap:再 append → 必须扩容(新数组 + 拷贝)。
空切片 s := []int{}:len=0, cap=0,第一次 append 就扩容(分配 1 个元素空间)。
预防缓存击穿
【查询不存在的数据,请求直接越过缓存,全部打到数据库。】
空值缓存:查询结果为空,也把 null/空对象 写入缓存,设置短过期时间。
布隆过滤器:前置拦截不存在的 key,请求根本不进缓存 / DB。
接口层参数校验:非法 ID、非法参数直接拦截。
预防缓存穿透
【热点 Key 突然失效,大量并发请求瞬间全部打到数据库。】
互斥锁(分布式锁):同一 key 只放一个请求去查 DB、更新缓存,其他请求等待。
永不过期:热点 Key 逻辑过期(不删缓存,后台异步更新)。
缓存过期时间加随机值:打散过期时间,避免集体失效。
预防缓存雪崩
【大量缓存 key 集体失效 / 缓存服务宕机,所有请求直接涌向 DB。】
过期时间加随机偏移,打散失效时间;
缓存集群高可用:主从、哨兵、集群,避免单点故障;
服务层限流、降级、熔断:兜底保护 DB;
多级缓存:本地缓存 + 分布式缓存,层层防护;
Redis 持久化:宕机后快速恢复数据。
SingleFlight(请求合并/单飞模式)
一、是什么
SingleFlight 是 Go 官方扩展库(golang.org/x/sync/singleflight)提供的并发原语,核心作用:同一 key 的并发请求只执行 1 次,其余等待并共享结果,本质是「请求合并」而非「互斥锁」。
二、核心原理(极简版)
- 结构体:
Group内含mu(互斥锁)+m(map:key→正在执行的call)。 - 执行流程:
- N 个 goroutine 同时调用
sg.Do(key, func)。 - 第 1 个抢到锁的:发现 key 不存在 → 执行 func(查DB/调API)。
- 其他 N-1 个:发现 key 已存在 → 阻塞等待,不执行 func。
- 执行完的 goroutine:把结果/错误写入,唤醒所有等待者,共享同一份结果。
- N 个 goroutine 同时调用
- 返回值:
(val interface{}, err error, shared bool),shared=true表示结果是共享的(非本 goroutine 执行)。
三、核心作用(面试必背)
1. 防缓存击穿(最常用)
- 场景:热点 key 过期 → 大量请求同时打 DB。
- SingleFlight:同一 key 只放行 1 个请求查 DB,其他等待 → DB 压力从 N 降为 1。
2. 减少重复调用
- 第三方 API(按次计费)、复杂计算、配置拉取、元数据查询等,相同输入→相同输出的高成本操作。
3. 削峰控并发
- 瞬间高并发接口,合并请求,保护下游服务。
四、Go 代码示例(直接能用)
1 | package main |
输出:只会打印 1 次「真实查询DB」,其余 9 个请求直接共享结果。
五、关键特点(vs 互斥锁)
- 互斥锁:一次一个线程进临界区,串行执行,所有请求都要排队。
- SingleFlight:只执行1次,其他等待共享,并行等待、结果共享,性能更高。
六、避坑点(面试高频)
- 不是缓存:不存结果,只合并「缓存未命中→查DB」这一瞬间的请求,必须配合 Redis 等缓存用。
- 阻塞风险:如果执行函数卡死/慢,所有等待者都会阻塞 → 加超时控制(Do+context)。
- 错误扩散:执行函数失败,所有等待者都拿到错误 → 做好降级/重试。
- key 设计:必须精准(如订单ID、用户ID),不能带随机参数/时间戳,否则合并失效。
- 全局复用:
singleflight.Group要全局单例,否则不同实例无法合并请求。
七、总结(一句话)
SingleFlight:同一 key 并发请求合并为 1 次执行,防缓存击穿、降下游压力。
Flink 核心速记
一、基础定位
Apache Flink:分布式实时流处理引擎,主打低延迟、高吞吐、Exactly-Once,同时支持批处理(批是流的特例)。
口号:流处理优先,批流一体。
二、核心特点
- 批流统一
底层统一流式模型,批数据 = 有界流,实时数据 = 无界流,一套代码跑批/流。 - 状态计算
内置状态管理(内存+持久化),支持累计、窗口、聚合等计算,是实时计算核心。 - 精准语义
支持 Exactly-Once(精确一次)、At-Least-Once、At-Most-Once。 - 低延迟
基于事件驱动,而非微批,毫秒级延迟。 - 高可用 & 容错
依靠 Checkpoint(检查点)+ Savepoint(保存点) 做故障恢复、版本升级。
三、核心架构(四大组件)
- JobManager:主节点,调度任务、协调 Checkpoint、故障恢复(集群大脑)
- TaskManager:工作节点,执行具体 Task,管理内存/网络/状态
- Client:客户端,提交任务、生成执行图
- ResourceManager:资源管理器(对接 Yarn/K8s/Standalone)
运行链路:Client 提交任务 → JobManager 解析生成执行图 → 分发到 TaskManager 执行。
四、核心编程模型(两层 API)
1. 底层 API:DataStream(流) / DataSet(批,逐步废弃)
面向数据流,细粒度控制,做复杂计算、底层开发。
核心概念:
- Stream:无界/有界数据流
- Operator:算子(map、filter、flatMap、keyBy、reduce、sink)
- KeyBy:分组(类似 SQL group by),数据按 key 分到同一下游子任务
2. 高层 API(主流业务使用)
- Table API & Flink SQL:类 SQL 语法,开发效率高,企业最常用,支持窗口、聚合、关联。
五、高频核心概念(必背)
1. 窗口 Window
流是无限的,靠窗口切分成有限数据集再计算:
- 滚动窗口 Tumbling:固定时长/大小,不重叠、不漏数据
- 滑动窗口 Sliding:窗口长度 > 滑动步长,数据重叠
- 会话窗口 Session:按空闲间隔划分,一段时间无数据则窗口关闭
2. 时间语义(3 种)
- EventTime 事件时间:数据本身携带的时间戳(业务最常用,保证数据时序正确)
- ProcessingTime 处理时间:算子所在机器的系统时间(延迟最低,易受机器影响)
- IngestionTime 摄入时间:数据进入 Flink 的时间
配合 Watermark(水位线) 解决 EventTime 乱序、迟到数据 问题。
3. Watermark 水位线
- 作用:标记小于该时间的数据已全部到达,触发窗口计算
- 本质:一种特殊数据流,单调递增
- 迟到数据处理:设置允许迟到时间、侧输出流丢弃脏数据
4. 状态 State
- 分类:托管状态(Flink 自动管理,推荐)、原生状态
- 常用结构:ValueState、ListState、MapState、ReducingState
- 持久化:搭配 Checkpoint 落地到 HDFS/Redis 等
5. Checkpoint & Savepoint
- Checkpoint:自动周期性快照,故障自动恢复,保证 Exactly-Once
- Savepoint:手动触发快照,用于版本升级、代码修改、任务启停,人工运维使用
六、数据传输 & 并行度
- 并行度 Parallelism:决定任务并发能力,每个算子可单独设置并行度
- 数据分区策略:keyBy(哈希)、rebalance(轮询)、rescale、broadcast 等
七、典型应用场景
- 实时大屏、实时指标统计
- 实时风控、日志分析、用户行为分析
- 实时数仓(分层计算:ODS → DWD → DWS → ADS)
- 实时 ETL、数据同步
八、和 Spark Streaming 核心区别(面试对比)
- 模型
- Flink:纯流模型,事件驱动,毫秒级延迟
- Spark Streaming:微批模型,按批次处理,延迟秒级
- 时间 & 乱序
- Flink:原生支持 EventTime + Watermark,乱序处理完善
- Spark 弱支持,乱序处理复杂
- 状态
- Flink 内置强状态管理;Spark 依赖外部存储
- 批流
- Flink 流优先,批流一体;Spark 批优先,流是补充
极简背诵口诀
Flink = 分布式实时流引擎 + 批流一体 + 事件时间+水位线 + 状态+Checkpoint + 低延迟 Exactly-Once。






