仿小红书源码架构解析,瀑布流、Redis缓存、搜索与WebSocket消息设计

仿小红书源码架构解析,瀑布流、Redis缓存、搜索与WebSocket消息设计

仿小红书产品的技术核心,不只是图文发布、短视频发布、多图上传、点赞评论、收藏关注这些表层功能,更重要的是内容流如何稳定分发、图片视频如何存储、搜索结果如何快速返回、即时消息如何触达、多端数据如何保持一致。

在 Spring Boot 架构下,仿小红书源码通常会涉及 Redis、EasyES、WebSocket、Quartz、Shiro、Druid、对象存储、内容审核、短信服务等技术。不同技术并不是孤立存在,而是围绕内容社区的核心链路协同工作。

一、从内容流角度理解系统架构

仿小红书类应用的核心入口通常包括发现页、关注页、附近页、内容详情页和个人主页。发现页强调内容推荐和瀑布流展示,关注页依赖用户关系链,附近页需要结合定位数据,详情页承载评论、点赞、收藏、关注等互动行为,个人主页则聚合作品、收藏、浏览记录、关注列表和粉丝列表。

从后端设计来看,这些页面并不是简单查询某一张表,而是内容、用户、互动、搜索、消息等多类数据的组合结果。

例如发现页中的一条内容卡片,至少可能包含内容标题、封面图、作者信息、点赞数、收藏状态、评论数、发布时间、内容类型等字段。如果是短视频,还需要返回视频封面、视频地址、播放时长等数据。如果是附近页,还可能涉及经纬度和距离排序。

因此,仿小红书源码在设计时,不能只按照页面拆接口,更适合按照业务域拆分,例如内容域、用户域、互动域、搜索域、消息域、商品订单域和系统权限域。这样可以降低功能之间的耦合,也方便后续维护。

二、内容发布链路:草稿、上传、审核、入库、索引

图文发布、短视频发布、多图上传、话题标签和草稿保存,属于内容发布链路中的核心环节。

一个较完整的发布流程可以理解为:

内容编辑 ↓ 草稿保存 ↓ 图片或视频上传 ↓ 内容审核 ↓ 内容数据入库 ↓ 话题关系绑定 ↓ 搜索索引同步 ↓ 进入内容流展示

图片和视频文件不适合直接写入数据库。常见做法是将图片、视频、封面等资源上传到腾讯云对象存储,数据库只保存资源地址、文件类型、宽高、大小、时长、排序等元数据。

内容主表主要保存标题、正文摘要、作者 ID、分类 ID、发布状态、审核状态、发布时间、点赞数、评论数、收藏数、浏览数等字段。图片、视频、话题、内容与话题关系可以拆成独立表,避免所有字段堆在内容主表中。

草稿保存和正式发布也需要分开。草稿不一定进入审核流程,也不需要写入搜索索引。正式发布后,才需要触发内容审核、搜索索引同步和内容流分发。

@Transactional public Long publishPost(PostPublishDTO dto, Long userId) { Post post = new Post(); post.setUserId(userId); post.setTitle(dto.getTitle()); post.setContent(dto.getContent()); post.setCategoryId(dto.getCategoryId()); post.setAuditStatus(AuditStatus.WAITING); post.setCreateTime(LocalDateTime.now()); postMapper.insert(post); savePostMedia(post.getId(), dto.getMediaList()); savePostTopics(post.getId(), dto.getTopicIds()); return post.getId(); }

这段代码只展示内容发布的主流程。实际项目中还需要处理参数校验、文件归属校验、话题合法性校验、审核状态回写、异常回滚等问题。

三、双列瀑布流:重点在分页稳定性

仿小红书页面常见双列瀑布流布局。前端负责根据图片比例展示卡片,后端负责提供稳定的数据顺序。

如果使用普通的 pageNum + pageSize 分页,在内容持续新增的情况下,用户下拉加载时可能会遇到重复数据或漏数据。内容流更适合使用游标分页。

游标分页可以基于发布时间、内容 ID、推荐分数等字段。例如发现页可以使用 score + id,关注页可以使用 create_time + id,附近页可以结合距离、发布时间和内容 ID 做排序。

public List<PostVO> queryWaterfallFeed(Long lastId, LocalDateTime lastTime, Integer size) { LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Post::getStatus, PostStatus.NORMAL); if (lastId != null && lastTime != null) { wrapper.and(w -> w.lt(Post::getCreateTime, lastTime) .or() .eq(Post::getCreateTime, lastTime) .lt(Post::getId, lastId)); } wrapper.orderByDesc(Post::getCreateTime) .orderByDesc(Post::getId) .last("limit " + size); return postMapper.selectList(wrapper) .stream() .map(this::convertToPostVO) .toList(); }

瀑布流接口还需要返回图片宽高。前端拿到宽高后,可以提前计算卡片高度,减少图片加载完成后的页面抖动。短视频内容则需要返回封面图、视频时长、播放地址和内容类型,方便前端在同一条内容流中区分图文与视频。

