基于 Redis 的幂等性设计:SpringBoot @Async 在高并发 MySQL 日志存储中的应用
一、问题描述
在高并发场景下,大量设备实时上报状态数据,需要异步保存到MySQL,同时需要解决幂等性校验和线程池耗尽问题。
二、解决方案
1. 幂等性控制
作用:确保同一请求无论执行多少次,结果都一致,避免重复处理。
实现方式:
- 唯一标识:设备ID + 时间戳组合
- Redis原子操作:SET NX EX实现原子校验
- 多级保障:Redis快速判断 + 数据库唯一索引 + 业务层查询确认
- 超时机制:设置合理过期时间,避免永久占用资源
2. 防止线程池耗尽
策略:
- 合理配置线程池:
- 核心线程数:CPU核心数×2
- 最大线程数:100
- 队列容量:500
- 拒绝策略:CallerRunsPolicy(压力返回调用方)
- 快速失败:幂等校验快速过滤重复请求
- 监控告警:建议添加线程池监控指标
3. 异步处理模式
CompletableFuture等待结果模式:
- 控制器等待异步操作完成后返回结果
- 设置超时时间(5秒)避免无限等待
- 超时返回HTTP 202状态码,提供状态查询接口
三、示例
1.Controller
@PostMapping("/{deviceId}/status")
public ResponseEntity<?> reportStatus(@PathVariable String deviceId,@RequestParam("timestamp") long timestamp,@RequestBody DeviceStatus status) {String requestId = "device:" + deviceId + ":status:" + timestamp;try {// 等待异步操作完成(最多5秒)deviceStatusService.processDeviceStatus(requestId, deviceId, timestamp, status).get(5, TimeUnit.SECONDS);return ResponseEntity.ok().build();} catch (TimeoutException e) {return ResponseEntity.accepted().header("X-Request-ID", requestId).build();} catch (Exception e) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();}
}
2.Service
@Async("deviceStatusExecutor")
public CompletableFuture<Void> processDeviceStatus(