一、场景痛点分析:为什么传统方案会崩?

  1. String直接计数INCR命令导致热Key瓶颈(单Key每秒百万级QPS)
  2. 重复写入:用户疯狂点击造成数据库雪崩
  3. 数据丢失:Redis宕机后点赞数“一夜回到解放前”

图片

💥 传统架构崩溃现场模拟:

1
// 错误示例:直接操作Stringpublic void likePost(String postId) {    redisTemplate.opsForValue().increment("post:" + postId); // 热Key警告!}

二、终极解决方案:4层架构抵御流量海啸

1. 数据结构优化:分片Hash + 二级索引

🔑 核心代码:

1
2
3
4
5
// 分片Hash存储(1024个分片)
String postShardKey = "post_like:" + postId + ":shard_" + (postId.hashCode() % 1024);
// 原子操作:记录用户点赞并更新计数
redisTemplate.execute(new DefaultRedisScript<Boolean>(
"if redis.call('HSETNX', KEYS[1], ARGV[1], 1) == 1 then " + " redis.call('HINCRBY', KEYS[1], 'count', 1) " + " return true " + "else " + " return false " + "end", Boolean.class), Arrays.asList(postShardKey), userId.toString());

图片

2. 流量削峰:异步化 + 批量合并

🔑 Kafka生产者代码:

1
2
@Autowiredprivate KafkaTemplate<String, String> kafkaTemplate;
public void asyncLike(String postId, String userId) { String message = postId + ":" + userId; kafkaTemplate.send("like_events", postId.hashCode() % 100, message); // 按postId分区}

📦 消费者批量处理(Spring Batch示例):

1
2
3
4
5
6
7
8
9
10
11
@KafkaListener(topics = "like_events", groupId = "like-group")
public void batchProcess(List<ConsumerRecord<String, String>> records) {
Map<String, List<String>> postUserMap = new HashMap<>();
records.forEach(record -> {
String[] parts = record.value().split(":");
postUserMap.computeIfAbsent(parts[0], k -> new ArrayList<>()).add(parts[1]);
});
postUserMap.forEach((postId, userIds) -> {
String shardKey = "post_like:" + postId + ":shard_" + (postId.hashCode() % 1024); redisTemplate.opsForHash().putAll(shardKey, userIds.stream() .collect(Collectors.toMap(u -> u, u -> "1")));
});
}

3. 分布式扩展:Redis Cluster + 边缘计算

🌍 全球机房部署架构图:

图片

⚙️ Redis Cluster配置建议:

1
2
3
4
# redis.conf 关键配置io-threads 4                
# 启用多线程IOcluster-enabled yes
# 开启集群模式tcp-backlog 10000
# 高并发连接队列

4. 数据安全:双写保护 + 熔断降级

🔒 双写校验代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 先写Redis,异步写MySQL
@Transactionalpublic boolean likeWithGuard(String postId, String userId) {
// 1. Redis原子操作
boolean success = redisLikeService.like(postId, userId);
if (!success) return false;
// 2. 发送异步事件(带本地事务)
transactionTemplate.execute(status -> {
kafkaTemplate.send("like_events", postId, userId); return null;
});
return true;
}
// 补偿任务:每小时修复数据
@Scheduled(fixedRate = 3600000)public void repairData() {
// 对比Redis与MySQL差异,修复计数
}

三、性能压测结果

方案 单机QPS 延迟(P99) 数据一致性
原生String 8万 15ms 可能丢失
分片Hash+异步队列 68万 8ms 最终一致(<1s)

四、彩蛋:真实踩坑案例

  1. 热Key导致CPU 100%

    • 现象:某明星直播时,post_like:666分片过热
    • 解决:动态拆分分片(从1024扩容到2048)
  2. Kafka消息积压

    • 现象:消费者处理速度跟不上,延迟10分钟
    • 解决:升级消费者为parallel=16 + 开启auto.commit=false

*技术点总结*

分片Hash → 异步削峰 → 集群扩展 → 双写兜底,这四板斧可应对任何突发流量!建议收藏本文,随时应对下一个“顶流大瓜”! 🚀