合并写入

写放大问题

系统运行一段时间后,我发现了一个新问题。

监控数据:

Redis 状态:
- QPS:约 8000
- 其中 INCR/DECR:约 6000 次/秒
- 其中 SADD/SREM:约 2000 次/秒

数据库状态:
- QPS:约 1500
- 其中同步写入:约 500 次/秒
- 其中查询:约 1000 次/秒

问题:每次点赞都要同步写入数据库!

每次点赞的流程:
1. 更新 Redis(INCR)
2. 同步写入数据库(INSERT)
3. 更新数据库计数(UPDATE)

影响:
- 数据库压力大
- 响应时间长
- 吞吐量受限

能否减少数据库写入次数?

我想到了合并写入

合并写入原理

核心思想:

  • 先更新 Redis(立即返回)
  • 将写操作放入队列
  • 定时批量写入数据库
  • 减少数据库写入次数

示意图:

原来:
用户点赞 → 更新 Redis → 写入数据库 → 返回
          ↑______________|
          同步操作,耗时长

合并写入:
用户点赞 → 更新 Redis → 返回(快速)

      写入队列

      定时批量写入数据库(异步)

优势:

  • 响应时间短(不等待数据库)
  • 吞吐量高(批量写入)
  • 数据库压力小

劣势:

  • 数据可能延迟
  • 实现复杂度高

实现方案

方案 1:内存队列 + 定时写入

点赞接口

方案 2:Redis Stream

方案 3:优化的合并策略

性能对比

测试代码

实际效果

监控数据

合并写入上线后:

Redis 状态:
- QPS:约 8000(不变)
- 响应时间:平均 0.5ms(更快)

数据库状态:
- QPS:从 1500 降到 150(降低 90%)
- 其中写入:从 500 降到 50(批量写入)
- 响应时间:平均 10ms

系统吞吐量:
- 从 200 req/s 提升到 2000 req/s
- 提升 10 倍!

数据一致性

延迟分析:
- 最大延迟:1 秒(刷新间隔)
- 平均延迟:0.5 秒
- 对用户影响:几乎无感知

数据准确性:
- 最终一致性
- 定期对账验证
- 不一致率 < 0.1%

课后练习

练习 1

合并写入时,如何处理”用户点赞后立即取消”的情况?

参考答案(3 个标签)
合并写入去重优化

方案:操作去重

练习 2

合并写入队列满时如何处理?

参考答案(3 个标签)
合并写入流控降级

方案:限流 + 降级

练习 3

如何保证合并写入的数据不丢失?

参考答案(3 个标签)
可靠性持久化容灾

方案:持久化队列

练习 4

合并写入时如何监控”延迟”?

参考答案(3 个标签)
监控延迟性能指标

方案:记录时间戳

练习 5

合并写入时,如何处理”数据库故障”?

参考答案(3 个标签)
容错故障处理可靠性

方案:重试 + 死信队列

思考题

  1. 合并写入的”刷新间隔”如何设置?

  2. 如果用户点赞后立即查询,可能查不到数据,如何处理?

  3. 合并写入和”延迟双删”如何配合使用?

💡 提示:这些问题没有标准答案,建议结合实际情况深入思考。