趣享社项目整体架构搭建与技术栈选型深度解析

一、项目核心概述

趣享社是一个面向大学生群体的内容社区平台,定位类似于小红书。后端采用 Spring Boot 3.2 + MyBatis Plus + MySQL 8 + Redis 7 + RabbitMQ 3.12 为核心技术栈,构建了一套从用户认证、内容发布、Feed 流分发、AI 审核到搜索引擎同步的完整服务链路。

本项目并非简单的 CRUD 单体应用------它在架构设计上充分考虑了社区平台的高并发读写特点:点赞/收藏/浏览等高频计数组件使用 Redis Lua 脚本 + 分布式锁保证原子性;Feed 流推送采用推/拉/推拉结合三种策略适配不同量级博主;内容审核则设计了同步阻塞 + 异步 MQ 双模式以兼容不同场景。本文将从项目顶层视角,拆解其整体架构、技术选型背后的考量、模块划分以及基础设施搭建细节。

二、整体架构梳理

以下是项目的分层架构图(文本描述),清晰展示了从前端到后端再到中间件的完整调用链路:

复制代码
┌─────────────────────────────────────────────────────────────────────────┐
│                         前端层 (Vue 3 + Vite)                            │
│                    Nginx 反向代理 → API Gateway                         │
└─────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                      控制层 (Controller Layer)                           │
│  AuthController │ NoteController │ FeedController │ UserController      │
│  FollowController │ SearchController │ NotificationController ...       │
│                                                                         │
│  统一入口:@RateLimit注解限流 + JwtAuthenticationFilter认证 + 参数校验    │
└─────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                      服务层 (Service Layer)                              │
│  IAuthService │ INoteService │ IFeedService │ ICommentService            │
│  IUserService │ IFollowService │ INotificationService ...               │
│                                                                         │
│  核心设计:Redis计数缓存 + 分布式锁 + 事务同步器 + MQ异步投递           │
└─────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                      持久层 (Mapper Layer)                               │
│  NoteMapper │ UserMapper │ FeedPushLogMapper │ NoteReviewMapper ...     │
│  MyBatis Plus BaseMapper + 自定义XML SQL + LambdaQueryWrapper           │
└─────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                         基础设施层                                       │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐               │
│  │ MySQL 8  │  │ Redis 7  │  │RabbitMQ  │  │ ES(搜索) │               │
│  │ 主数据   │  │ 缓存/锁  │  │ 异步消息 │  │ 全文索引 │               │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘               │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐                             │
│  │ OSS存储  │  │ Caffeine  │  │ Redisson │                             │
│  │ 图片视频 │  │ 本地缓存  │  │ 分布式锁 │                             │
│  └──────────┘  └──────────┘  └──────────┘                             │
└─────────────────────────────────────────────────────────────────────────┘

包结构设计遵循经典的分层架构,核心划分如下:

复制代码
com.quxiangshe.backend
├── annotation/        # 自定义注解:@RateLimit
├── aspect/            # AOP切面:RateLimitAspect
├── common/            # 公共类:统一响应体R
├── component/         # 组件:SnowflakeIdGenerator、FeedPusher
├── config/            # 配置类:Security、RabbitMQ、Async、Redis、Oss...
├── consumer/          # MQ消费者:ReviewTaskConsumer、FeedPushConsumer...
├── controller/        # 控制器:14个Controller
├── dto/               # 数据传输对象:18个DTO
├── entity/            # 数据库实体:18个Entity
├── exception/         # 异常处理:GlobalExceptionHandler
├── mapper/            # MyBatis Mapper:18个Mapper
├── security/          # 安全相关:JwtAuthenticationFilter
├── service/           # 服务接口 + impl实现:46个类
│   └── sort/          # 排序策略:FullSortStrategy、BucketSortStrategy
├── task/              # 异步任务:ReviewAsyncTask
├── util/              # 工具类:Jwt、Password、RateLimiter、DistributedLock...
└── vo/                # 视图对象:NoteVO、UserVO、LoginVO、PageVO

三、核心方案落地实现

3.1 Spring Boot 3.2 启动类

项目的入口类 QuxiangsheApplication 十分简洁,但包含了几个关键注解:

java 复制代码
@SpringBootApplication
@MapperScan("com.quxiangshe.backend.mapper")
@EnableConfigurationProperties
@EnableScheduling
public class QuxiangsheApplication {
    public static void main(String[] args) {
        SpringApplication.run(QuxiangsheApplication.class, args);
    }
}
  • @MapperScan:自动扫描 MyBatis Plus 的 Mapper 接口,无需在每个 Mapper 上加 @Mapper 注解

  • @EnableScheduling:开启定时任务支持(如热门榜单定时刷新、浏览数异步回写 DB)

  • @EnableConfigurationProperties:启用 @ConfigurationProperties 绑定

