Redis定時監(jiān)控與數據處理的實踐指南
1. 背景與需求分析
1.1 原始需求
我們有一個 LogMediaAdIdCache 類,用于緩存廣告位 ID,并定期從 Redis 刷新數據。原始實現(xiàn)使用 Set 存儲數據,結構如下:
SET logscraping:mediaAdId [id1, id2, id3, ...]
但隨著業(yè)務發(fā)展,我們需要存儲更多元信息(如廣告位名稱、狀態(tài)、更新時間等),僅用 Set 已無法滿足需求。
1.2 新需求
- 存儲結構化數據:每個廣告位 ID 需要關聯(lián)額外信息(如
name,status,updateTime)。 - 高效查詢:快速獲取某個廣告位的詳細信息。
- 定時監(jiān)控:每10秒檢查 Redis 數據變化,確保緩存一致性。
因此,我們決定將數據結構從 Set 改為 Hash:
HASH logscraping:mediaAdId
id1 -> { "name": "廣告位1", "status": "active" }
id2 -> { "name": "廣告位2", "status": "inactive" }
2. Redis 數據結構選型:Set vs. Hash
| 特性 | Set | Hash |
|---|---|---|
| 存儲方式 | 無序唯一集合 | 鍵值對存儲(field-value) |
| 適用場景 | 去重、集合運算(交集、并集) | 結構化數據,需存儲額外屬性 |
| 查詢效率 | O(1) 判斷元素是否存在 | O(1) 按 field 查詢 value |
| 擴展性 | 只能存儲單一值 | 可存儲復雜對象(JSON、Map) |
結論:
- 如果僅需存儲 ID 并判斷是否存在,Set 更高效。
- 如果需要存儲額外信息(如廣告位詳情),Hash 更合適。
3. 代碼改造:從 Set 遷移到 Hash
3.1 改造后的 LogMediaAdIdCache
@Component
@Slf4j
@RequiredArgsConstructor
public class LogMediaAdIdCache {
private final RedisTemplate<String, String> redisTemplate;
private volatile Set<Long> cachedLogMediaAdIds = Collections.emptySet();
public static final String LOG_REDIS_KEY = "logscraping:mediaAdId";
@PostConstruct
public void init() {
refreshCache();
}
@Scheduled(fixedRate = 5 * 1000) // 每5秒刷新一次
public void refreshCache() {
try {
Map<Object, Object> idMap = redisTemplate.opsForHash().entries(LOG_REDIS_KEY);
if (idMap != null) {
Set<Long> newCache = idMap.keySet().stream()
.map(key -> Long.valueOf(key.toString()))
.collect(Collectors.toSet());
this.cachedLogMediaAdIds = newCache;
log.info("廣告位ID緩存刷新成功,數量: {}", newCache.size());
}
} catch (Exception e) {
log.error("刷新廣告位ID緩存失敗", e);
}
}
public Set<Long> getLogMediaAdIds() {
return Collections.unmodifiableSet(cachedLogMediaAdIds);
}
public boolean contains(Long mediaAdId) {
return cachedLogMediaAdIds.contains(mediaAdId);
}
// 新增方法:獲取廣告位詳情
public String getAdInfo(Long mediaAdId) {
return redisTemplate.<String, String>opsForHash().get(LOG_REDIS_KEY, mediaAdId.toString());
}
// 新增方法:更新廣告位信息
public void updateAdInfo(Long mediaAdId, String info) {
redisTemplate.opsForHash().put(LOG_REDIS_KEY, mediaAdId.toString(), info);
refreshCache(); // 立即刷新緩存
}
}
3.2 主要改進點
- 改用
opsForHash()操作 Redis Hash,支持結構化存儲。 - 新增
getAdInfo()方法,按廣告位 ID 查詢詳情。 - 新增
updateAdInfo()方法,支持動態(tài)更新數據。
4. 定時任務優(yōu)化:每10秒監(jiān)控 Redis 數據
4.1 新增 LogStatsMonitorJob
@Component
@Slf4j
@RequiredArgsConstructor
public class LogStatsMonitorJob {
private final RedisTemplate<String, String> redisTemplate;
private static final String LOG_STATS_KEY = "log:stats:1635474646";
@Scheduled(fixedRate = 10 * 1000) // 每10秒執(zhí)行一次
public void monitorLogStats() {
String currentTimeKey = getFormattedTime();
String fullKey = LOG_STATS_KEY + ":" + currentTimeKey;
try {
Map<Object, Object> stats = redisTemplate.opsForHash().entries(fullKey);
if (stats == null || stats.isEmpty()) {
log.warn("未找到統(tǒng)計信息: {}", fullKey);
return;
}
log.info("----- 統(tǒng)計信息監(jiān)控(Key: {})-----", fullKey);
stats.forEach((field, value) ->
log.info("{}: {}", field, value));
// 業(yè)務處理示例
int total = Integer.parseInt(stats.getOrDefault("total", "0").toString());
if (total > 1000) {
log.warn("警告:數據量過大({}條)", total);
}
} catch (Exception e) {
log.error("監(jiān)控統(tǒng)計信息失敗", e);
}
}
private String getFormattedTime() {
// 生成格式化的時間戳,如 20250609175050
return LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
}
}
4.2 功能說明
- 定時任務:每10秒檢查 Redis Hash 數據。
- 動態(tài) Key:支持按時間戳生成 Key(如 log:stats:1635474646:20250609175050)。
- 異常處理:捕獲 Redis 操作異常,避免任務中斷。
- 業(yè)務告警:數據量超過閾值時觸發(fā)告警。
5. 完整代碼實現(xiàn)
5.1 LogMediaAdIdCache(改造后)
(見上文 3.1 節(jié))
5.2 LogStatsMonitorJob(新增)
(見上文 4.1 節(jié))
5.3 配置類(可選)
@Configuration
@EnableScheduling
public class SchedulingConfig {
// 啟用定時任務
}
6. 總結與最佳實踐
6.1 關鍵改進
- 數據結構升級:從 Set → Hash,支持結構化存儲。
- 定時任務優(yōu)化:每10秒監(jiān)控數據,確保實時性。
- 代碼健壯性:異常處理 + 日志記錄。
6.2 最佳實踐
- 合理選擇數據結構:根據業(yè)務場景選擇 Set / Hash / ZSet 等。
- 動態(tài) Key 設計:如時間戳、業(yè)務ID等,方便數據分區(qū)。
- 定時任務調優(yōu):
- 短周期(如10s)適合實時監(jiān)控。
- 長周期(如1h)適合批量處理。
- 異常處理:避免因 Redis 異常導致任務崩潰。
6.3 后續(xù)優(yōu)化方向
- 數據分片:若數據量過大,可采用分片存儲。
- 分布式鎖:避免多實例任務重復執(zhí)行。
- 數據過期策略:設置 TTL 自動清理舊數據。
結語
本文通過一個實際案例,演示了如何將 Redis 數據結構從 Set 遷移到 Hash,并實現(xiàn)高效定時監(jiān)控。合理的數據結構選擇 + 定時任務優(yōu)化,可以顯著提升系統(tǒng)性能和可維護性。
以上就是Redis定時監(jiān)控與數據處理實踐指南的詳細內容,更多關于Redis定時監(jiān)控與數據處理的資料請關注腳本之家其它相關文章!
相關文章
redis cluster支持pipeline的實現(xiàn)思路
本文給大家介紹redis cluster支持pipeline的實現(xiàn)思路,在 cluster 上執(zhí)行 pipeline 可能會由于 redis 節(jié)點擴縮容 中途 redirection 切換連接導致結果丟失,具體細節(jié)問題請參考下本文2021-06-06

