Flink 没有全局统一的 sink.batch-size 配置,它是各类 Sink 连接器的独立参数,核心作用是攒批写入、降低与下游的 IO 交互开销。
确定 Sink 的 batch-size 不是靠经验拍数字,而是一套「先划边界、再算基准、压测调优」的标准化流程,核心逻辑是:在不触发硬报错、满足延迟要求的前提下,找到吞吐收益的拐点值。
以下是通用四步方法论 + 主流 Sink 的专属测算规则,你可以直接套用到自己的场景中。
一、通用四步法:从 0 到 1 确定最优值
第一步:先划定「硬约束天花板」(绝对不能超过)
batch-size 不是越大越好,超过以下任意一条边界都会直接报错,必须先算清上限:
下游系统的写入大小限制
这是最核心的硬天花板:单批次总字节数不能超过下游的最大请求包限制。
常见值参考:MySQL
max_allowed_packet(默认 4MB)、Kafkamessage.max.bytes(默认 1MB)、Doris Stream Load 单次默认 100MB。
Flink TaskManager 内存上限
批次数据会缓存在 TM 堆内存中,单批次总大小 = 单条数据平均大小 × batch-size,不能超过算子可用内存的 30%(预留 GC 和其他算子开销)。
低资源 ARM 节点(内存≤4GB)建议进一步收紧到 20%,避免 OOM。
事务 / 请求超时限制
批次越大,单次写入执行时间越长,超过下游的事务超时、请求超时阈值就会直接回滚失败。
比如 MySQL 的
innodb_lock_wait_timeout、接口的 socket 超时时间,都决定了单批次的最大执行时长。
业务延迟 SLA 要求
批次越大,攒批等待时间越长,端到端延迟越高。如果业务要求秒级延迟,批次就不能无限拉大。
第二步:测算理论基准值
先测单条数据的平均大小
抽样 100~1000 条真实业务数据,序列化后计算平均字节数,比如:
小报文日志 / 简单订单:单条约 200B ~ 1KB
普通业务宽表:单条约 1KB ~ 5KB
含 text/blob 大字段:单条约 10KB ~ 100KB+
用硬约束倒推理论最大批次
公式:
理论最大条数 = 下游单包最大字节数 ÷ 单条数据平均大小
理论最大字节数 = 下游单包最大字节数 × 安全系数(0.6~0.7)
安全系数是为了预留协议头、编码开销,避免刚好卡上限报错。
得到初始基准值
取「内存上限、大小上限、超时上限」三个结果中的最小值,作为初始测试的基准值。
第三步:结合业务场景修正初始值
在基准值基础上,根据场景做加减:
Exactly-Once 场景:下调 20%~30%,批次过大时写入失败重试、事务回滚的成本极高。
At-Least-Once 场景:可上调 10%~20%,容错成本更低,优先保吞吐。
流量波动极大场景:下调 10%~20%,避免流量洪峰时批次瞬间打满导致内存飙升。
低峰期占比高场景:重点配套调小「刷盘超时时间」,不要盲目加大批次。
第四步:压测迭代,找到最优拐点
以初始基准值为中点,按 ±30% 的步长做对比压测,观察以下 4 个核心指标,找到收益拐点:
吞吐(records/s):持续加大批次时,吞吐涨幅会逐渐收窄,当涨幅<10% 时,就到达了拐点,再加大批次只会增加延迟和风险,没有收益。
端到端延迟:必须满足业务 SLA 要求,超过阈值就缩小批次。
下游系统负载:下游 CPU、IO、连接数不要打满,预留 20% 以上冗余。
失败率:出现写入超时、数据包过大、OOM 等报错,立即缩小批次。
二、主流 Sink 的专属测算规则
1. JDBC Sink(MySQL/PostgreSQL 等,单位:条数)
对应参数:代码 withBatchSize()、SQL sink.buffer-flush.max-rows
硬约束优先级:
max_allowed_packet> 事务超时 > 内存快速测算示例
MySQL 默认
max_allowed_packet=4MB,单条数据平均 1KB:理论最大条数 = 4×1024KB ÷ 1KB × 0.6 ≈ 2457 条
取整后初始基准值设为 2000 条,再根据压测微调。
必须配套参数:
sink.buffer-flush.interval(刷盘间隔),建议设为 1s~5s,低峰期时间到了就刷写,避免延迟无限累积。
2. Kafka Sink(单位:字节,极易踩坑)
对应参数:batch.size,单位是字节,不是条数,90% 的人都会在这里搞错。
硬约束优先级:
message.max.bytes(Broker 端) > Topic 分区数 > 内存快速测算示例
Broker 单条消息最大 1MB,单条消息平均 1KB:
理论批次大小 = 1MB × 0.7 ≈ 716KB(734003 字节)
常规吞吐场景设为 32KB~128KB,高吞吐日志场景设为 128KB~256KB。
必须配套参数:
linger.ms(攒批等待时间),默认 0ms。只调大batch.size不调linger.ms,批次永远攒不满,等于白调;通常设为 5ms~50ms,二者满足其一就发送。
3. OLAP / 数仓 Sink(Doris/StarRocks/ClickHouse)
这类 Sink 天生依赖批量写入,小批次会产生大量小文件,严重拖累查询性能,批次上限远高于关系型数据库。
硬约束优先级:单次导入大小上限 > Checkpoint 周期 > 内存
建议测算逻辑
优先按「字节大小」控制,而非条数:
Doris/StarRocks Stream Load:单批次 64MB ~ 256MB,对应条数约 1 万~10 万条
ClickHouse:单批次 10MB ~ 50MB,对应条数约 1000~10000 条
关键原则:批次写入频率要和 Checkpoint 周期对齐,避免产生过多小版本 / 小文件。比如 1 分钟 Checkpoint,就保证 30s~60s 攒满一个批次。
三、关键避坑提醒
不要只调 batch-size,忽略时间阈值
batch-size 是「量够就发」,时间阈值是「时间到就发」,二者是「或」的关系,必须配套设置,否则低峰期延迟会爆炸。
大字段场景不要按条数配置
如果数据含大文本、二进制字段,务必按字节大小控制批次,不要按条数,否则很容易触发下游包大小限制,或者直接 OOM。
ARM 低资源节点保守调优
同配置下 ARM 架构的内存吞吐、GC 表现弱于 x86,建议在测算结果基础上下调 30% 左右,优先保证稳定性。
不要追求极限值
到达吞吐拐点后,再加大批次只有风险没有收益,生产环境建议在拐点值基础上再预留 20% 冗余。
四、建议值和调优逻辑
下面按最常见的几类 Sink 分别给出建议值和调优逻辑,搭建可以根据自己的写入目标对应参考。
1.关系型数据库 JDBC Sink(最常用,MySQL/PostgreSQL 等)
对应参数:代码中 JdbcSink.withBatchSize()、Flink SQL 中 sink.buffer-flush.max-rows
官方默认值:50~100 条
建议配置值
常规业务场景(单条记录 1KB 以内,普通增删改):1000 ~ 5000 条
高吞吐小数据(单条 < 100B,纯插入无更新):5000 ~ 10000 条
大宽表 / 含大字段(text/blob/ 长字符串):100 ~ 500 条
关键约束
单批次总字节数不能超过数据库
max_allowed_packet限制(MySQL 默认通常 4MB)批次过大会导致单事务执行时间过长,触发数据库事务超时回滚
2.消息队列 Sink(Kafka 为主)
对应参数:batch.size,单位为字节,不是记录条数
官方默认值:16384(16KB)
建议配置值
低延迟优先:保持默认 16KB,甚至调小到 8KB
吞吐优先:32KB ~ 128KB
超高吞吐日志场景:128KB ~ 256KB
关键约束:必须配合
linger.ms(攒批等待时间)一起调,二者共同决定批量大小和延迟的平衡,只调大batch.size效果有限。
3.OLAP / 数仓类 Sink(Doris/StarRocks/ClickHouse/Hudi)
这类 Sink 天生适合批量写入,过小的批次会产生大量小文件 / 小分区,严重拖累下游查询性能。
建议配置值
Doris/StarRocks(Stream Load 模式):按行数 1 万~10 万条,或按字节 64MB ~ 256MB
ClickHouse:1000 ~ 10000 条,或单批次 10MB ~ 50MB
Hudi/Iceberg:按 checkpoint 周期对齐,单批次写入量建议 128MB ~ 512MB
五、核心调优原则
单条数据大小:记录越瘦小,批次可以越大;含大字段必须缩小批次,避免 Flink TM OOM 和下游写入报错。
下游写入能力:关系型数据库抗大批次能力弱,宜偏小;列式数仓抗大批次能力强,宜偏大。
延迟要求:批次越大,吞吐越高,但端到端延迟越高;实时性要求高的场景优先保证延迟,不要盲目追求大批次。
容错成本:批次越大,写入失败时重试 / 回滚的数据量越多,Exactly-Once 场景建议不要设置过大。
资源限制:如果是资源受限的边缘 ARM 节点(内存 < 4GB),建议在上述建议值基础上下调 30%~50%,避免内存溢出。
六、通用最佳实践
起步先按场景取中间值,再根据压测结果微调,不要一开始就拉满。
batch-size 不是越大越好:超过临界值(比如 JDBC 超过 1 万条)后,吞吐提升非常有限,但延迟和故障风险会显著上升。
原文链接
欢迎访问 小易撩挨踢