高性能点赞模块设计:Redis缓存与定时数据库写入策略

一、点赞功能的核心挑战

在社交媒体、内容平台等高并发场景下,点赞功能需同时满足三个核心需求:

  1. 低延迟响应:用户操作需在毫秒级完成反馈,避免卡顿感
  2. 数据强一致性:确保用户看到的点赞数与实际存储一致
  3. 系统高可用性:在流量洪峰下保持服务稳定,避免雪崩效应

传统数据库直写方案在每秒万级请求时会出现明显性能衰减。以MySQL为例,单表点赞记录的写入TPS通常不超过3000,而热点内容的并发点赞量可能达到10万+/分钟。这种量级差异迫使我们必须采用缓存层来吸收瞬时流量。

二、Redis缓存层设计要点

1. 数据结构选择

  • Hash结构:适合存储用户-内容点赞关系
    1. HSET like:content:123 user:456 1 # 用户456点赞了内容123
  • String计数器:高效统计点赞总数
    1. INCR like:count:123 # 内容123点赞数+1
  • Sorted Set:可实现热门内容排行榜
    1. ZADD hot_content 1000 123 # 内容123热度值1000

2. 缓存策略优化

  • 多级缓存:本地缓存(Caffeine)+ Redis集群
  • 异步刷新:采用Redis的管道(Pipeline)批量操作
  • 防击穿设计:对热点Key设置逻辑过期时间(如10秒),后台异步续期

3. 并发控制机制

  • Lua脚本原子操作:实现点赞+计数+排行的原子性

    1. -- 点赞并更新排行
    2. local contentId = KEYS[1]
    3. local userId = KEYS[2]
    4. local now = tonumber(ARGV[1])
    5. -- 检查是否已点赞
    6. if redis.call("HEXISTS", "like:content:"..contentId, "user:"..userId) == 0 then
    7. -- 增加计数
    8. redis.call("INCR", "like:count:"..contentId)
    9. -- 记录点赞关系
    10. redis.call("HSET", "like:content:"..contentId, "user:"..userId, 1)
    11. -- 更新排行(简化示例)
    12. redis.call("ZINCRBY", "hot_content", 1, contentId)
    13. return 1
    14. else
    15. return 0
    16. end

三、定时写入数据库实现

1. 写入策略设计

  • 时间窗口聚合:每5分钟将Redis中的增量数据批量写入数据库
  • 双写校验:写入前检查数据库最新值,避免并发导致的数据丢失
  • 失败重试机制:对写入失败的任务进行指数退避重试

2. 数据库表设计优化

  1. CREATE TABLE content_like (
  2. id BIGINT PRIMARY KEY AUTO_INCREMENT,
  3. content_id BIGINT NOT NULL,
  4. like_count INT NOT NULL DEFAULT 0,
  5. version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
  6. update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  7. INDEX idx_content (content_id)
  8. ) ENGINE=InnoDB;
  9. CREATE TABLE user_like_relation (
  10. id BIGINT PRIMARY KEY AUTO_INCREMENT,
  11. user_id BIGINT NOT NULL,
  12. content_id BIGINT NOT NULL,
  13. create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  14. UNIQUE KEY uk_user_content (user_id, content_id)
  15. ) ENGINE=InnoDB;

3. 批量写入实现示例

  1. // 使用Spring Batch实现批量写入
  2. @Bean
  3. public Job likeDataSyncJob(JobRepository jobRepository, Step syncStep) {
  4. return new JobBuilder("likeDataSyncJob", jobRepository)
  5. .start(syncStep)
  6. .build();
  7. }
  8. @Bean
  9. public Step syncStep(StepBuilderFactory stepBuilderFactory,
  10. ItemReader<Map.Entry<Long, Integer>> reader,
  11. ItemWriter<List<Map.Entry<Long, Integer>>> writer) {
  12. return stepBuilderFactory.get("syncStep")
  13. .<Map.Entry<Long, Integer>, List<Map.Entry<Long, Integer>>>chunk(1000)
  14. .reader(reader)
  15. .writer(writer)
  16. .faultTolerant()
  17. .skipLimit(10)
  18. .skip(DataAccessException.class)
  19. .build();
  20. }

四、异常处理与数据修复

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. 第一阶段(1周):完成Redis缓存层搭建,实现基础点赞功能
  2. 第二阶段(2周):开发定时写入数据库模块,完成初步测试
  3. 第三阶段(1周):构建监控体系,优化异常处理流程
  4. 第四阶段(持续):根据压测结果进行参数调优

典型压测数据表明,该方案在单机环境下可支撑:

  • QPS:12万+/秒(纯缓存操作)
  • 平均延迟:1.2ms
  • 数据库写入峰值:8000条/秒

这种设计既保证了高并发场景下的系统性能,又通过定时写入机制确保了数据的持久化可靠性,是构建百万级DAU产品点赞功能的理想方案。实际实施时,建议先在小流量环境进行充分测试,再逐步扩大应用范围。