一、点赞功能的核心挑战
在社交媒体、内容平台等高并发场景下,点赞功能需同时满足三个核心需求:
- 低延迟响应:用户操作需在毫秒级完成反馈,避免卡顿感
- 数据强一致性:确保用户看到的点赞数与实际存储一致
- 系统高可用性:在流量洪峰下保持服务稳定,避免雪崩效应
传统数据库直写方案在每秒万级请求时会出现明显性能衰减。以MySQL为例,单表点赞记录的写入TPS通常不超过3000,而热点内容的并发点赞量可能达到10万+/分钟。这种量级差异迫使我们必须采用缓存层来吸收瞬时流量。
二、Redis缓存层设计要点
1. 数据结构选择
- Hash结构:适合存储用户-内容点赞关系
HSET like
123 user:456 1 # 用户456点赞了内容123
- String计数器:高效统计点赞总数
INCR like
123 # 内容123点赞数+1
- Sorted Set:可实现热门内容排行榜
ZADD hot_content 1000 123 # 内容123热度值1000
2. 缓存策略优化
- 多级缓存:本地缓存(Caffeine)+ Redis集群
- 异步刷新:采用Redis的管道(Pipeline)批量操作
- 防击穿设计:对热点Key设置逻辑过期时间(如10秒),后台异步续期
3. 并发控制机制
-
Lua脚本原子操作:实现点赞+计数+排行的原子性
-- 点赞并更新排行local contentId = KEYS[1]local userId = KEYS[2]local now = tonumber(ARGV[1])-- 检查是否已点赞if redis.call("HEXISTS", "like
"..contentId, "user:"..userId) == 0 then-- 增加计数redis.call("INCR", "like
"..contentId)-- 记录点赞关系redis.call("HSET", "like
"..contentId, "user:"..userId, 1)-- 更新排行(简化示例)redis.call("ZINCRBY", "hot_content", 1, contentId)return 1elsereturn 0end
三、定时写入数据库实现
1. 写入策略设计
- 时间窗口聚合:每5分钟将Redis中的增量数据批量写入数据库
- 双写校验:写入前检查数据库最新值,避免并发导致的数据丢失
- 失败重试机制:对写入失败的任务进行指数退避重试
2. 数据库表设计优化
CREATE TABLE content_like (id BIGINT PRIMARY KEY AUTO_INCREMENT,content_id BIGINT NOT NULL,like_count INT NOT NULL DEFAULT 0,version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,INDEX idx_content (content_id)) ENGINE=InnoDB;CREATE TABLE user_like_relation (id BIGINT PRIMARY KEY AUTO_INCREMENT,user_id BIGINT NOT NULL,content_id BIGINT NOT NULL,create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,UNIQUE KEY uk_user_content (user_id, content_id)) ENGINE=InnoDB;
3. 批量写入实现示例
// 使用Spring Batch实现批量写入@Beanpublic Job likeDataSyncJob(JobRepository jobRepository, Step syncStep) {return new JobBuilder("likeDataSyncJob", jobRepository).start(syncStep).build();}@Beanpublic Step syncStep(StepBuilderFactory stepBuilderFactory,ItemReader<Map.Entry<Long, Integer>> reader,ItemWriter<List<Map.Entry<Long, Integer>>> writer) {return stepBuilderFactory.get("syncStep").<Map.Entry<Long, Integer>, List<Map.Entry<Long, Integer>>>chunk(1000).reader(reader).writer(writer).faultTolerant().skipLimit(10).skip(DataAccessException.class).build();}
四、异常处理与数据修复
1. 缓存与数据库不一致处理
- 对账机制:每日全量比对Redis计数与数据库值
- 补偿写入:对差异超过阈值的内容触发修复流程
- 监控告警:设置计数偏差率超过5%的告警阈值
2. 缓存穿透防护
- 空值缓存:对未点赞状态设置短时间缓存(如1分钟)
- 布隆过滤器:预加载热点内容ID,过滤无效请求
- 限流策略:对单个内容的点赞请求进行令牌桶限流
五、性能优化实践
1. 集群部署方案
- Redis Cluster:至少3主3从配置,分片数建议为节点数的2倍
- 读写分离:从节点承担90%的读请求
- 连接池优化:Jedis连接池最大连接数设置为(核心线程数*2 + 10)
2. 监控指标体系
| 指标类型 | 监控项 | 告警阈值 |
|---|---|---|
| 缓存层 | Redis内存使用率 | >85% |
| 命令处理延迟 | >5ms | |
| 键空间命中率 | <95% | |
| 数据库层 | 写入QPS | >5000/秒 |
| 慢查询数 | >10次/分钟 | |
| 应用层 | 点赞接口平均耗时 | >200ms |
| 接口错误率 | >0.5% |
六、扩展性设计
1. 水平扩展方案
- 分库分表:按内容ID哈希分库,支持10亿级数据存储
- 动态分片:基于Vitess实现MySQL分片的自动扩容
- 服务化架构:将点赞服务拆分为独立微服务
2. 跨机房部署
- 单元化架构:每个机房部署完整的服务单元
- 数据同步:使用MySQL Group Replication实现跨机房数据同步
- 流量调度:基于DNS解析实现就近访问
七、实施路线图建议
- 第一阶段(1周):完成Redis缓存层搭建,实现基础点赞功能
- 第二阶段(2周):开发定时写入数据库模块,完成初步测试
- 第三阶段(1周):构建监控体系,优化异常处理流程
- 第四阶段(持续):根据压测结果进行参数调优
典型压测数据表明,该方案在单机环境下可支撑:
- QPS:12万+/秒(纯缓存操作)
- 平均延迟:1.2ms
- 数据库写入峰值:8000条/秒
这种设计既保证了高并发场景下的系统性能,又通过定时写入机制确保了数据的持久化可靠性,是构建百万级DAU产品点赞功能的理想方案。实际实施时,建议先在小流量环境进行充分测试,再逐步扩大应用范围。