🔥你好我是fengxin_rou这是我的个人主页 fengxin_rou的主页
❄️欢迎查看我的专栏我的专栏
《Java后端学习》、《JAVASE基础》、《JUC并发》、《redis》、《JVM虚拟机》、《MYSQL》、《黑马点评》、《rabbitmq》、《JavaWeb+AI的talis学习系统》、《苍穹外卖》

目录
[一、雪花算法 ID 生成器:分布式唯一 ID 设计与实现](#一、雪花算法 ID 生成器:分布式唯一 ID 设计与实现)
[1.1 ID 结构设计](#1.1 ID 结构设计)
[1.2 核心代码实现](#1.2 核心代码实现)
[1.3 关键特性](#1.3 关键特性)
[二、Feed 流三级缓存架构:高并发读性能优化](#二、Feed 流三级缓存架构:高并发读性能优化)
[2.1 缓存层级定义](#2.1 缓存层级定义)
[2.2 缓存读取流程](#2.2 缓存读取流程)
[2.3 hasMore 软缓存设计](#2.3 hasMore 软缓存设计)
[2.4 核心优势](#2.4 核心优势)
[3.1 核心设计思路](#3.1 核心设计思路)
[3.2 计数监听核心代码](#3.2 计数监听核心代码)
[3.3 反向索引与清理机制](#3.3 反向索引与清理机制)
[4.1 关键实践原则](#4.1 关键实践原则)
[4.2 架构整体价值](#4.2 架构整体价值)
前言
在高并发内容平台中,分布式 ID 生成、多级缓存架构、实时计数更新 是支撑海量请求的核心技术。本文基于知文业务实战,深度解析雪花算法 ID 生成器、Feed 流三级缓存设计、计数旁路更新与反向索引精准失效方案,覆盖原理、代码实现与工程化实践,可直接用于分布式内容系统架构设计。补充可以观看我前一篇feed文Feed 三级缓存架构详解:分层设计、缓存一致性与高性能实战
一、雪花算法 ID 生成器:分布式唯一 ID 设计与实现
在分布式系统中,数据库自增 ID 存在性能瓶颈、易暴露业务量、不支持多机房 等缺陷,雪花算法通过内存生成 ID,单机 TPS 可达千万级,完美解决上述问题。
1.1 ID 结构设计
雪花 ID 为64 位长整型,结构固定:
- 1 位符号位:固定为 0,保证 ID 为正数
- 41 位时间戳:相对自定义纪元,支持约 69 年
- 5 位数据中心 ID:支持 32 个机房
- 5 位工作节点 ID:单机房支持 32 台服务器
- 12 位序列号:单毫秒支持 4096 个 ID
1.2 核心代码实现
@Component
public class SnowflakeIdGenerator {
// 自定义纪元:2024-01-01 00:00:00 UTC
private static final long EPOCH = 1704067200000L;
// 各部分位数定义
private static final long WORKER_ID_BITS = 5L;
private static final long DATACENTER_ID_BITS = 5L;
private static final long SEQUENCE_BITS = 12L;
// 最大值计算
private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
private static final long MAX_DATACENTER_ID = ~(-1L << DATACENTER_ID_BITS);
// 位移偏移量
private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;
private static final long DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
private static final long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS;
private static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);
private final long datacenterId;
private final long workerId;
private long lastTimestamp = -1L;
private long sequence = 0L;
// 构造器与参数校验
public SnowflakeIdGenerator(long datacenterId, long workerId) {
if (workerId > MAX_WORKER_ID || workerId < 0) {
throw new IllegalArgumentException("workerId越界");
}
if (datacenterId > MAX_DATACENTER_ID || datacenterId < 0) {
throw new IllegalArgumentException("datacenterId越界");
}
this.datacenterId = datacenterId;
this.workerId = workerId;
}
// 线程安全生成ID
public synchronized long nextId() {
long timestamp = System.currentTimeMillis();
// 时钟回拨处理
if (timestamp < lastTimestamp) {
long offset = lastTimestamp - timestamp;
if (offset <= 5) {
// 小幅度回拨:等待时钟追回
try { Thread.sleep(offset); }
catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException("线程中断");
}
timestamp = System.currentTimeMillis();
if (timestamp < lastTimestamp) {
throw new IllegalStateException("时钟仍回拨");
}
} else {
// 大幅度回拨:拒绝生成
throw new IllegalStateException("时钟回拨过大");
}
}
// 序列号自增
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & SEQUENCE_MASK;
if (sequence == 0) {
timestamp = waitNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
// 组装ID
return ((timestamp - EPOCH) << TIMESTAMP_LEFT_SHIFT)
| (datacenterId << DATACENTER_ID_SHIFT)
| (workerId << WORKER_ID_SHIFT)
| sequence;
}
private long waitNextMillis(long lastTimestamp) {
long timestamp = System.currentTimeMillis();
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
return timestamp;
}
}
1.3 关键特性
- 线程安全:nextId () 加 synchronized,保证并发安全
- 时钟回拨防护:≤5ms 等待追回,>5ms 直接抛异常,避免 ID 重复
- 高并发:单毫秒支持 4096 个 ID,内存计算无 IO 开销
二、Feed 流三级缓存架构:高并发读性能优化
知文 Feed 采用L1 本地缓存 + L2 Redis 分片缓存 + L3 数据库三级架构,解决高并发下缓存击穿、命中率低、更新不及时问题。
2.1 缓存层级定义
- L1 Caffeine 缓存:本地内存,存储整页 Feed 数据,访问速度 0.001ms
- L2 Redis 分片缓存:存储文章 ID 列表、单篇文章详情、hasMore 标记,支持批量读取
- L3 MySQL 数据库:数据源头,仅缓存未命中时查询
2.2 缓存读取流程
- 请求进入,优先查询 L1,命中直接返回
- L1 未命中,查询 L2,数据完整则组装并回填 L1
- L2 数据不完整,触发 L3 查询,全量覆盖 L2 后回填 L1
- 前端展示并结束流程
2.3 hasMore 软缓存设计
hasMore 标记是否有下一页,采用软缓存 + 兜底逻辑:
- 优先使用缓存中的 hasMore 值
- 缓存缺失时,按
当前页数量==页大小判断 - 兜底不影响最终准确性,下一页请求会修正为真实值
2.4 核心优势
- 防缓存击穿:单航班锁保证同一页只查一次数据库
- 高命中率:L1+L2 组合命中率可达 99%+
- 状态分离:用户态与公共态分离,避免缓存污染
三、计数旁路更新与反向索引:实时计数精准失效
点赞、收藏等计数变化,需不侵入主流程、精准更新所有相关缓存,采用计数旁路 + 反向索引方案实现。
3.1 核心设计思路
- 旁路更新:计数变更通过事件异步触发,不阻塞主接口
- 反向索引:记录文章 ID→被哪些 Feed 页引用,实现精准失效
- 双缓存更新:同步更新 L1 本地缓存与 L2 Redis 缓存
3.2 计数监听核心代码
@EventListener
public void onCounterChanged(CounterEvent event) {
// 只处理知文点赞/收藏事件
if (!"knowpost".equals(event.getEntityType())) return;
String metric = event.getMetric();
if (!"like".equals(metric) && !"fav".equals(metric)) return;
String eid = event.getEntityId();
int delta = event.getDelta();
// 更新创作者总计数
try {
KnowPost post = knowPostMapper.findById(Long.valueOf(eid));
if (post != null && post.getCreatorId() != null) {
long owner = post.getCreatorId();
if ("like".equals(metric)) {
userCounterService.incrementLikesReceived(owner, delta);
}
if ("fav".equals(metric)) {
userCounterService.incrementFavsReceived(owner, delta);
}
}
} catch (Exception ignored) {}
// 获取最近两小时反向索引
long hourSlot = System.currentTimeMillis() / 3600000L;
Set<String> keys = new LinkedHashSet<>();
Set<String> cur = redis.opsForSet().members("feed:public:index:" + eid + ":" + hourSlot);
Set<String> prev = redis.opsForSet().members("feed:public:index:" + eid + ":" + (hourSlot - 1));
if (cur != null) keys.addAll(cur);
if (prev != null) keys.addAll(prev);
// 遍历更新缓存
for (String key : keys) {
// 更新L1本地缓存
FeedPageResponse local = feedPublicCache.getIfPresent(key);
if (local != null) {
FeedPageResponse updated = adjustPageCounts(local, eid, metric, delta, true);
feedPublicCache.put(key, updated);
}
// 更新L2 Redis缓存
String cached = redis.opsForValue().get(key);
if (cached != null) {
try {
FeedPageResponse resp = objectMapper.readValue(cached, FeedPageResponse.class);
FeedPageResponse updated = adjustPageCounts(resp, eid, metric, delta, false);
writePageJsonKeepingTtl(key, updated);
} catch (Exception ignored) {}
} else {
// 清理失效索引
redis.opsForSet().remove("feed:public:index:" + eid + ":" + hourSlot, key);
}
}
}
3.3 反向索引与清理机制
- 正向索引:页面 Key→包含的文章 ID
- 反向索引:文章 ID→被哪些页面引用
- 自动清理:缓存过期时,监听器自动移除无效索引,避免内存浪费
四、工程化实践要点与架构价值
4.1 关键实践原则
- 参数安全化:接口参数校验,防止恶意请求
- 防御性编程:空值判断、异常捕获,保证系统健壮
- 状态隔离:用户态不写入公共缓存,避免数据污染
- 软缓存兜底:关键标记用软缓存 + 逻辑兜底,提升可用性
4.2 架构整体价值
- 性能提升:接口响应从百毫秒降至毫秒级
- 高可用:缓存 + 数据库降级,支持流量洪峰
- 易扩展:支持多机房、多节点水平扩容
- 低耦合:计数、缓存、业务逻辑分离,便于维护
结语
本文完整呈现知文 Feed 高并发架构的三大核心:雪花 ID 保证分布式唯一 、三级缓存支撑高并发读 、反向索引 + 旁路更新实现实时计数。整套方案兼顾性能、可靠性与可扩展性,适用于内容 Feed、社交动态、商品流等高并发场景。实际落地中,可根据业务调整节点位数、缓存过期时间、回拨容忍阈值,进一步优化架构适配性。
