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设大一点。原因有三:

  1. 减少网络开销:每次网络往返都是成本。大Batch相当于拼车,一次拉一车人。
  2. 提高资源利用率:CPU、磁盘IO、数据库连接,这些资源都能被更充分地利用。
  3. 降低锁竞争:事务次数少了,行锁、表锁的争抢自然就少了。

我的经验:对于数据库批量写入场景,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调参的决策路径

下面这张图是我自己总结的调参思路,每次做压测前我都会过一遍。

Batch Size调参决策路径 开始调参 内存是否充足? 是 否 用小Batch (1-50) 尝试大Batch (200-500) 事务时间<1s? 是 否 减小Batch 或拆分事务 继续增大Batch 直到TPS拐点 找到甜点区间

3.7 实战建议:怎么找到你的“甜点”?

说了这么多,到底怎么调?我分享一个我自己用的方法:

  1. 从100开始:这是大多数系统的安全起点。
  2. 翻倍测试:100 → 200 → 400 → 800,每次跑5分钟压测。
  3. 观察三个指标:TPS、平均响应时间、内存使用率。
  4. 找到拐点:当TPS不再明显增长,或者响应时间开始飙升,那就是上限了。
  5. 回退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反而下降,别慌。检查一下是不是内存满了、锁竞争激烈了、或者数据库连接池不够用了。这些我都遇到过,都是正常现象。