Redis定時(shí)監(jiān)控與數(shù)據(jù)處理的實(shí)踐指南
1. 背景與需求分析
1.1 原始需求
我們有一個(gè) LogMediaAdIdCache
類,用于緩存廣告位 ID,并定期從 Redis 刷新數(shù)據(jù)。原始實(shí)現(xiàn)使用 Set 存儲(chǔ)數(shù)據(jù),結(jié)構(gòu)如下:
SET logscraping:mediaAdId [id1, id2, id3, ...]
但隨著業(yè)務(wù)發(fā)展,我們需要存儲(chǔ)更多元信息(如廣告位名稱、狀態(tài)、更新時(shí)間等),僅用 Set 已無(wú)法滿足需求。
1.2 新需求
- 存儲(chǔ)結(jié)構(gòu)化數(shù)據(jù):每個(gè)廣告位 ID 需要關(guān)聯(lián)額外信息(如
name
,status
,updateTime
)。 - 高效查詢:快速獲取某個(gè)廣告位的詳細(xì)信息。
- 定時(shí)監(jiān)控:每10秒檢查 Redis 數(shù)據(jù)變化,確保緩存一致性。
因此,我們決定將數(shù)據(jù)結(jié)構(gòu)從 Set 改為 Hash:
HASH logscraping:mediaAdId id1 -> { "name": "廣告位1", "status": "active" } id2 -> { "name": "廣告位2", "status": "inactive" }
2. Redis 數(shù)據(jù)結(jié)構(gòu)選型:Set vs. Hash
特性 | Set | Hash |
---|---|---|
存儲(chǔ)方式 | 無(wú)序唯一集合 | 鍵值對(duì)存儲(chǔ)(field-value) |
適用場(chǎng)景 | 去重、集合運(yùn)算(交集、并集) | 結(jié)構(gòu)化數(shù)據(jù),需存儲(chǔ)額外屬性 |
查詢效率 | O(1) 判斷元素是否存在 | O(1) 按 field 查詢 value |
擴(kuò)展性 | 只能存儲(chǔ)單一值 | 可存儲(chǔ)復(fù)雜對(duì)象(JSON、Map) |
結(jié)論:
- 如果僅需存儲(chǔ) ID 并判斷是否存在,Set 更高效。
- 如果需要存儲(chǔ)額外信息(如廣告位詳情),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緩存刷新成功,數(shù)量: {}", 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 主要改進(jìn)點(diǎn)
- 改用
opsForHash()
操作 Redis Hash,支持結(jié)構(gòu)化存儲(chǔ)。 - 新增
getAdInfo()
方法,按廣告位 ID 查詢?cè)斍椤?/li> - 新增
updateAdInfo()
方法,支持動(dòng)態(tài)更新數(shù)據(jù)。
4. 定時(shí)任務(wù)優(yōu)化:每10秒監(jiān)控 Redis 數(shù)據(jù)
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)計(jì)信息: {}", fullKey); return; } log.info("----- 統(tǒng)計(jì)信息監(jiān)控(Key: {})-----", fullKey); stats.forEach((field, value) -> log.info("{}: {}", field, value)); // 業(yè)務(wù)處理示例 int total = Integer.parseInt(stats.getOrDefault("total", "0").toString()); if (total > 1000) { log.warn("警告:數(shù)據(jù)量過(guò)大({}條)", total); } } catch (Exception e) { log.error("監(jiān)控統(tǒng)計(jì)信息失敗", e); } } private String getFormattedTime() { // 生成格式化的時(shí)間戳,如 20250609175050 return LocalDateTime.now() .format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); } }
4.2 功能說(shuō)明
- 定時(shí)任務(wù):每10秒檢查 Redis Hash 數(shù)據(jù)。
- 動(dòng)態(tài) Key:支持按時(shí)間戳生成 Key(如 log:stats:1635474646:20250609175050)。
- 異常處理:捕獲 Redis 操作異常,避免任務(wù)中斷。
- 業(yè)務(wù)告警:數(shù)據(jù)量超過(guò)閾值時(shí)觸發(fā)告警。
5. 完整代碼實(shí)現(xiàn)
5.1 LogMediaAdIdCache(改造后)
(見(jiàn)上文 3.1 節(jié))
5.2 LogStatsMonitorJob(新增)
(見(jiàn)上文 4.1 節(jié))
5.3 配置類(可選)
@Configuration @EnableScheduling public class SchedulingConfig { // 啟用定時(shí)任務(wù) }
6. 總結(jié)與最佳實(shí)踐
6.1 關(guān)鍵改進(jìn)
- 數(shù)據(jù)結(jié)構(gòu)升級(jí):從 Set → Hash,支持結(jié)構(gòu)化存儲(chǔ)。
- 定時(shí)任務(wù)優(yōu)化:每10秒監(jiān)控?cái)?shù)據(jù),確保實(shí)時(shí)性。
- 代碼健壯性:異常處理 + 日志記錄。
6.2 最佳實(shí)踐
- 合理選擇數(shù)據(jù)結(jié)構(gòu):根據(jù)業(yè)務(wù)場(chǎng)景選擇 Set / Hash / ZSet 等。
- 動(dòng)態(tài) Key 設(shè)計(jì):如時(shí)間戳、業(yè)務(wù)ID等,方便數(shù)據(jù)分區(qū)。
- 定時(shí)任務(wù)調(diào)優(yōu):
- 短周期(如10s)適合實(shí)時(shí)監(jiān)控。
- 長(zhǎng)周期(如1h)適合批量處理。
- 異常處理:避免因 Redis 異常導(dǎo)致任務(wù)崩潰。
6.3 后續(xù)優(yōu)化方向
- 數(shù)據(jù)分片:若數(shù)據(jù)量過(guò)大,可采用分片存儲(chǔ)。
- 分布式鎖:避免多實(shí)例任務(wù)重復(fù)執(zhí)行。
- 數(shù)據(jù)過(guò)期策略:設(shè)置 TTL 自動(dòng)清理舊數(shù)據(jù)。
結(jié)語(yǔ)
本文通過(guò)一個(gè)實(shí)際案例,演示了如何將 Redis 數(shù)據(jù)結(jié)構(gòu)從 Set 遷移到 Hash,并實(shí)現(xiàn)高效定時(shí)監(jiān)控。合理的數(shù)據(jù)結(jié)構(gòu)選擇 + 定時(shí)任務(wù)優(yōu)化,可以顯著提升系統(tǒng)性能和可維護(hù)性。
以上就是Redis定時(shí)監(jiān)控與數(shù)據(jù)處理實(shí)踐指南的詳細(xì)內(nèi)容,更多關(guān)于Redis定時(shí)監(jiān)控與數(shù)據(jù)處理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Redis拓展之定時(shí)消息通知實(shí)現(xiàn)詳解
- Redis?延時(shí)任務(wù)實(shí)現(xiàn)及與定時(shí)任務(wù)區(qū)別詳解
- Spring boot詳解緩存redis實(shí)現(xiàn)定時(shí)過(guò)期方法
- Redis定時(shí)任務(wù)原理的實(shí)現(xiàn)
- Python定時(shí)從Mysql提取數(shù)據(jù)存入Redis的實(shí)現(xiàn)
- Spring Boot監(jiān)聽(tīng)Redis Key失效事件實(shí)現(xiàn)定時(shí)任務(wù)的示例
- 基于redis實(shí)現(xiàn)定時(shí)任務(wù)的方法詳解
- Springboot使用Redis實(shí)現(xiàn)定時(shí)任務(wù)的三種方式
相關(guān)文章
Redis官方可視化工具RedisInsight的安裝使用詳細(xì)教程(功能強(qiáng)大)
RedisInsight是Redis官方出品的可視化管理工具,可用于設(shè)計(jì)、開(kāi)發(fā)、優(yōu)化你的Redis應(yīng)用。支持深色和淺色兩種主題,界面非常炫酷,接下來(lái)通過(guò)本文給大家介紹Redis官方可視化工具RedisInsight的安裝使用過(guò)程,需要的朋友可以參考下2022-04-04分布式使用Redis實(shí)現(xiàn)數(shù)據(jù)庫(kù)對(duì)象自增主鍵ID
本文介紹在分布式項(xiàng)目中使用Redis生成對(duì)象的自增主鍵ID,通過(guò)Redis的INCR等命令實(shí)現(xiàn)計(jì)數(shù)器功能,具有一定的參考價(jià)值,感興趣的可以了解一下2024-12-12Redis Template實(shí)現(xiàn)分布式鎖的實(shí)例代碼
使用Redis的SETNX命令獲取分布式鎖的步驟,接下來(lái)通過(guò)本文給大家介紹Redis Template實(shí)現(xiàn)分布式鎖的實(shí)例代碼,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-09-09使用Redis控制表單重復(fù)提交和控制接口訪問(wèn)頻率方式
這篇文章主要介紹了使用Redis控制表單重復(fù)提交和控制接口訪問(wèn)頻率方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-06-06redis適合場(chǎng)景八點(diǎn)總結(jié)
在本篇文章中我們給大家整理了關(guān)于redis適合什么場(chǎng)景的8點(diǎn)知識(shí)點(diǎn)內(nèi)容,需要的朋友們參考下。2019-06-06Springboot/Springcloud項(xiàng)目集成redis進(jìn)行存取的過(guò)程解析
大家都知道Redis支持五種數(shù)據(jù)類型:string(字符串),hash(哈希),list(列表),set(集合),zset(sorted set:有序集合),本文重點(diǎn)給大家介紹Springboot/Springcloud項(xiàng)目集成redis進(jìn)行存取的過(guò)程,需要的朋友參考下吧2021-12-12使用redis實(shí)現(xiàn)高效分頁(yè)的項(xiàng)目實(shí)踐
在很多場(chǎng)景下,我們需要對(duì)大量的數(shù)據(jù)進(jìn)行分頁(yè)展示,本文主要介紹了使用redis實(shí)現(xiàn)高效分頁(yè)的項(xiàng)目實(shí)踐,具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02面試分析分布式架構(gòu)Redis熱點(diǎn)key大Value解決方案
這篇文章主要為大家介紹了分布式架構(gòu)Redis熱點(diǎn)key大Value解決方案,以及在面試中如果遇到這類問(wèn)題的分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-03-03