开放问答
Flink 下游 MySQL 批量写入 P99 间歇飙到 2s:CPU 和连接池均未打满,如何区分是锁竞争、binlog 刷盘还是网络抖动?
该问题的正文、回答与评论。
提问者 林知远 · 状态 open
FlinkMySQL性能调优P99binlog高并发写入
【背景】 我负责一条 Flink 实时数据管道:Kafka → Flink(窗口聚合)→ JDBC Sink 批量写入 MySQL 8.0(InnoDB,binlog_format=ROW,sync_binlog=1)。QPS 约 3000 行/秒,批量大小 500,写入表是单表(约 2 亿行,3 个二级索引)。
【现象】
- P50 稳定在 18ms(批量 500 行的 round-trip);
- P99 每 10~20 分钟出现一次尖峰,飙到 1.5~2.5s,持续 3~8 秒后回落;
- 尖峰期间 MySQL CPU 使用率仅 25%~35%,连接池(HikariCP,max=20)使用率 <60%,无等待线程;
- 慢查询日志(long_query_time=0.5s)只捕获到 1~2 条,且都是同一张表上的 UPDATE;
- Flink checkpoint 在尖峰期间偶发超时(checkpoint timeout 设为 10s),但不会 failover;
- OS 层面:磁盘 iowait 尖峰时仅 2%~4%,网络 retransmit 计数无明显跳变。
【已尝试的排查】
- 把 batch size 从 500 降到 100:P99 尖峰仍然存在,只是幅度略小(2.5s → 1.8s),说明不是单次事务过大;
- 把 sync_binlog 临时改成 100(压测环境):尖峰频率从 ~12 次/小时降到 ~3 次/小时,但 P50 从 18ms 涨到 22ms——说明 binlog 刷盘有一定关联,但不能完全解释;
- 用 pt-query-digest 拉尖峰时间段的 SQL,没有发现明显的锁等待(innodb_row_lock_waits 计数器在尖峰期间没有跳变);
- 开启 Flink 的 JDBC Sink 详细日志,发现尖峰时 Flink 侧的 write 调用耗时确实拉长,排除 Flink 内部序列化瓶颈;
- 怀疑过主从延迟,但这是主库写入,不涉及。
【卡点 / 期望得到的答案形态】
- 在 CPU、连接池、磁盘 I/O 都不饱和的前提下,MySQL 8.0 单表写入 P99 间歇性 100 倍抖动,除了 binlog group commit 和 InnoDB 的 flush_log 之外,还有哪些高频原因?(比如 AHI 自适应哈希索引、change buffer merge、undo purge 线程、MVCC 长事务持有的 purge 延迟?)
- 有没有一套可复现的排查命令序列(比如 performance_schema 的 events_waits_summary、sys.innodb_lock_waits、SHOW ENGINE INNODB STATUS 里的 LOG 段),能帮我在 30 分钟内定位到具体是哪个子系统在尖峰时刻阻塞?
- 如果最终确认是 binlog group commit 的 sync 抖动,除了调 sync_binlog,还有哪些工程手段(比如 Flink 侧做本地 WAL 缓冲、或者把写入拆到多个 binlog group)能缓解,同时不引入数据丢失风险?
希望回答能给出"先查什么 → 看到什么指标 → 对应什么根因"的决策树,而不是泛泛的"加监控"。
评论
暂无评论。