批量处理

从逐条处理到批量处理

还记得我最初的实现吗?

每次取消订单都要:

  1. 更新订单状态(数据库写入)
  2. 释放库存(数据库写入)
  3. 发送通知(HTTP 请求)
  4. 记录日志

如果有 1000 个订单要取消,那就是 3000 次数据库写入和 1000 次 HTTP 请求!

逐条处理的性能瓶颈:

数据库 I/O:3000 次
网络 I/O:1000 次
总耗时:~15 秒

批量处理的优势

性能对比

维度逐条处理批量处理提升
数据库 I/O3000 次100 次30x
网络往返1000 次10 次100x
总耗时15 秒2 秒7.5x
连接占用-

原理

逐条处理:
┌─────────┐    ┌─────────┐    ┌─────────┐
│ 任务 1  │───►│ 处理任务  │───►│ 写数据库  │
└─────────┘    └─────────┘    └─────────┘
┌─────────┐    ┌─────────┐    ┌─────────┐
│ 任务 2  │───►│ 处理任务  │───►│ 写数据库  │
└─────────┘    └─────────┘    └─────────┘
...

批量处理:
┌─────────┐    ┌─────────┐    ┌─────────┐
│ 任务 1  │────│          │    │         │
├─────────┤    │ 批量处理  │───►│ 批量写入  │
│ 任务 2  │────│          │    │         │
├─────────┤    └─────────┘    └─────────┘
│ 任务 3  │────│
└─────────┘    │
...           │


         一次处理完成

批量处理实现

数据库批量更新

批量查询

批量插入


批量处理的注意事项

1. 批量大小的选择

批量大小建议:

场景批量大小理由
简单数据库更新100~500数据库连接池限制
复杂业务逻辑10~50避免单个请求超时
外部 API 调用5~20避免超时和限流
大量数据导入1000~5000最大化吞吐量

2. 事务管理

3. 错误处理


批量处理的完整示例


想一想

思考 1

批量处理时,如果部分任务失败,应该如何处理?

参考答案

问题分析:

批量处理中,如果 100 个任务中有 5 个失败,如何处理?

三种策略:

策略 1:全部失败回滚

优点: 数据一致性好 缺点: 一个失败影响全部


策略 2:部分失败跳过

优点: 不会影响成功的任务 缺点: 需要额外处理失败任务


策略 3:分组处理

优点: 平衡了并发控制和故障隔离 缺点: 实现较复杂

最佳实践建议:

  1. 允许部分失败:对于非关键任务
  2. 分组处理:对于大批量任务
  3. 全部回滚:对于强一致性要求