友猫社区源码拆解:基于 Redis 缓存的动态流性能优化实践

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

这样可以避免深分页带来的性能损耗。

五、热点数据处理:避免缓存击穿

动态流里会有“爆款内容”:

  • 点赞高
  • 评论多
  • 被频繁访问

如果缓存失效:

  • 瞬间大量请求打到数据库

解决方式:

  1. 设置随机过期时间(防止同时失效)
  2. 热点数据永不过期(人工干预)

例如:

 

redisTemplate.opsForValue().set(
"feed:detail:" + id,
data,
300 + new Random().nextInt(100),
TimeUnit.SECONDS
);

这种“抖动过期时间”的策略很实用。

六、写扩散 vs 读扩散:动态流核心架构选择

动态流设计有两个方向:

1. 写扩散(推模式)

发一条动态:

  • 推送到所有粉丝缓存

优点:

  • 读取快

缺点:

  • 写入压力大

2. 读扩散(拉模式)

用户打开首页:

  • 动态实时聚合

优点:

  • 写入轻量

缺点:

  • 读取复杂

友猫社区这类通用社区更偏向“读扩散 + 热点缓存”的混合模式:

  • 普通内容 → 实时拉取
  • 热门内容 → 缓存加速

这种设计更均衡。

七、点赞/评论计数:不能实时写数据库

动态流的互动操作:

  • 点赞
  • 评论
  • 收藏

如果每次都更新数据库:

  • 写放大严重
  • 锁竞争明显

更好的方式:

  • 先写 Redis
  • 定时刷回数据库

例如:

like:count:1001 -> 235

定时任务批量同步:

  • 减少数据库写压力
  • 提高响应速度

八、缓存一致性问题:最容易踩坑的地方

常见问题:

  • 用户删除动态,但缓存还在
  • 内容更新,但列表未同步

解决策略:

  • 删除时同步清缓存
  • 或采用“延迟双删”

示意流程:

  1. 删除数据库
  2. 删除缓存
  3. 延迟再删一次缓存

这样可以避免并发读写导致脏数据。

九、个性化推荐的缓存分层

友猫社区支持话题、圈子、推荐内容等模块

动态流不是单一列表,而是:

  • 推荐流
  • 关注流
  • 圈子流

缓存设计要分层:

 

feed:recommend:{userId}
feed:follow:{userId}
feed:circle:{circleId}

这样可以:

  • 提高命中率
  • 支持不同策略

十、缓存雪崩的真实触发场景

缓存雪崩不是理论问题,而是很容易发生:

  • 大量 key 同时过期
  • 系统重启缓存全空

应对方式:

  • 分批加载缓存
  • 设置不同过期时间
  • 加入降级策略(返回旧数据)

十一、动态流架构的几个关键误区

实际项目里经常见到:

  • 把 Redis 当数据库用(直接存大对象)
  • 所有数据都缓存(内存被打爆)
  • 没有过期策略(缓存失控)
  • 分页仍然走数据库 offset

这些问题在小规模阶段不明显,一旦用户增长就会集中爆发。

十二、为什么动态流优化决定用户体验

用户打开首页的体验,本质就是:

  • 首屏加载时间
  • 滚动是否流畅
  • 数据是否新鲜

Redis 在这里不是“优化项”,而是“基础设施”。

友猫社区这类结构把动态流拆成:

  • ID流
  • 内容缓存
  • 行为计数

本质是在降低数据库参与度,让系统在高并发下仍然稳定运行。

友猫社区这套完善的源码,目前在市场上已经具备。https://www.chongyou.info/1/product/tm.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值