3.2 三线程池隔离设计(AsyncConfig)

社区平台的不同异步任务对资源的需求截然不同,如果共用一个线程池,审核任务堆积会拖慢 Feed 推送,反之亦然。因此项目在 AsyncConfig 中定义了三个独立线程池:

java 复制代码
@Configuration
@EnableAsync
public class AsyncConfig {
​
    @Bean("pushExecutor")
    public Executor pushExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(200);
        executor.setThreadNamePrefix("push-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
​
    @Bean("reviewExecutor")
    public Executor reviewExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(3);
        executor.setMaxPoolSize(8);
        executor.setQueueCapacity(500);
        executor.setThreadNamePrefix("review-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
​
    @Bean("feedDistributeExecutor")
    public Executor feedDistributeExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("feed-dist-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

三个线程池的职责清晰:

线程池名称 核心/最大线程 队列容量 职责
pushExecutor 5/10 200 Feed 流推送,博主发笔记后推送给粉丝
reviewExecutor 3/8 500 AI 内容审核,队列容量大以应对突发审核
feedDistributeExecutor 2/5 100 智能分发,按粉丝活跃度优先级分批推送

所有线程池均采用 CallerRunsPolicy 拒绝策略------当队列满时由调用线程执行,保证任务不丢失。

四、多方案横向对比

4.1 框架选型:Spring Boot vs Spring Cloud

维度 Spring Boot 3.2 Spring Cloud
架构复杂度 单体/模块化,部署简单 微服务,需服务发现、配置中心、网关
运维成本 低,一个 JAR 即可运行 高,需维护注册中心、配置中心
团队规模要求 1-3 人即可 至少 5 人以上
性能开销 低,无 RPC 序列化损耗 有网络调用和序列化开销
适用场景 中小型项目、快速迭代 大型分布式系统

4.2 ORM 选型:MyBatis Plus vs JPA/Hibernate vs 原生 JDBC

维度 MyBatis Plus 3.5 JPA/Hibernate 原生 JDBC
SQL 可控性 高,支持自定义 SQL 低,自动生成 SQL 难以优化 最高
开发效率 高,BaseMapper 开箱即用 中,注解配置繁琐 低,大量模板代码
复杂查询支持 LambdaQueryWrapper 链式调用 JPQL/Criteria API 手写 SQL
社区生态 国内主流,文档丰富 国际主流 -

4.3 存储选型:MySQL vs MongoDB

维度 MySQL 8 MongoDB
事务支持 ACID 事务完善 4.0+ 支持多文档事务但性能差
关联查询 JOIN 能力强 需要 $lookup,性能受限
数据结构灵活性 固定 Schema Schema-less JSON 文档
运维成熟度 极高,DBA 生态完善 需要额外学习成本

五、项目选型原因

选择 Spring Boot 3.2 而非 Spring Cloud 的理由:趣享社项目当前处于早期快速迭代阶段,团队规模小,业务边界相对清晰。过早引入微服务架构会带来不必要的分布式事务、服务间通信延迟、运维复杂度等问题。Spring Boot 3.2 的单体模块化架构足够支撑十万级 DAU,未来当单点性能瓶颈出现时,再考虑垂直拆分到 Spring Cloud 也是顺滑的迁移路径------因为我们已经在代码层面按照 controller/service/mapper 做到了清晰的分层解耦。

选择 MyBatis Plus 而非 JPA 的理由 :内容社区的数据查询场景复杂多变------笔记列表需要多表 JOIN 用户信息、Feed 流需要复杂的分页游标查询、热门榜单需要聚合统计。JPA 的自动 SQL 生成在面对这些复杂查询时往往力不从心,而 MyBatis Plus 的 LambdaQueryWrapper 既提供了类型安全的链式查询,又保留了手写 SQL 的灵活性。NoteMapper.selectDiscoverNotesWithExclude() 这种需要排除已展示 ID 列表的查询,在 JPA 中实现会非常痛苦。

选择 MySQL 而非 MongoDB 的理由 :笔记、用户、关注关系、点赞记录之间存在大量关联查询。例如个人主页需要同时查询用户信息、笔记列表、获赞总数,在 MongoDB 中需要多次 $lookup,性能远不如 MySQL 的 JOIN。此外,我们使用 Flyway 做数据库版本管理,MySQL 的 DDL 事务在 8.0 版本已相当成熟。

选择 RabbitMQ 而非 Kafka 的理由:趣享社的消息量级目前并不需要 Kafka 的高吞吐能力。RabbitMQ 的灵活路由(Direct Exchange + DLX)、管理界面友好、Spring AMQP 集成成熟度高,在中小规模场景下是更务实的选择。六组业务队列(Feed 推送、私信、通知、邮件、视频转码、内容审核)清晰划分了消息域。

六、踩坑记录与问题解决

踩坑 1:Redisson 与 spring-boot-starter-data-redis 冲突

在引入 redisson-spring-boot-starter 后,启动时报 No qualifying bean of type 'RedisConnectionFactory'。原因是 Redisson starter 默认排除了 Spring Data Redis 的自动配置,但项目中部分代码仍依赖 StringRedisTemplate

解决方案:在 pom.xml 中显式排除 Redisson 自带的 Redis 依赖,保留 Spring Data Redis:

XML 复制代码
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.23.0</version>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </exclusion>
    </exclusions>
</dependency>

踩坑 2:Spring Boot 3.x 下 javax.* 迁移到 jakarta.*

Spring Boot 3.x 基于 Jakarta EE 9,所有 javax.servlet.* 包需要替换为 jakarta.servlet.*。在 JwtAuthenticationFilter 中使用了 jakarta.servlet.FilterChain,但在其他第三方依赖(如部分旧版 Knife4j)中仍有 javax 引用。最终引入了 knife4j-openapi3-jakarta-spring-boot-starter 的 Jakarta 适配版本解决。

踩坑 3:MyBatis Plus 乐观锁在 Spring Boot 3.2 下需要显式配置

MyBatis Plus 的 @Version 注解在 Spring Boot 3.2 默认不会自动注册乐观锁拦截器,需要手动配置:

java 复制代码
@Configuration
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

七、性能优化与高并发设计

1. 三级缓存体系:Caffeine 本地缓存(5-10 分钟)作为最热数据的第一道防线,Redis 作为二级缓存(热度数据 15 分钟),MySQL 作为数据真相源。本地缓存命中率可达 90%+,大幅降低了 Redis 的网络 IO。

2. Redis Pipeline 批量操作:Feed 流批量写入时使用 Redis Pipeline,将多次 Redis 命令打包一次网络往返发送,相比单条发送性能提升 5-10 倍。

3. 计数器的读写分离:点赞数、收藏数、浏览数等高频更新字段在 Redis 中维护实时值(Lua 脚本原子操作),数据库中的字段作为异步回写的备份。读取时优先 Redis,Redis 不可用时降级到 DB。这种设计将热点写操作的压力从 MySQL 转移到了 Redis。

4. 连接池优化 :HikariCP 连接池配置了 maximumPoolSize=20minimumIdle=5,配合 MySQL 的 max_connections=200,确保连接不会被耗尽。RabbitMQ 消费者配置了 ConcurrentConsumers=10MaxConcurrentConsumers=20,动态伸缩以应对消息量波动。

八、总结与后续迭代方向

趣享社项目通过 Spring Boot 3.2 + MyBatis Plus + Redis + RabbitMQ 的技术组合,在保证开发效率的同时,已经具备了一定的高并发处理能力。三线程池隔离设计确保了核心业务(内容审核、Feed 推送、智能分发)不会互相干扰。

后续迭代方向

  1. 服务拆分:当 DAU 突破 10 万后,拟将用户服务、笔记服务、Feed 服务拆分为独立微服务,使用 Spring Cloud Gateway 做统一网关

  2. 接入 Sentinels:引入阿里 Sentinel 做流量控制和熔断降级,替代当前自研的限流组件

  3. ES 搜索优化:目前只做了简单的笔记同步,后续需要接入 IK 分词器、拼音搜索、搜索建议

  4. 可观测性:集成 Prometheus + Grafana 做指标监控,SkyWalking 做链路追踪

  5. 灰度发布:使用 Nacos 做配置中心,支持功能开关和灰度策略

相关推荐
一个天蝎座 白勺 程序猿3 分钟前
MongoDB迁移新范式|从烟囱式孤岛到KES-AI融合架构
人工智能·mongodb·架构·kingbasees
AI 小老六20 分钟前
Agent Runtime 如何用 Session、Memory、User Profile 和 Skill 实现外部学习
服务器·人工智能·学习·ai·架构·自动化
程序边界23 分钟前
从烟囱到融合:一次MongoDB迁移引发的架构重构深思
mongodb·重构·架构
Asize26 分钟前
无状态 Stateless:大模型为什么记不住你是谁
javascript·人工智能·架构
echoVic36 分钟前
Agent 的会话为什么是一棵树,而不是一串消息
架构·agent
echoVic1 小时前
Plan 模式为什么不能只是一个权限开关
架构·agent
echoVic1 小时前
运行中的修改,到底什么时候生效
架构·agent
echoVic1 小时前
为什么 Agent 的每个请求,都要先拍一张快照
架构·agent
烬羽1 小时前
组件拆了,逻辑没拆——自定义 Hook 才是 React 业务逻辑的正当归属
react.js·架构·typescript
小月土星1 小时前
自定义业务 Hook:从零解剖一个 React + TypeScript Todo 应用:用金字塔思维看透前端架构
react.js·架构·前端框架