当“加固”变成“炸点”:Cloudflare 11·18 事故随想
一条 SQL 的蝴蝶效应,给所有人的三个提醒
一、先抛结论,再讲故事
- 11 月 18 日,Cloudflare 全球宕机 5 小时 46 分,根因不是 DDoS,而是一条漏写
WHERE database=的 SQL。 - 任何“内部配置”都要当“用户输入”来防;任何“小权限优化”都要当“全链路变更”来审。
- 把“能回滚”做成“一键杀”,比“能灰度”更重要;把“可观测”做成“可定位”,比“多监控”更值钱。
二、时间线速写(所有时间 UTC+8)
- 19:05 数据库权限补丁上线,开始滚动重启 ClickHouse 节点。
- 19:20 首个 5xx spike 出现,Bot Management 特征文件尺寸翻倍 → 代理 panic。
- 19:32 内部告警响起,on-call 误判为“超大规模 DDoS”。
- 21:05 给 Workers KV、Access 做了“紧急Bypass”,部分流量恢复。
- 22:24 停止特征文件自动生成,手动灌入“上周备份”。
- 22:30 核心流量回到基线。
- 01:06 最后一条长尾 5xx 消失, incident close。
三、技术细节,一句话版本
ClickHouse 的分布式表分两层:default(逻辑视图)和 r0(物理分片)。
为了“让子查询跑在用户账号下”,运维把 r0 的元数据可见性打开;
特征生成脚本只按表名捞列,结果把两份 schema 当成双倍特征写进文件;
Rust 代码里硬编码 MAX_FEATURES=200,直接 panic,cascade 失败。
四、三个深坑,对照自查
坑 1:配置 ≠ 代码,却按代码走灰度
- 特征文件是“数据面”配置,分钟级全网扩散,却没用“版本号+回滚通道”封装。
- 如果把它当成“普通代码”,至少要有 staged canary:先 1%→5%→20%→100%。
- 教训:任何能触发进程 panic 的“文件”,都要走“红蓝双桶”模型——新文件先读、不 crash 再切流。
坑 2:权限变更 ≠ 性能变更,却缺回归 Case
- DBA 视角:只是“让用户看到本来就能访问的列”,属于安全加固。
- 研发视角:schema 结果集翻倍,属于语义破坏。
- 两边都没写端到端回归,因为“只是权限”。
- 教训:只要查询结果可能变长,就是“契约变更”,必须加 diff 断言。
坑 3:观测丰富 ≠ 观测清晰,错把噪音当信号
- 为了抓“攻击”,开了全量采样 + 堆栈 dump,CPU 打满,延迟雪上加霜。
- 同时 status.cloudflare.com 正好也挂(外部供应商),两条曲线一叠加,心理暗示“这是协同攻击”。
- 教训:应急观测要“分级闸门”——先保业务,再保排障;采样策略必须能 10s 内一键关。
五、给自己的作业清单
把“能回滚”做成平台能力
- 任何文本型配置→对象存储→带版本→带签名→统一 Agent 拉取;
- Agent 里内置“大小/哈希/字段数”三重校验,超限自动 reject。
把“权限变更”塞进 CI
- 用 ClickHouse 的
EXPLAIN SYNTAX把“变更前后”结果集拍 diff; - 超过 1% 行数变化就阻断 MR,让 DBA 和研发一起 review。
- 用 ClickHouse 的
把“观测开关”做成红色按钮
- 采样、debug log、core dump 各带全局 kill 开关,写入 on-call 手册第一页;
- 每周做一次“关灯演练”,确保 30 秒内能关掉高耗观测。
六、写在最后
很多人把这次事故当成“一条 SQL 引发的血案”,我却更愿意叫它“一次完美风暴”:
- 小变更(权限可见性)× 隐式依赖(脚本无库过滤)× 硬编码阈值(200 特征)× 分钟级扩散(文件热更新)× 认知偏差(DDoS 先入为主)。
链条里任意一环如果多 10 分钟思考,都不会炸成全球新闻。
SRE 的日常工作,就是跟“完美风暴”抢那 10 分钟。
愿下一次,我们都能提前把蝴蝶的翅膀捆好,让风暴只在 PPT 里发生。
(全文 1 100 余字,首发于 lyuy.top,转载请注明出处。)
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 运阳的小窝
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果