You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

358 lines
16 KiB

1 month ago
# 性能优化
<cite>
**本文引用的文件**
- [CrmAppApplication.java](file://crm-app/src/main/java/com/crm/app/CrmAppApplication.java)
- [application.yml](file://crm-app/src/main/resources/application.yml)
- [AuthProperties.java](file://crm-auth/src/main/java/com/crm/auth/config/AuthProperties.java)
- [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
- [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java)
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
- [PageConverter.java](file://crm-base/src/main/java/com/crm/base/utils/PageConverter.java)
- [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java)
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
- [MinioConfig.java](file://crm-file/src/main/java/com/crm/file/config/MinioConfig.java)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本指南面向应用层面的性能优化,覆盖数据库查询、内存管理、线程池配置、HTTP层优化(压缩、缓存、连接池)、分页查询优化(以 PageConverter 为例)以及 JVM 调优与监控。文档结合代码仓库中的实际实现,给出可落地的策略与最佳实践,并附带可视化图示帮助理解。
## 项目结构
本项目采用多模块结构:
- crm-app:应用启动入口与全局配置
- crm-auth:认证授权与安全相关能力
- crm-base:通用基础能力(MyBatis-Plus、Redis、工具类、分页转换等)
- crm-file:文件服务(对象存储集成、上传下载、预览)
```mermaid
graph TB
subgraph "应用"
APP["crm-app<br/>启动与配置"]
end
subgraph "认证授权"
AUTH["crm-auth<br/>安全、鉴权、令牌、权限"]
end
subgraph "基础能力"
BASE["crm-base<br/>MyBatis-Plus、Redis、工具类"]
end
subgraph "文件服务"
FILE["crm-file<br/>对象存储、上传下载"]
end
APP --> AUTH
APP --> BASE
APP --> FILE
AUTH --> BASE
FILE --> BASE
```
**图表来源**
- [CrmAppApplication.java](file://crm-app/src/main/java/com/crm/app/CrmAppApplication.java)
- [application.yml](file://crm-app/src/main/resources/application.yml)
**章节来源**
- [CrmAppApplication.java](file://crm-app/src/main/java/com/crm/app/CrmAppApplication.java)
- [application.yml](file://crm-app/src/main/resources/application.yml)
## 核心组件
- 认证与令牌:JWT 过滤器、令牌服务、安全配置
- 数据访问:MyBatis-Plus 配置、通用 Service 基类
- 缓存:部门树缓存、Redis 配置
- 分页转换:PageConverter 将分页结果转换为统一 DTO
- 文件服务:MinIO 客户端与上传下载流程
**章节来源**
- [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java)
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
- [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java)
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
- [PageConverter.java](file://crm-base/src/main/java/com/crm/base/utils/PageConverter.java)
- [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java)
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
- [MinioConfig.java](file://crm-file/src/main/java/com/crm/file/config/MinioConfig.java)
## 架构总览
下图展示请求从进入 Spring Security 到数据访问与缓存的关键路径,体现认证、权限、分页与缓存的交互。
```mermaid
sequenceDiagram
participant Client as "客户端"
participant Filter as "JwtAuthenticationFilter"
participant SecCfg as "SecurityConfig"
participant TokenSvc as "TokenService"
participant Svc as "业务服务(BaseServiceImpl)"
participant DB as "数据库(MyBatis-Plus)"
participant Cache as "Redis/本地缓存(DeptTreeCache)"
Client->>Filter : "HTTP 请求(携带Token)"
Filter->>SecCfg : "校验白名单/放行规则"
Filter->>TokenSvc : "解析并验证Token"
TokenSvc-->>Filter : "用户上下文"
Filter-->>Client : "通过或拒绝"
Client->>Svc : "调用分页接口"
Svc->>DB : "分页查询(PageHelper/MP)"
DB-->>Svc : "分页结果"
Svc->>Cache : "可选读取部门树/字典等"
Cache-->>Svc : "缓存命中或未命中"
Svc-->>Client : "返回分页响应"
```
**图表来源**
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
- [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java)
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
## 详细组件分析
### 认证与令牌链路(JWT)
- 过滤器负责拦截请求、提取 Token、校验签名与过期时间,并将用户信息注入上下文
- 令牌服务提供生成、解析、刷新等能力
- 安全配置定义放行路径、异常处理、跨域等
```mermaid
classDiagram
class JwtAuthenticationFilter {
+doFilter(request, response, chain)
-validateToken(token)
-setAuthentication(context)
}
class TokenService {
+generateToken(user)
+parseToken(token)
+refreshToken(token)
-verifySignature(token)
}
class SecurityConfig {
+configure(http)
+permitAllPaths()
+exceptionHandling()
}
JwtAuthenticationFilter --> TokenService : "解析/校验"
JwtAuthenticationFilter --> SecurityConfig : "按规则放行"
```
**图表来源**
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
- [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java)
**章节来源**
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
- [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java)
### 数据访问与分页(MyBatis-Plus + BaseServiceImpl)
- MyBatis-Plus 提供分页插件与通用 Mapper/Service
- BaseServiceImpl 封装常用 CRUD 与分页逻辑,减少样板代码
- 建议配合索引、只取必要字段、避免 N+1 查询
```mermaid
flowchart TD
Start(["分页请求"]) --> BuildQuery["构建查询条件"]
BuildQuery --> ApplyPagination["应用分页参数"]
ApplyPagination --> ExecuteQuery["执行SQL(仅必要字段)"]
ExecuteQuery --> MapResult["映射为DTO/VO"]
MapResult --> ReturnResp["返回分页结果"]
```
**图表来源**
- [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java)
- [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java)
**章节来源**
- [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java)
- [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java)
### 分页转换(PageConverter)
- 将数据库分页对象转换为统一的分页 DTO,便于前端消费
- 建议:控制每页大小上限、避免大对象序列化、按需加载关联数据
```mermaid
flowchart TD
In(["原始分页对象"]) --> Validate["校验分页参数"]
Validate --> Convert["字段映射/类型转换"]
Convert --> Enrich["补充元数据(总数/页码)"]
Enrich --> Out(["标准分页响应"])
```
**图表来源**
- [PageConverter.java](file://crm-base/src/main/java/com/crm/base/utils/PageConverter.java)
**章节来源**
- [PageConverter.java](file://crm-base/src/main/java/com/crm/base/utils/PageConverter.java)
### 缓存(部门树与 Redis)
- 部门树缓存用于高频读场景,降低数据库压力
- Redis 配置用于分布式缓存与会话共享
```mermaid
classDiagram
class DeptTreeCache {
+getDeptTree()
-buildTree(depts)
-refreshIfNeeded()
}
class RedisConfig {
+redisTemplate()
+cacheManager()
}
DeptTreeCache ..> RedisConfig : "可选使用Redis"
```
**图表来源**
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
**章节来源**
- [DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
### 文件服务(MinIO)
- MinIO 客户端配置连接池、超时与重试
- FileApiImpl 封装上传、分片、下载与预览流程
```mermaid
sequenceDiagram
participant Client as "客户端"
participant FileApi as "FileApiImpl"
participant Minio as "MinIO客户端"
Client->>FileApi : "上传/下载请求"
FileApi->>Minio : "建立连接/读写对象"
Minio-->>FileApi : "流式响应/状态"
FileApi-->>Client : "返回结果/流"
```
**图表来源**
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
- [MinioConfig.java](file://crm-file/src/main/java/com/crm/file/config/MinioConfig.java)
**章节来源**
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
- [MinioConfig.java](file://crm-file/src/main/java/com/crm/file/config/MinioConfig.java)
## 依赖关系分析
- 认证模块依赖基础模块(工具、配置)
- 文件模块依赖基础模块(配置、工具)
- 启动模块聚合各功能模块
```mermaid
graph LR
APP["crm-app"] --> AUTH["crm-auth"]
APP --> BASE["crm-base"]
APP --> FILE["crm-file"]
AUTH --> BASE
FILE --> BASE
```
**图表来源**
- [CrmAppApplication.java](file://crm-app/src/main/java/com/crm/app/CrmAppApplication.java)
**章节来源**
- [CrmAppApplication.java](file://crm-app/src/main/java/com/crm/app/CrmAppApplication.java)
## 性能考量
### 应用层面优化
- 数据库查询优化
- 精准选择字段,避免 SELECT *
- 合理使用索引,关注慢查询与全表扫描
- 避免 N+1 查询,使用批量查询或 JOIN 替代循环查询
- 分页限制最大页大小,防止超大结果集
- 参考实现位置:[MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java)、[BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java)
- 内存管理
- 控制对象创建与复用,避免临时大对象
- 合理设置分页大小,减少一次性加载的数据量
- 及时释放资源(流、连接),避免内存泄漏
- 参考实现位置:[PageConverter.java](file://crm-base/src/main/java/com/crm/base/utils/PageConverter.java)
- 线程池配置
- Web 容器线程池:根据 CPU 核数与 IO 比例调整
- 异步任务线程池:区分 CPU 密集与 IO 密集任务
- 队列容量与拒绝策略:避免 OOM 与请求丢失
- 监控指标:活跃线程、队列长度、拒绝次数
### HTTP 层面优化
- 响应压缩
- 启用 GZIP 压缩,减少带宽占用
- 对静态资源与 JSON 响应进行压缩
- 缓存策略
- 浏览器缓存:合理设置 Cache-Control、ETag
- 服务端缓存:Redis/本地缓存热点数据(如部门树)
- 参考实现位置:[DeptTreeCache.java](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java)、[RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
- 连接池配置
- 数据库连接池:最小/最大连接数、空闲超时、获取超时
- HTTP 客户端连接池:最大连接数、连接超时、请求超时
- 参考实现位置:[application.yml](file://crm-app/src/main/resources/application.yml)、[MinioConfig.java](file://crm-file/src/main/java/com/crm/file/config/MinioConfig.java)
### 分页查询优化(以 PageConverter 为例)
- 限制每页大小,避免一次性返回过多数据
- 仅查询必要字段,减少序列化开销
- 对关联数据采用懒加载或分批加载
- 在缓存层命中后直接返回,减少数据库压力
- 参考实现位置:[PageConverter.java](file://crm-base/src/main/java/com/crm/base/utils/PageConverter.java)
### JVM 调优建议
- 堆内存配置
- 初始堆与最大堆:根据应用峰值与可用内存设定
- 新生代与老年代比例:默认通常较合理,必要时微调
- GC 策略
- 优先使用 G1GC 或 ZGC(JDK17+),降低停顿时间
- 观察 GC 日志,定位频繁 Full GC 的原因
- 监控指标
- 堆使用率、GC 次数与耗时、线程池活跃度、慢查询数量
- 使用 APM 与 Profiler(Arthas、VisualVM)定位瓶颈
### 性能测试与瓶颈定位
- 压测工具
- JMeter:模拟并发请求,观察吞吐与延迟
- wrk/ab:HTTP 层快速压测
- 定位技巧
- 开启慢查询日志,分析 SQL 执行计划
- 使用 Arthas 在线诊断方法耗时与锁竞争
- 检查线程栈,识别阻塞点与死锁
- 对比不同分页大小与缓存命中率的影响
## 故障排查指南
- 常见问题
- 高延迟:检查数据库慢查询、连接池耗尽、GC 停顿
- 内存溢出:排查大对象、未关闭流、缓存无界增长
- 认证失败:检查 Token 签名、过期时间、过滤器链顺序
- 排查步骤
- 查看应用日志与错误堆栈
- 采集 JVM 快照与线程 dump
- 分析数据库执行计划与索引使用情况
- 逐步缩小范围,隔离问题模块
**章节来源**
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
- [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java)
- [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
## 结论
通过合理的数据库查询优化、内存与线程池配置、HTTP 层压缩与缓存、以及 JVM 调优与监控,可以显著提升系统吞吐与稳定性。分页查询与缓存是常见瓶颈点,应重点优化。建议在上线前进行压测与性能基线评估,持续监控与迭代优化。
## 附录
- 关键配置参考
- 应用配置:[application.yml](file://crm-app/src/main/resources/application.yml)
- 认证属性:[AuthProperties.java](file://crm-auth/src/main/java/com/crm/auth/config/AuthProperties.java)
- 安全配置:[SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java)
- 数据访问:[MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java)
- 缓存配置:[RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java)
- 文件服务:[MinioConfig.java](file://crm-file/src/main/java/com/crm/file/config/MinioConfig.java)