1
This commit is contained in:
105
Redis清理说明.md
Normal file
105
Redis清理说明.md
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
# Redis键清理功能说明
|
||||||
|
|
||||||
|
## 功能概述
|
||||||
|
本功能用于清理Redis中超过93天(3个月)的旧数据,支持两种类型的键:
|
||||||
|
1. **tag键**:格式为 `tag:hash值:YYYY-MM-DD HH`,例如 `tag:01381d95e4936f1f3fe643bba2171894:2025-01-12 00`
|
||||||
|
2. **jd:refresh:tag键**:格式为 `jd:refresh:tag:hash值:YYYY-MM-DD HH:mm:ss` 或 `jd:refresh:tag:YYYY-MM-DD HH:mm:ss`
|
||||||
|
|
||||||
|
## 使用方式
|
||||||
|
|
||||||
|
### 方式一:手动调用API接口(推荐)
|
||||||
|
|
||||||
|
发送POST请求到:`http://your-server:port/jd/cleanRedisData`
|
||||||
|
|
||||||
|
**请求示例:**
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:8080/jd/cleanRedisData \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"skey": "2192057370ef8140c201079969c956a3"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应示例:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "Redis清理任务已执行完成,详情请查看日志"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 方式二:使用Postman等工具
|
||||||
|
|
||||||
|
1. 创建新的POST请求
|
||||||
|
2. URL: `http://localhost:8080/jd/cleanRedisData`
|
||||||
|
3. Headers: `Content-Type: application/json`
|
||||||
|
4. Body (raw JSON):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"skey": "2192057370ef8140c201079969c956a3"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 方式三:自动定时执行
|
||||||
|
|
||||||
|
系统已配置定时任务,每天凌晨3点自动执行清理:
|
||||||
|
- **tag键清理**:每天凌晨3点执行(cron: `0 0 3 * * ?`)
|
||||||
|
- **jd:refresh:tag键清理**:每月1日11:45执行(cron: `0 45 11 * * ?`)
|
||||||
|
|
||||||
|
## 清理规则
|
||||||
|
|
||||||
|
- **截止日期**:当前时间减去93天
|
||||||
|
- **清理对象**:所有早于截止日期的键
|
||||||
|
- **安全性**:只删除符合特定格式且过期的键
|
||||||
|
|
||||||
|
例如:
|
||||||
|
- 当前时间:2025-10-27
|
||||||
|
- 截止日期:2025-07-26
|
||||||
|
- 将删除:2025-07-26之前的所有符合格式的键
|
||||||
|
- 保留:2025-07-26及之后的键
|
||||||
|
|
||||||
|
## 日志查看
|
||||||
|
|
||||||
|
清理任务执行时会输出详细日志,可通过以下日志查看执行情况:
|
||||||
|
|
||||||
|
```
|
||||||
|
开始清理93天前的tag键数据,截止时间:YYYY-MM-DD HH:mm:ss
|
||||||
|
找到 X 个tag相关的键
|
||||||
|
已删除 100 个过期的tag键
|
||||||
|
已删除 200 个过期的tag键
|
||||||
|
...
|
||||||
|
tag键清理完成,共删除 X 个过期键
|
||||||
|
```
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. **skey验证**:调用接口需要提供正确的skey(密钥)
|
||||||
|
2. **执行时间**:建议在业务低峰期手动执行清理,避免影响性能
|
||||||
|
3. **备份建议**:首次执行前建议备份Redis数据
|
||||||
|
4. **监控日志**:执行后及时查看日志,确认清理结果
|
||||||
|
|
||||||
|
## 代码位置
|
||||||
|
|
||||||
|
- **清理逻辑**:`d:\code\jd\src\main\java\cn\van\business\util\JDScheduleJob.java`
|
||||||
|
- `cleanOldTagRedisData()` - 清理tag键
|
||||||
|
- `cleanOldRedisHashData()` - 清理jd:refresh:tag键
|
||||||
|
- `manualCleanOldRedisData()` - 手动触发清理
|
||||||
|
|
||||||
|
- **API接口**:`d:\code\jd\src\main\java\cn\van\business\controller\jd\JDInnerController.java`
|
||||||
|
- `/jd/cleanRedisData` - POST接口
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
**Q: 如何查看当前Redis中有多少符合条件的键?**
|
||||||
|
A: 可以使用Redis命令:
|
||||||
|
```bash
|
||||||
|
redis-cli KEYS "tag:*" | wc -l
|
||||||
|
redis-cli KEYS "jd:refresh:tag:*" | wc -l
|
||||||
|
```
|
||||||
|
|
||||||
|
**Q: 清理后可以恢复吗?**
|
||||||
|
A: 不可以,删除操作是不可逆的,请谨慎操作。
|
||||||
|
|
||||||
|
**Q: 如果需要调整清理天数怎么办?**
|
||||||
|
A: 修改 `JDScheduleJob.java` 中的 `minusDays(93)` 参数,例如改为 `minusDays(60)` 清理60天前的数据。
|
||||||
|
|
||||||
@@ -3,6 +3,7 @@ package cn.van.business.controller.jd;
|
|||||||
import cn.van.business.model.pl.TaobaoComment;
|
import cn.van.business.model.pl.TaobaoComment;
|
||||||
import cn.van.business.repository.TaobaoCommentRepository;
|
import cn.van.business.repository.TaobaoCommentRepository;
|
||||||
import cn.van.business.util.JDProductService;
|
import cn.van.business.util.JDProductService;
|
||||||
|
import cn.van.business.util.JDScheduleJob;
|
||||||
import cn.van.business.util.JDUtil;
|
import cn.van.business.util.JDUtil;
|
||||||
import cn.van.business.repository.CommentRepository;
|
import cn.van.business.repository.CommentRepository;
|
||||||
import cn.van.business.model.pl.Comment;
|
import cn.van.business.model.pl.Comment;
|
||||||
@@ -32,13 +33,15 @@ public class JDInnerController {
|
|||||||
|
|
||||||
private final JDProductService jdProductService;
|
private final JDProductService jdProductService;
|
||||||
private final JDUtil jdUtil;
|
private final JDUtil jdUtil;
|
||||||
|
private final JDScheduleJob jdScheduleJob;
|
||||||
private final CommentRepository commentRepository;
|
private final CommentRepository commentRepository;
|
||||||
private final TaobaoCommentRepository taobaoCommentRepository;
|
private final TaobaoCommentRepository taobaoCommentRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public JDInnerController(JDProductService jdProductService, JDUtil jdUtil, CommentRepository commentRepository, TaobaoCommentRepository taobaoCommentRepository) {
|
public JDInnerController(JDProductService jdProductService, JDUtil jdUtil, JDScheduleJob jdScheduleJob, CommentRepository commentRepository, TaobaoCommentRepository taobaoCommentRepository) {
|
||||||
this.jdProductService = jdProductService;
|
this.jdProductService = jdProductService;
|
||||||
this.jdUtil = jdUtil;
|
this.jdUtil = jdUtil;
|
||||||
|
this.jdScheduleJob = jdScheduleJob;
|
||||||
this.commentRepository = commentRepository;
|
this.commentRepository = commentRepository;
|
||||||
this.taobaoCommentRepository = taobaoCommentRepository;
|
this.taobaoCommentRepository = taobaoCommentRepository;
|
||||||
}
|
}
|
||||||
@@ -381,6 +384,30 @@ public class JDInnerController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动清理Redis中超过93天的旧数据
|
||||||
|
* 请求参数:{ skey }
|
||||||
|
* 返回:{ message, success }
|
||||||
|
*/
|
||||||
|
@PostMapping("/cleanRedisData")
|
||||||
|
public Object cleanRedisData(@RequestBody Map<String, Object> body) {
|
||||||
|
String skey = body.get("skey") != null ? String.valueOf(body.get("skey")) : null;
|
||||||
|
if (checkSkey(skey)) {
|
||||||
|
return error("invalid skey");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
logger.info("手动触发Redis清理任务");
|
||||||
|
jdScheduleJob.manualCleanOldRedisData();
|
||||||
|
JSONObject resp = new JSONObject();
|
||||||
|
resp.put("success", true);
|
||||||
|
resp.put("message", "Redis清理任务已执行完成,详情请查看日志");
|
||||||
|
return resp;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("cleanRedisData error", e);
|
||||||
|
return error("cleanRedisData failed: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static JSONObject error(String msg) {
|
private static JSONObject error(String msg) {
|
||||||
JSONObject o = new JSONObject();
|
JSONObject o = new JSONObject();
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import org.springframework.scheduling.annotation.Scheduled;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
@@ -655,4 +654,74 @@ public void cleanOldRedisHashData() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理tag:hash:时间 格式的Redis键(按小时),删除93天前的数据
|
||||||
|
* 可以手动调用或定时执行
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点执行
|
||||||
|
public void cleanOldTagRedisData() {
|
||||||
|
try {
|
||||||
|
// 获取93天前的时间
|
||||||
|
LocalDateTime ninetyThreeDaysAgo = LocalDateTime.now().minusDays(93);
|
||||||
|
int deletedCount = 0;
|
||||||
|
|
||||||
|
logger.info("开始清理93天前的tag键数据,截止时间:{}", ninetyThreeDaysAgo.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||||
|
|
||||||
|
// 获取所有以"tag:"开头的键
|
||||||
|
Set<String> tagKeys = redisTemplate.keys("tag:*");
|
||||||
|
|
||||||
|
if (tagKeys != null && !tagKeys.isEmpty()) {
|
||||||
|
logger.info("找到 {} 个tag相关的键", tagKeys.size());
|
||||||
|
|
||||||
|
for (String key : tagKeys) {
|
||||||
|
try {
|
||||||
|
// 处理格式:tag:hash值:YYYY-MM-DD HH
|
||||||
|
// 例如:tag:01381d95e4936f1f3fe643bba2171894:2025-01-12 00
|
||||||
|
if (key.matches("tag:[a-f0-9]{32}:[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}")) {
|
||||||
|
// 提取时间部分(最后一个冒号之后)
|
||||||
|
String timePart = key.substring(key.lastIndexOf(":") + 1);
|
||||||
|
|
||||||
|
LocalDateTime time;
|
||||||
|
try {
|
||||||
|
// 解析为小时级别的时间格式 yyyy-MM-dd HH
|
||||||
|
time = LocalDateTime.parse(timePart + ":00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
logger.warn("无法解析Redis键时间:{},时间部分:{}", key, timePart);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否在93天前
|
||||||
|
if (time.isBefore(ninetyThreeDaysAgo)) {
|
||||||
|
redisTemplate.delete(key);
|
||||||
|
deletedCount++;
|
||||||
|
if (deletedCount % 100 == 0) {
|
||||||
|
logger.info("已删除 {} 个过期的tag键", deletedCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.warn("解析Redis tag键时间失败:{}", key, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("tag键清理完成,共删除 {} 个过期键", deletedCount);
|
||||||
|
} else {
|
||||||
|
logger.info("未找到tag相关的键");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("清理tag Redis数据时发生错误", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动执行清理方法(通过接口调用)
|
||||||
|
* 清理所有超过93天的tag键和jd:refresh:tag键
|
||||||
|
*/
|
||||||
|
public void manualCleanOldRedisData() {
|
||||||
|
logger.info("=== 手动触发Redis键清理 ===");
|
||||||
|
cleanOldTagRedisData();
|
||||||
|
cleanOldRedisHashData();
|
||||||
|
logger.info("=== Redis键清理完成 ===");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user