如何设计一个朋友圈系统

整体分层:接入层 → 业务服务层(用户关系 / 朋友圈动态 / 互动点赞)→ 缓存层 → 消息队列层 → 存储层(MySQL + 分库分表 + ES)

核心技术栈:SpringBoot、MyBatis-Plus、Redis Cluster、RocketMQ/Kafka、Elasticsearch、Sharding-JDBC、分布式锁 Redisson

一、模块 1:关注、取关、共同关注(用户关系子系统)

1.1 核心实体与存储设计

数据库分库分表方案

用户关系数据量大,按用户 ID 哈希分片,分为两张核心表:

  1. user_follow 关注表(我关注的人)

    CREATE TABLE user_follow (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT COMMENT '当前用户ID',
    follow_user_id BIGINT COMMENT '被关注人ID',
    status TINYINT DEFAULT 1 COMMENT '1正常关注 0已取关',
    create_time DATETIME,
    update_time DATETIME,
    UNIQUE KEY uk_uid_fuid (user_id, follow_user_id)
    ) ENGINE=InnoDB;

  2. user_fan 粉丝表(关注我的人)

    CREATE TABLE user_fan (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT COMMENT '被关注人ID',
    fan_user_id BIGINT COMMENT '粉丝ID',
    status TINYINT DEFAULT 1,
    create_time DATETIME,
    update_time DATETIME,
    UNIQUE KEY uk_uid_fanuid (user_id, fan_user_id)
    ) ENGINE=InnoDB;

设计说明:双向存储,查关注列表查 user_follow,查粉丝列表查 user_fan,避免关联查询,提升读性能;唯一索引防止重复关注。

Redis 缓存设计(热点数据全缓存,减轻 DB 压力)
  1. 我关注的人集合 Set Key:follow:set:{userId},Value:所有 follow_user_id,过期时间永久,取关时直接 SREM
  2. 我的粉丝集合 Set Key:fan:set:{userId},Value:所有 fan_user_id
  3. 关注状态缓存(快速判断 A 是否关注 B) Key:follow:map:{userId},Hash 结构,field=followUserId,value=1 关注 / 0 取关

1.2 核心接口逻辑

  1. 关注接口 follow (Long targetUserId)
    • 前置校验:不能关注自己;分布式锁防止并发重复关注
    • DB:user_follow 插入 / 更新,user_fan 插入 / 更新
    • Redis:SADD 关注集合、HSET 状态
    • MQ 发送关注关系变更事件,用于后续动态推送刷新共同好友
  2. 取关接口 unFollow (Long targetUserId)
    • DB:两张表 status 更新为 0,逻辑删除(保留历史数据)
    • Redis:SREM 集合、HSET 状态 0
  3. 共同关注(双向交集) 需求:查看我和用户 A 共同关注了哪些人 实现:Redis 集合交集命令 SINTER follow:set:{myId} follow:set:{targetId} 优化:交集结果缓存 5 分钟,减少频繁计算;超大集合交集异步计算存入临时缓存

1.3 并发与一致性方案

  1. 关注 / 取关使用Redisson 分布式锁 ,锁 key:lock:follow:{uid}:{targetUid},防止并发重复关注、脏数据
  2. 缓存与 DB 双写一致性:先更新 DB,再更新 Redis;失败则 MQ 重试补偿
  3. 冷热分离:3 个月前失效的关注 / 粉丝数据归档至历史分表,减少主表数据量

二、模块 2:关注推送(朋友圈动态流推送系统)

2.1 两种推送方案对比(业界主流)

方案 实现逻辑 优点 缺点 适用场景
推模式(写扩散) 用户发朋友圈时,遍历自己所有粉丝,把动态 ID 写入每个粉丝的推送缓存 刷朋友圈读极快,O (1) 读取 大 V 粉丝百万级,发动态阻塞、占用大量内存 普通用户(粉丝 < 1w)
拉模式(读扩散) 用户刷朋友圈时,查询自己全部关注人,批量拉取所有人最新动态 发动态无性能损耗,大 V 友好 刷首页需要批量查询多用户动态,查询耗时高 百万粉大 V、网红

2.2 混合推送架构(线上落地最优方案)

  1. 用户分层:
    • 普通用户(粉丝 < 5000):推模式
    • 大 V(粉丝≥5000):拉模式
  2. 动态存储: 朋友圈动态主表 moment,按发布用户 ID 分表,ES 存储全文(文字、图片标签,支持搜索)
  3. Redis 推送存储结构(推模式) Key:feed:list:{userId}SortedSet 有序集合
    • score:动态发布时间戳(倒序,最新动态在前)
    • member:momentId 限制长度:只保留最近 500 条动态,超过自动 ZREM 淘汰旧数据,控制内存占用

2.3 完整推送链路(异步解耦,核心靠 MQ)

  1. 用户发布朋友圈 → 写入 MySQL moment 表 + ES 索引
  2. 发送MomentPublishEvent消息至 RocketMQ Topic
  3. MQ 消费者分两条消费链路:
    • 链路 1【推模式推送】:获取发布者粉丝列表,批量将 momentId 写入每个粉丝的 feed 有序集合;批量操作 pipeline 优化 Redis 性能
    • 链路 2【统计异步任务】:动态点赞数、评论数初始化,更新用户动态数量缓存
  4. 用户刷朋友圈首页:
    • 先查自身 feed 有序集合,批量获取 momentId
    • 批量查询 Redis 缓存动态详情,缓存失效则批量查 MySQL
    • 分页返回前端;下拉加载更多直接 ZREVRANGE 分页

