引言:那个让Redis「歪脖子」的夜晚
还记得那是一个月黑风高的夜晚,突然收到报警:「Redis节点CPU飙升至95%!」。心急火燎地登录服务器,发现其中一个分片像个发烧的病人,而其他节点却闲得能打麻将。
是的,Redis它...「歪脖子」了!这就是我们今天要聊的------Redis倾斜问题。
一、什么是Redis倾斜?不只是数据分配不均!
简单来说,Redis倾斜就像是把100斤的包袱让一个人背,其他9个人在旁边嗑瓜子。主要表现为两种形式:
- 数据倾斜:某些节点上的数据特别多,内存告急
- 请求倾斜:某些节点接收的请求特别多,CPU压力山大
二、倾斜的「罪魁祸首」类型分析
1. 数据倾斜的3大「妖魔鬼怪」
① 热点数据集中化 🎯 想象一下双11的某爆款商品,所有人都往同一个key里挤,不分片才怪!
bash
# 所有人都访问同一个key
GET:product:12345:detail
HGETALL:activity:double11:2023
② Hash Tag滥用导致的「扎堆现象」
bash
# 使用hash tag让不同的key分配到同一个slot
{user:1001}:profile
{user:1001}:orders
{user:1001}:cart
这就像把一家老小的行李都绑在一个人身上!
③ Big Key「巨无霸」横行 某个key里存了10MB的数据(比如一个超大的List或Hash),不仅自己占地方,还会让操作变慢。
2. 请求倾斜的2大「流量刺客」
① 热点Key的「万人迷」效应 某个Key被疯狂访问(比如明星离婚公告),瞬间成为流量黑洞。
② 单命令操作多个Key的「连坐」效应
bash
# 使用mget操作多个key,但如果这些key都在同一个节点...
MGET user:1001:name user:1001:age user:1001:email
三、Redis倾斜「捉妖指南」:诊断方法
1. 使用redis-cli --bigkeys抓拿「巨无霸」
bash
redis-cli --bigkeys -h your_redis_host -p 6379
2. 使用redis-cli --hotkeys找出「万人迷」
bash
# 需要先开启maxmemory-policy为LFU策略
redis-cli --hotkeys -h your_redis_host -p 6379
3. 使用redis-cli --memkeys检测内存分配
bash
redis-cli --memkeys -h your_redis_host -p 6379 --samples 100
4. 监控各个节点的QPS和内存使用情况
bash
# 查看各个节点的QPS
redis-cli -h your_redis_host -p 6379 info stats | grep instantaneous_ops_per_sec
# 查看内存使用情况
redis-cli -h your_redis_host -p 6379 info memory | grep used_memory_human
四、「扶正」Redis:解决方案大全
1. 数据倾斜的「整形手术」
① 拆分Big Key
java
// 拆分前:一个大的Hash
HGETALL user:1001:all_data
// 拆分后:多个小的Hash
HGET user:1001:profile name
HGET user:1001:orders recent
HGET user:1001:settings theme
② 使用集群模式+合理hash tag
bash
# 适度使用hash tag,不要过度
{user:1001}.profile
{user:1001}.orders
{user:1002}.profile # 这会分配到不同节点
③ 数据预分布+监控预警 提前规划key的分布,设置内存使用阈值告警。
2. 请求倾斜的「分流大法」
① 本地缓存+多级缓存
java
// 使用本地缓存缓解热点key压力
@Cacheable(value = "userProfile", key = "#userId")
public UserProfile getUserProfile(String userId) {
// 只有缓存未命中时才会查询Redis
return redisTemplate.opsForValue().get("user:profile:" + userId);
}
② Key拆分+请求分散
java
// 将热点key拆分成多个子key
public String getHotValue(String key) {
int segment = ThreadLocalRandom.current().nextInt(1, 5);
return redisTemplate.opsForValue().get(key + ":segment_" + segment);
}
③ 使用Redis代理或客户端侧负载均衡
java
// 使用支持负载均衡的客户端
@Configuration
public class RedisConfig {
@Bean
public RedisConnectionFactory redisConnectionFactory() {
LettucePoolingClientConfiguration config =
LettucePoolingClientConfiguration.builder()
.readFrom(ReadFrom.REPLICA) // 优先从副本读取
.build();
RedisClusterConfiguration clusterConfig =
new RedisClusterConfiguration(Arrays.asList(
"redis-node1:6379",
"redis-node2:6379",
"redis-node3:6379"
));
return new LettuceConnectionFactory(clusterConfig, config);
}
}
五、防患于未然:Redis倾斜预防指南
1. 设计阶段的「防歪脖」 checklist
- 避免使用过大的value,拆分成多个key
- 谨慎使用hash tag,确保数据均匀分布
- 设计合理的过期时间,避免同时大量过期
2. 开发阶段的「健壮性」实践
java
// 使用pipeline减少网络开销,但注意不要一次操作太多key
public List<Object> batchGet(List<String> keys) {
return redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
for (String key : keys) {
connection.stringCommands().get(key.getBytes());
}
return null;
});
}
3. 运维阶段的「常态化」监控
监控指标清单:
- 各个节点的内存使用率
- 各个节点的QPS/TPS
- 慢查询日志
- key命中率
告警阈值建议:
- 内存使用率 > 80%
- QPS差异 > 50%
- 慢查询数量突增
六、总结:别等Redis「歪脖子」了才想起正骨
Redis倾斜问题就像颈椎病------平时不注意,发作起来真要命!通过合理的架构设计、代码规范和监控告警,我们完全可以避免这种「歪脖子」情况。
记住:一个健康的Redis集群,每个节点都应该「雨露均沾」,而不是让某个节点独自承受所有压力!
大家在工作中还遇到过哪些Redis的「奇葩」问题?欢迎在评论区分享你的「捉妖」经历!
本文已获得「Redis防歪脖协会」认证,转载请注明出处。祝大家的Redis永远挺直腰板,永不歪脖!