Redis大Key会导致单线程阻塞、网络打满、客户端超时及主从延迟,核心对策是设计阶段按业务维度水平分片(如mod 997)、禁用全量命令、强制UNLINK异步删除,并通过监控告警与熔断降级实现兜底。

高并发下,Redis 中百万级元素的 Hash 这类超大 Key 会直接触发单线程阻塞、网络带宽打满、客户端超时、主从同步延迟甚至节点失联。这不是“慢”,而是“卡死”。规避核心思路不是事后处理,而是从设计源头切断大 Key 的生成路径,并辅以安全兜底机制。
提前拆分:按业务维度做水平分片
不把百万订单塞进一个 order:20260721 hash,而是按可哈希字段(如 order_id、user_id、mod 997)分散到多个子 key:
- 新 key 格式示例:
order:20260721:001、order:20260721:002…order:20260721:997 - 写入时计算
Math.abs(orderId.hashCode() % 997)确定归属分片,用HSET写入对应子 key - 读取时同样路由,支持
HGET单查,也支持pipeline批量并行拉取多个分片 - 避免用时间戳或纯递增 ID 做分片依据,防止热点集中在某几个分片
控制读写粒度:禁止全量操作,强制按需访问
业务代码中严禁出现 HGETALL、LRANGE key 0 -1、SMEMBERS 等全量命令,尤其在高并发路径上:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 查询订单统计?改用预聚合字段,如
HINCRBY order:20260721:001 total_amount 100 - 需要批量查若干 order_id?用
HMGET order:20260721:001 id1 id2 id3,而非拉全量再过滤 - Java 侧封装工具类,对 RedisTemplate 做拦截校验 —— 检测到疑似全量命令(参数含
*或-1)直接抛运行时异常,上线前卡死问题
删除与过期必须异步化
哪怕已拆分,单个子 hash 仍可能达数万 field;DEL 仍会阻塞。务必启用 UNLINK 替代 DEL:
立即学习“Java免费学习笔记(深入)”;
- Spring Data Redis 2.3+ 默认对
delete()方法自动降级为UNLINK(需 Redis ≥4.0) - 手动调用时明确使用
redisTemplate.execute(RedisScript, …)或直连 Jedis 的unlink(key) - 对带 TTL 的大结构,避免依赖自动过期 —— 主动在业务低峰期用
HSCAN分批清理过期子项,配合UNLINK
监控与熔断双保险
靠预防不能 100% 防住,必须实时感知 + 快速止损:
- 接入
redis-cli --hotkeys或redis-exporter + Prometheus,对key size > 512KB或hash field count > 5000设置告警 - Java 应用层加 Sentinel 或 Resilience4j 熔断器:当 Redis 调用平均耗时 > 200ms 或错误率 > 5%,自动降级为查 DB 或返回默认值
- 日志中统一打印 key 名、命令类型、耗时、client ip,便于定位是哪个业务方在写大 Key

