2.4 关键优化点

  1. 推送限流熔断:大 V 误触发推模式时,熔断降级改为拉模式,防止 Redis 雪崩
  2. 过期动态清理:定时任务清理 feed 列表中超过 30 天的动态
  3. 未读红点:单独 Redis Hash 存储每个动态的未读标记,用户刷新后批量清除

三、模块 3:点赞互动子系统

3.1 存储设计(冷热分离,缓存优先)

  1. 数据库(持久化,记录点赞关系)moment_like,按 momentId 分表(一条动态点赞量极大,按动态分片)

    CREATE TABLE moment_like (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    moment_id BIGINT COMMENT '朋友圈动态ID',
    user_id BIGINT COMMENT '点赞用户ID',
    status TINYINT DEFAULT 1 COMMENT '1点赞 0取消赞',
    create_time DATETIME,
    update_time DATETIME,
    UNIQUE KEY uk_moment_uid (moment_id, user_id)
    ) ENGINE=InnoDB;

唯一索引防止同一用户重复点赞。

  1. Redis 缓存(所有点赞热点操作走缓存,DB 异步落库)
    • 动态点赞总数:Key like:count:{momentId} String 类型,incr/decr 原子增减
    • 点赞用户集合 Set:Key like:set:{momentId},存储所有点赞 userId,快速判断是否已点赞(SISMEMBER)
    • 点赞用户分页缓存:ZSet 存储点赞时间,用于前端展示点赞人列表

3.2 点赞 / 取消赞核心流程(异步化,保证高并发)

  1. 点赞接口 like (Long momentId)
    • Redis 原子操作:SADD 点赞集合 + INCR 点赞总数;原子命令保证计数和集合一致
    • 发送 MQ 事件 MomentLikeEvent,异步消费者更新数据库 moment_like
    • 推送点赞通知给动态发布者(消息通知模块)
  2. 取消赞接口 unLike (Long momentId)
    • Redis:SREM 集合 + DECR 点赞总数
    • MQ 异步更新 DB 状态为 0

设计思路:点赞是高频读 + 高频写场景,同步操作只操作 Redis,DB 异步落地,保证接口 RT 极低;MQ 失败重试保证最终一致性。

3.3 高频查询需求实现

  1. 判断我是否点赞该动态:Redis SISMEMBER,O (1) 查询
  2. 获取动态点赞总数:直接读取 Redis String,无需查 DB
  3. 分页展示点赞用户:Redis ZREVRANGE 分页,缓存热点动态点赞列表,减少重复查询

3.4 并发与数据一致性保障

  1. 防止重复点赞:Redis SADD 天然幂等,重复点赞不会新增数据,接口直接返回成功
  2. Redis 与 DB 最终一致性:MQ 消息持久化,消费者失败重试;定时补偿任务扫描 Redis 与 DB 数据差异,修复不一致数据
  3. 缓存淘汰策略:冷动态(30 天无访问)清理点赞 Set 缓存,查询时降级查 DB,节省 Redis 内存

四、整体系统兜底 & 容灾方案

  1. 缓存雪崩 / 击穿:Redis 过期时间随机打散;点赞、feed 热点 key 永不过期;互斥锁防止缓存击穿
  2. 流量削峰:所有写操作(发动态、点赞、关注)全部通过 MQ 异步处理,抵御活动流量洪峰
  3. 降级熔断:Redis 宕机时,feed 流降级为纯拉模式;点赞缓存失效临时直接查询数据库
  4. 分库分表扩容:用户关系、动态、点赞表均基于 ID 哈希分片,后期数据量增长可平滑扩容分片数量
相关推荐
RSABLOCKCHAIN10 小时前
AI Agents in LangGraph-1
人工智能·系统架构
rfidwlw1 天前
资产管理系统对接财务系统:告别重复录入,让资产数据自动“过账”
系统架构·资产管理系统·rfid资产管理系统
.柒宇.1 天前
Elasticsearch 核心概念与系统架构详解
elasticsearch·系统架构
向日的葵0061 天前
Redis会话机制vsJWT机制深度解析
数据库·redis·python·缓存·系统架构·jwt
Xxtaoaooo2 天前
DolphinDB 物联网数据平台全景:一份从架构到落地的实践地图
物联网·系统架构·时序数据库·数据库架构·dolphindb
微三云 - 廖会灵 (私域系统开发)2 天前
电商售后与退款系统架构设计:从状态机到资金回退的全链路实践
系统架构
谙弆悕博士2 天前
系统集成项目管理工程师教程(第3版)笔记——第4章:信息系统架构
笔记·系统架构·项目管理·创业创新·学习方法·业界资讯·物理
某林2122 天前
ROS2 + WebRTC + MQTT 异构系统架构
架构·系统架构·机器人·硬件架构·webrtc·ros2
小马哥编程2 天前
【软考架构】候选键求解与主属性 / 非主属性判定
系统架构