四、Redis缓存:热点内容、热门搜索和互动计数

仿小红书产品中,Redis 的使用频率很高。首页推荐、热门搜索、热点内容、短信验证码、用户 Token、未读消息数、点赞数、收藏数、浏览数等,都可以结合 Redis 处理。

热门搜索适合使用 Redis ZSet。用户每搜索一次关键词,就增加对应分值。搜索页展示时,取分值靠前的关键词即可。

public void recordSearchKeyword(String keyword) { if (!StringUtils.hasText(keyword)) { return; } redisTemplate.opsForZSet() .incrementScore("hot:search:keywords", keyword, 1); } public Set<String> listHotKeywords() { return redisTemplate.opsForZSet() .reverseRange("hot:search:keywords", 0, 9); }

点赞、收藏、浏览这类数据属于高频变化数据。如果每次操作都直接更新数据库,容易增加数据库写入压力。可以先将计数写入 Redis,再通过 Quartz 定时任务批量同步到数据库。

但缓存设计不能只考虑性能,还要考虑一致性。例如内容被删除、审核未通过、设置隐藏后,对应的首页缓存、搜索索引、热门榜单都需要同步处理,否则可能出现内容状态不一致的问题。

五、EasyES搜索:内容、话题、商品的检索设计

内容搜索、热门搜索、商品搜索、话题搜索和用户搜索,都是仿小红书系统中的高频入口。数据库 LIKE 查询适合小规模数据,但面对标题、正文、话题、分类、昵称等多字段检索时,扩展性会比较有限。

EasyES 可以简化 Elasticsearch 的接入。内容审核通过后,将内容标题、正文摘要、话题名称、分类名称、作者昵称、封面图、发布时间、内容状态等字段写入索引。

搜索时,先从 EasyES 中查询内容 ID,再回到业务数据库补充用户互动状态,例如当前用户是否点赞、是否收藏、是否关注作者。这样可以避免搜索索引承担过多业务判断。

搜索索引需要跟随内容状态变化。内容删除、隐藏、审核失败时,索引也要同步更新。否则用户搜索时可能看到已经不可访问的内容。

六、互动系统:点赞、评论、回复、收藏、关注

点赞、评论、回复、收藏、关注和粉丝管理,是仿小红书源码中非常重要的一部分。

点赞表一般包含 user_id、target_id、target_type、create_time。target_type 可以区分内容点赞、评论点赞等场景。收藏表记录用户与内容之间的收藏关系。关注表记录关注者和被关注者之间的关系。

评论系统通常需要支持一级评论和二级回复。可以在评论表中设计 parent_id 和 root_id。parent_id 表示当前评论回复的是哪一条评论,root_id 表示它属于哪一条一级评论。这样在内容详情页展示评论时,可以先加载一级评论,再按需加载二级回复。

互动模块要特别注意重复操作问题。点赞表、收藏表、关注表都需要建立联合唯一索引,例如 user_id + target_id + target_type。这样即使前端重复点击,数据库层也能避免重复写入。

七、WebSocket即时通讯:单聊与通知触达

单聊、消息已读未读、图片发送、表情发送、系统通知、评论通知、点赞提醒和关注提醒,都属于消息体系。

WebSocket 适合处理在线消息推送。用户登录后建立连接,服务端维护 userId 与连接 Session 的映射。发送消息时,后端应先保存消息记录,再判断接收方是否在线。如果接收方在线,则实时推送;如果不在线,则保留未读状态,用户下次进入消息页时再拉取。

消息设计中需要区分私信消息和业务通知。私信消息更强调会话关系、发送者、接收者和已读状态;业务通知更关注触发来源,例如评论、点赞、关注、系统通知等。

未读数可以放在 Redis 中,例如 unread:user:{userId}。当用户进入会话详情或通知列表时,再清空对应未读数并更新数据库状态。

八、商品、购物车与订单数据设计

商品分类、商品列表、商品详情、商品搜索、购物车、立即购买、订单管理和在线支付,属于交易相关数据。虽然这些功能可能出现在同一个内容社区中,但数据库结构上应尽量与内容模块保持边界。

商品表保存商品名称、封面图、价格、库存、分类 ID、状态等信息。购物车表记录用户 ID、商品 ID、数量和选中状态。订单表记录订单号、用户 ID、订单金额、支付状态、订单状态和创建时间。订单明细表保存商品快照,避免商品后续修改影响历史订单。

支付状态应以后端支付回调为准。前端页面跳转到支付成功,并不能作为订单状态更新的最终依据。后端收到支付回调后,需要校验订单号、支付金额、支付状态,再更新订单数据。

Quartz 可以用于处理超时未支付订单。定时任务扫描待支付订单,如果超过指定时间仍未支付,则修改为已取消,并释放对应库存或占用状态。

九、Shiro权限控制:接口权限比页面权限更重要

账号设置、资料编辑、作品管理、内容分类、商品分类、订单管理、系统通知等功能,都涉及权限控制。Shiro 可以用于登录认证、角色权限和接口鉴权。

