动态流是社交系统里访问频率最高的一块,用户一打开首页就是请求动态列表。只要这一层设计不合理,接口延迟、数据库压力、卡顿都会集中爆发。结合 友猫社区 的实现,把动态流里最核心的 Redis 用法拆开说清楚。

一、动态流为什么不能直接查数据库
动态列表的典型请求特征:
- 高频读取(远高于写入)
- 强时效(用户希望看到“最新”内容)
- 分页加载(滚动加载)
如果直接查数据库:
- 热点数据重复查询
- 分页越往后越慢
- 高并发直接拖垮 MySQL
友猫社区的动态模块支持图文、视频、长图文混合流展示
这类结构一旦没有缓存层,性能基本扛不住。
二、缓存结构设计:不是简单 key-value
动态流常见的错误做法:
- 缓存整个列表 JSON
- 每次更新直接覆盖
问题:
- 更新成本高
- 无法支持个性化
- 缓存命中率低
更合理的方式是:拆成多层缓存结构
核心设计:
- feed:list → 存ID列表(有序)
- feed:detail:{id} → 存具体内容
- user:feed:{userId} → 个性化流
示意:
feed:list -> [1001,1002,1003...]
feed:detail:1001 -> {内容JSON}
优点:
- 列表和内容解耦
- 支持局部更新
- 降低缓存失效成本
三、时间线排序:为什么用有序集合
动态流核心问题:排序。
如果用普通 List:
- 插入复杂
- 难以按时间排序
友猫社区这种场景更适合 Redis 的 ZSet:
// 发布动态写入时间线
redisTemplate.opsForZSet().add(
"feed:list",
postId,
System.currentTimeMillis()
);
关键点:
- score = 时间戳
- 自动排序
- 支持分页查询
分页读取:
Set<Long> ids = redisTemplate.opsForZSet()
.reverseRange("feed:list", 0, 9);
这种方式比 SQL 的 order by + limit 稳定得多。
四、分页设计:避免深分页性能问题
数据库分页常见问题:
- page 越大越慢
- offset 成本高
缓存层的优化思路:
- 不用 pageNumber
- 使用“游标分页”
实现方式:
- 记录最后一条动态的时间戳或ID
- 下一页从这个位置继续查
逻辑类似:
第一次:取最新10条
第二次:取 score < lastScore 的10条
这样可以避免深分页带来的性能损耗。
五、热点数据处理:避免缓存击穿
动态流里会有“爆款内容”:
- 点赞高
- 评论多
- 被频繁访问
如果缓存失效:
- 瞬间大量请求打到数据库
解决方式:
- 设置随机过期时间(防止同时失效)
- 热点数据永不过期(人工干预)
例如:
redisTemplate.opsForValue().set(
"feed:detail:" + id,
data,
300 + new Random().nextInt(100),
TimeUnit.SECONDS
);
这种“抖动过期时间”的策略很实用。
六、写扩散 vs 读扩散:动态流核心架构选择
动态流设计有两个方向:
1. 写扩散(推模式)
发一条动态:
- 推送到所有粉丝缓存
优点:
- 读取快
缺点:
- 写入压力大
2. 读扩散(拉模式)
用户打开首页:
- 动态实时聚合
优点:
- 写入轻量
缺点:
- 读取复杂
友猫社区这类通用社区更偏向“读扩散 + 热点缓存”的混合模式:
- 普通内容 → 实时拉取
- 热门内容 → 缓存加速
这种设计更均衡。

七、点赞/评论计数:不能实时写数据库
动态流的互动操作:
- 点赞
- 评论
- 收藏
如果每次都更新数据库:
- 写放大严重
- 锁竞争明显
更好的方式:
- 先写 Redis
- 定时刷回数据库
例如:
like:count:1001 -> 235
定时任务批量同步:
- 减少数据库写压力
- 提高响应速度
八、缓存一致性问题:最容易踩坑的地方
常见问题:
- 用户删除动态,但缓存还在
- 内容更新,但列表未同步
解决策略:
- 删除时同步清缓存
- 或采用“延迟双删”
示意流程:
- 删除数据库
- 删除缓存
- 延迟再删一次缓存
这样可以避免并发读写导致脏数据。
九、个性化推荐的缓存分层
友猫社区支持话题、圈子、推荐内容等模块
动态流不是单一列表,而是:
- 推荐流
- 关注流
- 圈子流
缓存设计要分层:
feed:recommend:{userId}
feed:follow:{userId}
feed:circle:{circleId}
这样可以:
- 提高命中率
- 支持不同策略
十、缓存雪崩的真实触发场景
缓存雪崩不是理论问题,而是很容易发生:
- 大量 key 同时过期
- 系统重启缓存全空
应对方式:
- 分批加载缓存
- 设置不同过期时间
- 加入降级策略(返回旧数据)
十一、动态流架构的几个关键误区
实际项目里经常见到:
- 把 Redis 当数据库用(直接存大对象)
- 所有数据都缓存(内存被打爆)
- 没有过期策略(缓存失控)
- 分页仍然走数据库 offset
这些问题在小规模阶段不明显,一旦用户增长就会集中爆发。

十二、为什么动态流优化决定用户体验
用户打开首页的体验,本质就是:
- 首屏加载时间
- 滚动是否流畅
- 数据是否新鲜
Redis 在这里不是“优化项”,而是“基础设施”。
友猫社区这类结构把动态流拆成:
- ID流
- 内容缓存
- 行为计数
本质是在降低数据库参与度,让系统在高并发下仍然稳定运行。
友猫社区这套完善的源码,目前在市场上已经具备。
https://www.chongyou.info/1/product/tm.html

187

被折叠的 条评论
为什么被折叠?



