推荐用复合键如"like:comment:{commentId}"或"like:level2:{parentId}:{childId}",值类型选AtomicLong或ConcurrentHashMap<String, AtomicLong>,配合API层幂等校验、守护线程定时批量合并至Redis并异步落库,兼顾性能与一致性。

在多级评论系统中,为避免高频点赞操作直接冲击数据库,通常会引入“临时计数器 + 守护线程 + 缓存落地”机制。核心思路是:点赞请求先写入内存中的线程安全临时计数器(如 ConcurrentHashMap),再由后台守护线程定期批量合并并更新到 Redis 等缓存,最后按需持久化到 DB。
设计临时点赞计数器结构
需支持多级评论(评论、子评论、孙评论)的粒度,推荐用复合键标识:
- 键格式示例:
"like:comment:{commentId}"或更细粒度"like:level2:{parentId}:{childId}" - 值类型用
AtomicLong或ConcurrentHashMap<String, AtomicLong>,确保多线程递增无竞争 - 注意区分“用户维度去重”——临时计数器只记净增量(如用户 A 对某评论点两次赞,实际应+1),建议前置在 API 层做幂等判断(如用布隆过滤器或 Redis Set 记录已点 ID),临时计数器只接收校验后的有效变更
启动守护线程执行定时倾倒
使用 ScheduledExecutorService 启动单线程守护任务(避免并发写缓存冲突),周期建议 3–10 秒(兼顾实时性与吞吐):
- 每次执行时遍历临时计数器,对每个键提取当前值并
getAndSet(0)归零 - 将非零增量合并进 Redis 的对应 key(如用
INCRBY like:comment:123 {delta}) - 若需最终一致性保障,可在此步同时写入轻量消息队列(如 Kafka),触发异步落库,避免阻塞倾倒流程
处理边界与异常情况
守护线程需具备健壮性,不能因单次失败中断后续调度:
- 所有 Redis 操作包裹
try-catch,失败时记录 warn 日志,并保留该批计数器值(不归零),下次重试 - JVM 关闭前,调用
shutdownNow()并同步执行一次强制倾倒(通过Runtime.getRuntime().addShutdownHook()) - 临时计数器本身不持久化,重启后清空;依赖缓存已有值 + 新增流量重建,因此首次启动后需允许短暂数据延迟(通常可接受)
验证与监控关键点
上线前需确认三个一致性环节:
- 比对“临时计数器总和”与“Redis 当前值 + 待倾倒差值”,用于定位漏刷
- 在 Redis 中为每个 like key 设置 TTL(如 7 天),避免僵尸计数长期占位
- 暴露 JMX 或 Prometheus 指标:倾倒周期耗时、平均 delta 大小、失败次数,便于容量预估
这套方案在千万级日活评论场景中已被验证可行,关键不在“多复杂”,而在“每步是否可测、可退、可观察”。

















