开放问答
Kafka 消费端写 MySQL 再 del Redis,del 失败 30 秒窗口内 offset 该不该 commit
该问题的正文、回答与评论。
提问者 江砚舟-305 · 状态 open
Kafka缓存一致性Redis消息中间件幂等
【背景】
Kafka 2.8(3 broker,min.insync=2)承载订单事件 topic order-events,6 分区,消费组 3 实例(每实例 2 分区)。下游是 MySQL 8.0 写订单表 + Redis 6.2 集群做读加速(订单缓存,TTL 30 分钟,读 QPS 约 8k,命中率 70%)。业务规则:以 DB 为准,Redis 仅作读加速。消费端代码顺序是:BEGIN → INSERT INTO orders → COMMIT → redis.del(orderKey) → consumer.commitSync(),enable.auto.commit=false。
【现象 / 卡点】 上周 Redis 集群做了一次主从切换,del 命令超时窗口约 25 秒。我观察到的两种处理姿势各有硬伤:
- 方案 A(忽略 del 失败继续 commit):切换恢复后缓存里残留旧值最长 30 分钟(受 TTL 限制),8k QPS × 70% 命中率下,C 端读到旧价格/旧库存的概率不低,业务侧已经收到 2 起客诉。
- 方案 B(del 失败抛异常,offset 不 commit):rebalance 后另一实例从旧 offset 重放,但订单表是 INSERT(业务 id 在生成阶段已确定,没有唯一键约束),重放直接多写一行;即便改成 UPSERT,"先写 DB 再删缓存"的顺序在重放里被打乱,仍可能读到旧值。
【已尝试的排查与结果】
- 给 del 加 3 次重试 + 指数退避(100ms / 400ms / 1600ms),25 秒窗口内仍全部超时,没救回来;
- 改成"先 del 再写 DB",DB 写失败时缓存已删,C 端直接穿透到 MySQL,单实例 QPS 从 ~1.5k 飙到 9k,主库 CPU 打满;
- 给缓存 value 加 updatedAt 版本号,读端比对 DB 版本——但要求 4 个读侧服务全改,跨团队排期没下来。
【期望得到的答案形态】
- 方案 A 与方案 B 在 25–30 秒 Redis 不可用窗口内的具体行为差异:哪些请求会读到旧值、哪些会重复写、量级大概多少(哪怕是估算);
- 有没有一种"DB 写 + 缓存失效"的落地姿势,能在 Redis 短时不可用时既不丢更新、也不放大重复写——比如延迟双删、缓存 version 字段、或基于 binlog/CDC 的异步失效,请给出具体的代码顺序与边界条件;
- 如果必须二选一,按"DB 为准、缓存读加速"的语义,你们生产上选哪个、为什么,最好带一个具体事故案例或线上数据。
评论
暂无评论。