尧图精选

缓存大键与连接池的发布检查

🕒 发布时间:2026/9/1 1:17:11 📁 来源:尧图网络
缓存大键与连接池的发布检查交付前应按业务数据分布复核大键阈值、连接池大小和压测数据集。在预发环境做基准压测时测试报告非常好看Redis 读写延迟维持在 1ms 以内MySQL 压测 QPS 轻松破万。然而当新功能正式发布上线的第一个流量高峰期报警电话突然响个不停。监控看板显示Redis 主节点的 CPU 利用率瞬间拉满到 100%大量的应用节点报出JedisConnectionException: Could not get a resource from the pool错误与此同时MySQL 的活跃连接数急剧飙升出现了大量处于Sending data状态的阻塞查询。排查生产现场后发现了两个经典的致命问题隐藏的 Redis BigKey研发为了图省事在 Hash 结构中存储了整个租户下数万名用户的状态列表单 Key 占用内存增至几十兆。在 Redis 单线程架构下一次HGETALL操作直接阻塞主线程长达 400 毫秒后续上千个轻量级的GET请求瞬间全部积压挂起。连接池与慢查询的协同灾难因为 Redis 被 BigKey 卡死上游微服务将读取压到 MySQL 数据库而 MySQL 恰好缺少联合索引触发了全表扫描进而导致数据库连接池被瞬间耗尽。压测环境如果缺乏“真实数据规模”与“生产级倾斜场景”的模拟简单的压测数据极具欺骗性。中间件交付前必须有一套标准化的硬核检查机制。Redis 热点 Key 发现与多级本地缓存Caffeine防御切断对于高并发系统除了 BigKey另一个杀手是HotKey热点 Key。当全网数万人同时抢购某一款商品或者突发热点新闻时该 Key 的访问请求会集中打到 Redis 某个特定 Slot 对应的分片节点上。即便是分布式 Redis 集群也无法通过扩容节点来分担单节点的热点负载。解决热点 Key 的标准化方案是构建“Redis 动态热点探测 Caffeine 本地一级缓存”的多级缓存防御屏障。防爆设计原理热点自动识别利用 Redis 4.0 提供的LFULeast Frequently Used内存回收策略或者在网关/中间件层通过客户端滑动窗口计数器实时识别出 QPS 1000 的热点 Key。本地二级避浪一旦感知到热点 Key应用节点立刻将其推送到本地 JVM 内存Caffeine Cache中设置 5 秒短过期时间。让 99% 的读请求在微服务进程内部被消化彻底切断打向 Redis 单节点的冲击波。用于生产环境的多级缓存读取与防穿透防护代码实战package com.middleware.cache; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; import java.time.Duration; import java.util.concurrent.TimeUnit; Slf4j Component public class MultiLevelCacheManager { private final StringRedisTemplate redisTemplate; // Caffeine 本地一级缓存容量 10,000过期时间 5 秒 private final CacheString, String localCache Caffeine.newBuilder() .maximumSize(10_000) .expireAfterWrite(5, TimeUnit.SECONDS) .build(); public MultiLevelCacheManager(StringRedisTemplate redisTemplate) { this.redisTemplate redisTemplate; } /** * 多级缓存获取方案优先本地缓存 - 次选 Redis - 兜底 DB */ public String getWithHotKeyProtection(String key, CacheLoader loader) { // 1. 读取 JVM 本地缓存 (Caffeine) String value localCache.getIfPresent(key); if (value ! null) { return value; } // 2. 本地未命中读取 Redis 分布式缓存 value redisTemplate.opsForValue().get(key); if (value ! null) { // 将 Redis 数据回填至本地缓存做 5 秒热点避峰 localCache.put(key, value); return value; } // 3. 缓存均未命中执行分布式锁或单线加载防止击穿 DB synchronized (this) { // 二次检查本地缓存 value localCache.getIfPresent(key); if (value ! null) return value; log.warn(缓存穿透/击穿从底层数据库加载数据, Key: {}, key); value loader.load(); if (value ! null) { // 写入 Redis (设置 30 分钟随机过期防雪崩) redisTemplate.opsForValue().set(key, value, Duration.ofMinutes(30)); // 写入本地 Caffeine localCache.put(key, value); } } return value; } FunctionalInterface public interface CacheLoader { String load(); } }MySQL 慢查询、长事务与索引失效的自动化静态巡检上线前不仅要关注 Redis还要对 MySQL 的 DDL 与 DML 进行自动化静态扫描。许多线上事故源于极隐蔽的代码习惯比如在 SQL 条件中对字符串字段传了数字类型引发隐式类型转换Implicit Type Conversion直接导致主键以外的索引全部失效全表扫描几百万行。在 CI/CD 流水线中我们引入了 MySQL 语句静态检查工具如 SOAR 或 SQL-Lint强制实施以下规则拦截禁止全表扫描所有UPDATE/DELETE语句必须带索引字段条件。严格控制长事务事务中严禁包裹 RPC 远程网络调用或 Redis 读写。长事务会导致 MySQL 保持Innodb_undo_logs无法 purge行锁持有时间拉长死锁概率剧增。最左前缀原则校验复合索引A, B, C查询条件中缺少 A 却直接查询 B 和 C 的 SQL在 CI 阶段直接报红阻断。生产环境中间件上线前的 10 项严苛验收检查表把关最后的交付质量必须对照清单逐项勾选严禁凭口头保证上线检查项验收标准与动作判定结果1.Redis BigKey 扫描使用redis-cli --bigkeys检查String 类型禁止 10KB集合类型元素数禁止 5000必须通过2.Redis 命令禁用生产环境明确禁用KEYS *、FLUSHALL、MONITOR等危险命令必须通过3.缓存过期时间打散批量导入或更新缓存时过期时间必须叠加TTL Random(1~300s)随机值必须通过4.Redis 连接池配置maxActive必须根据并发计算显式配置minIdle与maxWaitMillis必须通过5.MySQL 慢查询 EXPLAIN所有核心接口 SQL 的EXPLAIN结果中type严禁为ALL全表扫描必须通过6.MySQL 隐式转换校验确认 WHERE 条件参数类型与数据库 Schema 字段定义完全一致必须通过7.长事务包裹检测检查Transactional标注的方法内是否有 HTTP / RPC 耗时网络调用必须通过8.死锁风险语句检查避免SELECT ... FOR UPDATE跨多个非主键索引顺序不一致的并发更新必须通过9.多级缓存失效降级模拟 Redis 挂掉场景验证 Caffeine 或本地兜底逻辑能否保障主流程不崩退必须通过10.中间件超时时间设置MySQL 连接串必须配置connectTimeout与socketTimeout防止永远挂起线程必须通过中间件从来不是“挂上去就能自动跑稳”的黑盒。在交付之前把 BigKey 拆掉、把索引对齐、把本地缓存屏障架设起来才能让系统真正承受住线上真实流量的考验。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →