3. Batch Size基础
3.1 什么是Batch Size?先别急着调参
很多新手一上来就问我:“Batch Size设多少最好?”
说实话,这个问题没有标准答案。但如果你不理解Batch Size的本质,调参就是瞎蒙。
Batch Size,说白了就是“一次喂给系统多少数据”。
拿数据库批量插入举例:你有一条一条插,和一次插1000条,吞吐量天差地别。我见过一个项目,单条插入TPS只有200,改成Batch=100后,直接飙到8000。嗯,40倍的差距。
核心公式(记住这个):
吞吐量 = 单次操作耗时 × 并发数 ÷ Batch Size
但别高兴太早——Batch Size不是越大越好,后面我会讲为什么。
3.2 Batch Size对吞吐量的影响:一个真实案例
我曾经帮一家金融公司做压测。他们的核心业务是批量对账,每天处理几百万笔交易。
初始配置:Batch Size=10,TPS只有1200。系统CPU利用率不到30%,但数据库连接池已经爆了。
我建议他们把Batch Size调到200。你猜怎么着?
TPS直接跳到8500,CPU利用率升到75%,数据库连接数反而降了60%。
为什么会这样?
因为每次网络往返、事务开启、锁竞争的开销被摊薄了。你想想看,一次请求搞定200条数据,和分20次请求搞定,光网络延迟就省了多少。
| Batch Size | TPS | 平均响应时间(ms) | 数据库连接数 |
|---|---|---|---|
| 10 | 1,200 | 85 | 200 |
| 50 | 4,500 | 42 | 120 |
| 200 | 8,500 | 18 | 80 |
| 500 | 9,200 | 15 | 75 |
| 1000 | 8,800 | 22 | 90 |
看到没?Batch Size从10到200,TPS涨了7倍。但从200到1000,反而开始下降了。
这就是我今天要讲的核心:Batch Size存在一个“甜点区间”。
3.3 大Batch的优势:为什么大家都爱用大Batch?
我个人习惯,在压测初期先把Batch Size设大一点。原因有三:
- 减少网络开销:每次网络往返都是成本。大Batch相当于拼车,一次拉一车人。
- 提高资源利用率:CPU、磁盘IO、数据库连接,这些资源都能被更充分地利用。
- 降低锁竞争:事务次数少了,行锁、表锁的争抢自然就少了。
我的经验:对于数据库批量写入场景,Batch Size在100-500之间通常表现最好。但如果是内存计算,比如批量处理List数据,500-2000都行。
3.4 小Batch的劣势:别被“大就是好”骗了
但大Batch也有坑。我踩过,而且踩得很惨。
问题一:内存爆炸
有一次我把Batch Size调到5000,结果服务端直接OOM了。为什么?因为每条数据2KB,5000条就是10MB。如果并发20个线程,光Batch缓冲区就占了200MB。再加上业务对象、连接池、缓存……嗯,你懂的。
问题二:事务过长
大Batch意味着大事务。大事务意味着锁持有时间变长。我曾经遇到一个场景:Batch Size=1000时,一个事务要跑8秒。这8秒里,其他线程全在等锁。TPS反而比Batch=200时还低。
问题三:失败成本高
小Batch失败了,重试10条数据。大Batch失败了,重试1000条。而且大事务回滚的时间也长得多。
避坑指南:我曾经在一个高并发支付系统中,把Batch Size设成2000。结果某次网络抖动,一个事务超时回滚,导致后续所有请求排队等待。系统雪崩了整整3分钟。从那以后,我养成了一个习惯:大Batch一定要配合超时熔断机制。
3.5 大小Batch的优劣对比:一张表说清楚
| 对比维度 | 小Batch (1-50) | 大Batch (200-1000) |
|---|---|---|
| 吞吐量 | 低(网络开销大) | 高(摊薄成本) |
| 响应时间 | 低(单条快) | 高(排队等待) |
| 内存占用 | 低 | 高(小心OOM) |
| 事务风险 | 低(失败影响小) | 高(回滚成本大) |
| 资源利用率 | 低(CPU空闲多) | 高(压满资源) |
| 适用场景 | 实时性要求高、数据量小 | 批量处理、离线任务 |
3.6 核心逻辑图:Batch Size调参的决策路径
下面这张图是我自己总结的调参思路,每次做压测前我都会过一遍。
3.7 实战建议:怎么找到你的“甜点”?
说了这么多,到底怎么调?我分享一个我自己用的方法:
- 从100开始:这是大多数系统的安全起点。
- 翻倍测试:100 → 200 → 400 → 800,每次跑5分钟压测。
- 观察三个指标:TPS、平均响应时间、内存使用率。
- 找到拐点:当TPS不再明显增长,或者响应时间开始飙升,那就是上限了。
- 回退20%:在拐点基础上减20%,作为生产环境的Batch Size。
记住:Batch Size不是越大越好。你的目标是“在资源不爆的前提下,最大化吞吐量”。
我见过太多人把Batch Size调到5000、10000,结果系统挂了还找不到原因。
3.8 代码示例:一个简单的Batch调参模板
下面是我常用的压测脚本片段,你可以直接拿去改:
// Batch Size调参模板
public class BatchSizeTest {
// 测试不同Batch Size的吞吐量
public void testBatchSizes() {
int[] batchSizes = {50, 100, 200, 500, 1000};
for (int batchSize : batchSizes) {
long start = System.currentTimeMillis();
int totalRecords = 10000;
int processed = 0;
while (processed < totalRecords) {
int currentBatch = Math.min(batchSize, totalRecords - processed);
// 执行批量操作
batchInsert(currentBatch);
processed += currentBatch;
}
long cost = System.currentTimeMillis() - start;
double tps = totalRecords / (cost / 1000.0);
System.out.println("Batch=" + batchSize +
", TPS=" + String.format("%.2f", tps) +
", 耗时=" + cost + "ms");
}
}
}
这个脚本我用了好几年。每次换新项目,第一件事就是跑一遍这个测试。嗯,省了很多坑。
好了,Batch Size的基础就讲到这里。记住:没有银弹,只有测试。动手跑一遍,比看十篇文章都管用。
最后一句:如果你发现Batch Size调到某个值后TPS反而下降,别慌。检查一下是不是内存满了、锁竞争激烈了、或者数据库连接池不够用了。这些我都遇到过,都是正常现象。