事件驱动读写分离,如何验证在 10 万 QPS 下读库无延迟积压
解读
- 业务场景:国内互联网主流采用“写主库、读从库”的异步复制架构,事件驱动指写操作完成后通过 MQ、binlog 订阅或 Canal 触发读库更新。
- 核心风险:高并发读时,若复制延迟 > 业务容忍阈值(通常 50 ms 以内),就会出现“刚写完读不到”的脏读,表现为用户反复提交、订单重复创建等业务投诉。
- 验证目标:在 10 万 QPS 读流量下,读库复制延迟(lag)始终 ≤ SLA,且队列无堆积,CPU/IO 未饱和。
- 面试考点:能否把“无延迟积压”拆成可观测指标 → 设计可复现的压测模型 → 用中国特色工具链落地 → 给出通过标准与兜底方案。
知识点
- 复制延迟指标:Seconds_Behind_Master(MySQL)、lag 位点差(Kafka)、Canal 消费位点差;需区分“网络延迟”与“SQL 执行延迟”。
- 事件驱动链路:主库 commit → binlog 落盘 → dump 线程 → 从库 IO 线程 → relay log → SQL 线程 → 从库刷盘;任何一环慢都会积压。
- 压测模型:
a. 读写比例:国内电商下单场景常见 1:10~1:50,面试可直接说“按 1:20 建模”,即 5 k 写 QPS、95 k 读 QPS。
b. 数据热点:采用 Pareto 分布,20% 记录承担 80% 查询,模拟真实缓存穿透。
c. 事务模型:写操作带 3 条 insert + 2 条 update,保证 binlog 量足够大。 - 观测工具:
- 阿里云 DTS 控制台、腾讯云 DBbrain 可直接看“复制延迟曲线”;
- 开源侧用 pt-heartbeat 精确到毫秒级;
- 如果走 Canal → MQ → 业务消费,需监控 MQ 堆积量(Kafka lag)。
- 通过标准:国内大厂内部基线“P99 延迟 ≤ 50 ms 且连续 15 min 无抖动”,面试可直接引用。
- 瓶颈定位:
- IO 线程慢:主库 binlog 产生速度 > 网络带宽(常见 1 Gbps 网卡打满);
- SQL 线程慢:从库索引缺失、锁冲突、单线程回放;
- 事件消费慢:Canal 实例数 < 分区数,或下游 Redis 写耗时高。
- 兜底手段:
- 并行复制(MySQL 5.7 logical_clock)、binlog_group_commit;
- 读写流量分桶:关键读强制走主库(flag=1),非关键读走从库;
- 客户端重试 + 版本号比对,延迟大时自动降级到主库。
答案
“验证 10 万 QPS 下读库无延迟积压”分五步落地:
第一步,建立可观测基线
在主库与每个从库部署 pt-heartbeat,精度 0.1 s,输出到 Prometheus;同时拉取阿里云 DTS 的“复制延迟”指标做交叉校验,确保观测误差 < 5 ms。
第二步,设计压测场景
用公司自研 Gatling 框架(或阿里云 PTS)构造 1:20 读写比:5 k 写 QPS 均匀散列到 8 张表,95 k 读 QPS 按 Pareto 80/20 热点访问。数据量级 1 亿行,表带 3 个二级索引,关闭查询缓存,确保每次读都走磁盘或 InnoDB buffer。
第三步,资源对等与监控
读库规格与主库同配置(32 C128 G + ESSD PL1 3 W IOPS),提前跑 30 min 预热,让 buffer pool 命中率 > 99%。压测侧同步监控:QPS、P99 响应、CPU、IOPS、网卡吞吐、Seconds_Behind_Master、Canal 消费位点差、Kafka lag。
第四步,执行与判定
阶梯加压:0→2→5→8→10 万 QPS,每阶持续 10 min。判定标准:
- 复制延迟 P99 ≤ 50 ms;
- 从库 relay log 文件大小持续 < 100 MB;
- CPU 使用 ≤ 60%、IOPS ≤ 70%、网卡 ≤ 60%;
- Canal 消费组 lag 连续 5 次采样为 0。
四项同时满足即通过,否则记为失败。
第五步,瓶颈定位与优化
若延迟突刺,先看网卡是否打满 → 升级 10 Gbps;
若 IO 线程正常但 SQL 线程慢 → 打开 slave_parallel_workers=16,调大 binlog_group_commit_sync_delay=100 μs;
若单条大事务造成 lag → 业务侧拆事务,单条 insert 批大小 ≤ 1 k 行;
若 Canal 消费慢 → 增加 partition 数到 24,消费组扩容到 24 实例,保证 partition:实例=1:1。
优化后回归第二步,直到连续 2 小时压测无异常,输出《读写分离高可用压测报告》并邮件周知 DBA、业务、SRE 三方。
拓展思考
- 如果业务要求“零延迟读”,是否干脆放弃读写分离?
答:国内金融支付场景采用“半同步复制 + 强一致读”或干脆走分布式数据库(OceanBase、TiDB),但成本翻倍;面试可回答“在成本允许下,优先用强一致方案,否则接受 50 ms 延迟并通过客户端补偿”。 - 云原生环境多 AZ 部署,跨可用区 2 ms RTT,如何评估网络对复制延迟的影响?
答:用 tc 命令模拟 2 ms 延迟跑 baseline,发现 10 万 QPS 下仅增加 3 ms lag,证明网络不是瓶颈;若未来跨 Region,需引入 Global Database 或 CRDS 只读实例。 - 事件驱动链路引入 MQ 后,如何防止消息乱序导致读脏数据?
答:Canal 侧按表+主键 hash 到固定 partition,保证同一行变更顺序消费;下游用 Redis 版本号做 CAS,版本号落后时拒绝更新,并报警通知业务回查主库。