257 lines
7.1 KiB
Markdown
257 lines
7.1 KiB
Markdown
# 🚀 文件下载缓存机制说明
|
|
|
|
## 📋 功能概述
|
|
|
|
为了提高文件下载性能,减少对MinIO存储的重复请求,系统实现了基于内存的文件缓存机制。该机制具有以下特性:
|
|
|
|
### ✨ 核心特性
|
|
- **LRU淘汰策略**: 当缓存空间不足时,自动淘汰最久未访问的文件
|
|
- **智能大小控制**: 只缓存小于50MB的文件,避免内存溢出
|
|
- **过期时间管理**: 缓存条目具有30分钟的有效期
|
|
- **并发安全**: 使用读写锁保证多线程环境下的数据一致性
|
|
- **统计监控**: 提供缓存命中率、大小等统计信息
|
|
- **配置化管理**: 所有缓存参数可通过配置文件调整
|
|
|
|
## 🔧 配置参数
|
|
|
|
### 基础配置
|
|
在 `application.yml` 或 `application-dev.yml` 中添加以下配置:
|
|
|
|
```yaml
|
|
system:
|
|
file-cache:
|
|
# 是否启用文件缓存
|
|
enabled: true
|
|
|
|
# 最大缓存文件数量
|
|
max-cache-size: 100
|
|
|
|
# 最大缓存大小(字节)- 500MB
|
|
max-cache-size-bytes: 524288000
|
|
|
|
# 缓存过期时间(毫秒)- 30分钟
|
|
expire-time-ms: 1800000
|
|
|
|
# 最大缓存单个文件大小(字节)- 50MB
|
|
max-single-file-size: 52428800
|
|
|
|
# LRU淘汰比例(百分比)
|
|
evict-ratio: 20
|
|
|
|
# 是否启用缓存统计
|
|
enable-stats: true
|
|
|
|
# 缓存清理间隔(毫秒)- 5分钟
|
|
cleanup-interval-ms: 300000
|
|
```
|
|
|
|
### 参数说明
|
|
|
|
| 参数名 | 默认值 | 说明 |
|
|
|--------|--------|------|
|
|
| `enabled` | `true` | 是否启用文件缓存功能 |
|
|
| `max-cache-size` | `100` | 缓存的最大文件数量 |
|
|
| `max-cache-size-bytes` | `524288000` | 缓存的最大总大小(500MB) |
|
|
| `expire-time-ms` | `1800000` | 缓存条目的过期时间(30分钟) |
|
|
| `max-single-file-size` | `52428800` | 单个文件的最大缓存大小(50MB) |
|
|
| `evict-ratio` | `20` | LRU淘汰时移除的条目比例(20%) |
|
|
| `enable-stats` | `true` | 是否启用缓存统计功能 |
|
|
| `cleanup-interval-ms` | `300000` | 自动清理过期条目的间隔(5分钟) |
|
|
|
|
## 🚀 使用方法
|
|
|
|
### 1. 文件下载
|
|
缓存机制对用户透明,正常使用文件下载接口即可:
|
|
|
|
```http
|
|
GET /resource/oss/download/{ossId}
|
|
```
|
|
|
|
系统会自动:
|
|
1. 检查缓存中是否存在该文件
|
|
2. 如果存在且未过期,直接从缓存返回
|
|
3. 如果不存在或已过期,从MinIO下载并缓存
|
|
|
|
### 2. 缓存管理API
|
|
|
|
#### 获取缓存统计信息
|
|
```http
|
|
GET /resource/oss/cache/stats
|
|
```
|
|
|
|
返回示例:
|
|
```json
|
|
{
|
|
"code": 200,
|
|
"msg": "操作成功",
|
|
"data": {
|
|
"cacheSize": 25,
|
|
"currentCacheSizeBytes": 104857600,
|
|
"maxCacheSizeBytes": 524288000,
|
|
"cacheHits": 150,
|
|
"cacheMisses": 50,
|
|
"hitRate": "75.00%"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 清空缓存
|
|
```http
|
|
DELETE /resource/oss/cache/clear
|
|
```
|
|
|
|
#### 移除指定文件缓存
|
|
```http
|
|
DELETE /resource/oss/cache/{ossId}
|
|
```
|
|
|
|
## 📊 性能优化
|
|
|
|
### 缓存命中率优化
|
|
- **增加缓存大小**: 对于内存充足的环境,适当增加 `max-cache-size-bytes`
|
|
- **调整文件数量**: 对于小文件较多的场景,增加 `max-cache-size`
|
|
- **优化过期时间**: 根据文件访问频率调整 `expire-time-ms`
|
|
|
|
### 内存使用优化
|
|
- **控制单个文件大小**: 根据实际情况调整 `max-single-file-size`
|
|
- **调整淘汰策略**: 通过 `evict-ratio` 控制淘汰比例
|
|
- **定期清理**: 设置合适的 `cleanup-interval-ms`
|
|
|
|
### 监控指标
|
|
- **缓存命中率**: 目标 > 70%
|
|
- **内存使用率**: 监控缓存占用的内存大小
|
|
- **响应时间**: 缓存命中时的下载速度应显著提升
|
|
|
|
## 🔍 技术实现
|
|
|
|
### 核心组件
|
|
|
|
#### 1. 缓存条目类 (CacheEntry)
|
|
```java
|
|
private class CacheEntry {
|
|
private final byte[] data; // 文件数据
|
|
private final long size; // 文件大小
|
|
private final long createTime; // 创建时间
|
|
private final long lastAccessTime; // 最后访问时间
|
|
private final String contentType; // 内容类型
|
|
}
|
|
```
|
|
|
|
#### 2. LRU淘汰策略
|
|
```java
|
|
private void evictLRUEntries() {
|
|
// 按最后访问时间排序
|
|
List<Map.Entry<Long, CacheEntry>> entries = new ArrayList<>(fileCache.entrySet());
|
|
entries.sort((e1, e2) -> Long.compare(e1.getValue().getLastAccessTime(), e2.getValue().getLastAccessTime()));
|
|
|
|
// 淘汰最旧的20%条目
|
|
int evictCount = Math.max(1, entries.size() / 5);
|
|
for (int i = 0; i < evictCount && i < entries.size(); i++) {
|
|
Map.Entry<Long, CacheEntry> entry = entries.get(i);
|
|
fileCache.remove(entry.getKey());
|
|
currentCacheSize.addAndGet(-entry.getValue().getSize());
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 3. 并发安全
|
|
- 使用 `ConcurrentHashMap` 存储缓存数据
|
|
- 使用 `ReentrantReadWriteLock` 保证读写安全
|
|
- 使用 `AtomicLong` 统计缓存大小和命中率
|
|
|
|
### 工作流程
|
|
|
|
1. **文件下载请求**
|
|
```
|
|
用户请求 → 权限验证 → 检查缓存 → 返回文件
|
|
```
|
|
|
|
2. **缓存命中流程**
|
|
```
|
|
检查缓存 → 验证过期 → 直接返回 → 更新统计
|
|
```
|
|
|
|
3. **缓存未命中流程**
|
|
```
|
|
检查缓存 → 从MinIO下载 → 添加到缓存 → 返回文件
|
|
```
|
|
|
|
4. **缓存管理流程**
|
|
```
|
|
检查大小限制 → LRU淘汰 → 清理过期 → 添加新条目
|
|
```
|
|
|
|
## ⚠️ 注意事项
|
|
|
|
### 1. 内存管理
|
|
- 缓存会占用JVM堆内存,需要合理配置缓存大小
|
|
- 建议监控应用的内存使用情况
|
|
- 大文件不会被缓存,避免内存溢出
|
|
|
|
### 2. 数据一致性
|
|
- 缓存的文件数据可能与MinIO中的文件不同步
|
|
- 如果需要最新数据,可以手动清除缓存
|
|
- 建议在文件更新后清除相关缓存
|
|
|
|
### 3. 性能考虑
|
|
- 缓存命中时响应速度显著提升
|
|
- 缓存未命中时会有轻微的性能开销(用于缓存数据)
|
|
- 建议根据实际访问模式优化缓存参数
|
|
|
|
### 4. 安全考虑
|
|
- 缓存数据存储在内存中,应用重启后会丢失
|
|
- 敏感文件建议设置较短的过期时间
|
|
- 可以通过API手动管理缓存
|
|
|
|
## 🔧 故障排查
|
|
|
|
### 常见问题
|
|
|
|
1. **缓存命中率低**
|
|
- 检查缓存大小配置是否合理
|
|
- 分析文件访问模式
|
|
- 调整过期时间
|
|
|
|
2. **内存使用过高**
|
|
- 减少缓存大小限制
|
|
- 降低单个文件大小限制
|
|
- 增加淘汰比例
|
|
|
|
3. **缓存不生效**
|
|
- 检查 `enabled` 配置是否为 `true`
|
|
- 确认文件大小是否超过限制
|
|
- 查看日志中的缓存相关信息
|
|
|
|
### 监控建议
|
|
|
|
1. **定期检查缓存统计**
|
|
```bash
|
|
curl -X GET "http://localhost:8080/resource/oss/cache/stats"
|
|
```
|
|
|
|
2. **监控应用内存使用**
|
|
```bash
|
|
jstat -gc <pid> 1000
|
|
```
|
|
|
|
3. **查看缓存相关日志**
|
|
```bash
|
|
tail -f logs/application.log | grep "cache"
|
|
```
|
|
|
|
## 📈 性能测试
|
|
|
|
### 测试场景
|
|
1. **首次下载**: 从MinIO下载并缓存
|
|
2. **缓存命中**: 从内存直接返回
|
|
3. **并发下载**: 多用户同时下载同一文件
|
|
4. **大文件下载**: 超过缓存大小限制的文件
|
|
|
|
### 预期性能提升
|
|
- **缓存命中时**: 响应时间减少 80-90%
|
|
- **并发访问**: 显著减少MinIO压力
|
|
- **整体性能**: 平均下载速度提升 60-80%
|
|
|
|
---
|
|
|
|
**📝 维护说明**: 本文档基于文件缓存机制的实现,如需修改缓存策略或参数,请同步更新相关代码和配置。 |