在前后端分离架构中,不能只依赖前端隐藏按钮来控制权限。即使页面不展示某个操作入口,接口仍然可能被直接请求。因此,后端必须进行接口级权限判断。

普通用户只能编辑自己的资料、管理自己的作品、查看自己的收藏和浏览记录。后台账号可以根据角色不同,管理内容分类、商品分类、订单数据、系统通知等内容。

权限模型可以基于用户、角色、权限进行设计。用户绑定角色,角色绑定权限,接口再根据权限标识进行校验。这样可以避免所有后台能力都集中在单一身份上。

十、Druid连接池与数据库索引优化

Druid 主要用于数据库连接池管理和 SQL 监控。仿小红书产品中,首页内容流、内容详情、评论列表、个人主页、商品列表、订单列表等接口都可能产生较多数据库访问。

数据库优化不能只依赖连接池,还需要合理设计索引。内容表可以给 user_id、category_id、status、create_time 建立索引。评论表可以给 post_id、root_id、create_time 建立索引。点赞、收藏、关注关系表需要建立联合索引。订单表需要给 user_id、order_no、status 建立索引。

如果首页内容流涉及多表聚合,不建议在高并发接口中做过多实时 join。可以将部分展示字段冗余到内容表或内容统计表中,例如作者昵称、头像、封面图、点赞数、收藏数等。冗余字段需要配合更新策略,避免长期不一致。

十一、多端数据互通:APP、小程序、H5共用后台

安卓 APP、苹果 APP、微信小程序和 H5 网页端共用同一套后台时,接口字段结构要保持稳定。不同端可以有不同页面样式,但内容、用户、评论、消息、订单等数据来源应保持一致。

例如用户在 H5 收藏了一篇内容,APP 打开同一篇内容时,收藏状态也应同步变化。用户在小程序完成订单支付后,APP 订单列表中也应展示最新状态。用户在 APP 已读私信后,H5 端未读数也要减少。

移动端响应式适配主要发生在前端,但后端需要提供足够的数据字段。瀑布流需要图片宽高,短视频需要封面和时长,商品详情需要价格和库存,个人主页需要作品数、关注数、粉丝数、获赞数。

阿里云短信可以用于验证码发送。验证码适合存入 Redis,并设置过期时间。用户登录成功后生成 Token,后续请求通过 Token 识别身份,再结合 Shiro 完成权限校验。

十二、定时任务在内容社区中的使用场景

Quartz 定时任务适合处理一些不需要同步完成的任务,例如浏览记录落库、热门搜索刷新、热门内容计算、订单超时关闭、搜索索引修复、消息状态清理等。

这些任务不能只关注是否执行,还要关注幂等性。任务重复执行时,不能导致订单重复取消、浏览数重复增加、索引重复写入异常或消息状态错乱。

下面是核心技术在仿小红书源码中的常见落点:

技术主要作用
Spring Boot后端接口、业务服务、模块组织
Redis热点缓存、验证码、未读数、互动计数、热门搜索
EasyES内容搜索、商品搜索、话题搜索
WebSocket单聊消息、在线推送、通知触达
Quartz订单关闭、缓存同步、浏览记录落库、索引修复
Shiro登录认证、角色权限、接口鉴权
Druid数据库连接池、SQL监控
对象存储图片、视频、封面资源存储
内容审核文本、图片、视频内容检测

十三、源码目录结构的拆分思路

仿小红书源码可以按照业务域和基础能力进行目录拆分,而不是把所有代码都堆在一个 service 中。

modules ├── content 图文、短视频、话题、分类、草稿 ├── user 用户资料、关注、粉丝、账号设置 ├── interact 点赞、评论、回复、收藏、浏览记录 ├── search EasyES索引、搜索记录、热门搜索 ├── im WebSocket、单聊、未读消息 ├── goods 商品分类、商品列表、商品详情 ├── order 购物车、订单、支付回调 ├── file 图片视频上传、对象存储 ├── audit 文本审核、图片审核、视频审核 ├── task Quartz定时任务 └── system Shiro权限、角色、菜单、配置

这种拆分方式可以让内容、互动、搜索、消息、订单、文件、审核、权限之间保持清晰边界。内容发布不直接处理 WebSocket 推送,搜索模块不直接修改内容状态,订单模块不依赖内容表结构,文件模块只负责资源上传和资源信息返回。

从技术角度看,仿小红书源码的稳定性主要取决于内容流、搜索流、互动流、消息流和订单流之间的协作方式。Redis 负责高频数据处理,EasyES 负责检索体验,WebSocket 负责实时消息,Quartz 负责异步任务,Shiro 负责权限边界,Druid 保障数据库连接稳定,对象存储和内容审核支撑图片视频内容链路。

多端界面适配过程笔记湖南宠友信息技术有限公司是一家专注社区交友类产品、企业即时通信软件开发,为企业提供即时通信工具、垂直类内容圈子,自主研发的业界知名友猫产品拥有广大的企业用户群体https://chongyou.info/1/product/xhs.html