高并发流量治理实战(10):大促 48 小时:一次全链路压测与扩容演练复盘
发布时间:2026/9/28 4:49:45来源:尧图网络
最后一篇把九篇机制装进一个真实的 48 小时系列完结篇不再引入新机制而是把前九篇按进一次真实节奏里某电商平台年货节T-48h 全链路压测T-0 零点峰值T24h 复盘。作者是当晚值班 SRE复盘文档脱敏后如下。看的时候不妨拿着前九篇当检查表——你会发现每一个惊险时刻背后都对应某一篇里平时不做、战时必炸的那件事。T-48h压测之夜两颗雷压测按第 9 篇的剧本执行压测标贯穿、影子库、阶梯加压。第一颗雷在 T-46h数据组报告影子表里混进真实订单号段。排查半小时定位——补偿定时任务丢标正是第 9 篇实验里泄漏点的全部来源主链路同步调用和 MQ 透传都正确坏在凌晨重放待办的新上下文。修复走出身随数据走待办表加traffic_origin列离线任务按列分流。第二颗雷在最后一轮极限压入口推到预估峰值的 1.4 倍时券服务的熔断器参数暴露问题——慢调用阈值还是按日常 RT 配的压测流量一来大面积误熔断。这对应第 3 篇参数扫描那张表检出延迟和误伤是硬交换而健康画像本身随负载漂移阈值必须在压测态下重标定不能只在平静期看。T-24h扩容与预热的算术压测定了容量接下来是钱怎么花。把各服务压测得到的单机安全水位、当前节点数、今晚预估峰值入口 9000 rps 按调用放大比折算放进计算器importmath# 扩容账: 压测单机安全水位 - 今晚预估需求(放大比 x 冗余系数) - 节点数与限流反推# 入口今晚预估峰值 BASE_PEAK 9000 rpsBASE_PEAK9000svc{# 名称: (单机安全rps[压测得出], 当前节点, 调用放大比, 冗余系数)gateway:(900,12,1.00,1.2),order:(160,24,0.75,1.3),coupon:(420,8,1.25,1.3),inventory:(700,16,1.10,1.2),risk:(150,10,0.15,1.1),# 抽样评估, 放大比 1}print(服务 单机 当前 需求 应配 动作)total_add0plans[]forname,(per_node,nodes,amp,coef)insvc.items():targetBASE_PEAK*amp*coef needmath.ceil(target/per_node)addmax(0,need-nodes)total_addadd act扩 %d 台%addifaddelse(持平ifnodesneedelse冗余 %d 台, 不缩%(nodes-need))plans.append((name,per_node,need,target))print(%-12s %5d %5d %7.0f %6d %s%(name,per_node,nodes,target,need,act))print(合计新增 %d 台; 冗余只扩不缩, 缩容决策留到复盘周会%total_add)print(\n限流反推(网关接口窗口 扩容后集群容量 x 0.9, 压的是总量不是需求):)forname,per_node,need,targetinplans:capper_node*need*0.9print( %-12s 容量 %6.0f rps - 窗口 %6.0f rps | 今晚需求峰值 %.0f%(name,cap,cap,target))运行输出服务 单机 当前 需求 应配 动作 gateway 900 12 10800 12 持平 order 160 24 8775 55 扩 31 台 coupon 420 8 14625 35 扩 27 台 inventory 700 16 11880 17 扩 1 台 risk 150 10 1485 10 持平 合计新增 59 台; 冗余只扩不缩, 缩容决策留到复盘周会 限流反推(网关接口窗口 扩容后集群容量 x 0.9, 压的是总量不是需求): gateway 容量 9720 rps - 窗口 9720 rps | 今晚需求峰值 10800 order 容量 7920 rps - 窗口 7920 rps | 今晚需求峰值 8775 coupon 容量 13230 rps - 窗口 13230 rps | 今晚需求峰值 14625 inventory 容量 10710 rps - 窗口 10710 rps | 今晚需求峰值 11880 risk 容量 1350 rps - 窗口 1350 rps | 今晚需求峰值 1485三个读表要点。瓶颈不在入口在服务链中间网关和风控持平券服务要扩 27 台——只看入口容量的规划会在最薄弱环节爆炸这也是第 1 篇每层都要有闸的另一面每层都要有容量账。限流窗口刻意压在容量线上而不是需求线上gateway 窗口 9720 低于 1.2 倍冗余后的需求 10800意思很直白——如果流量真到 1.2 倍预测值宁可拒一部分也不让系统进非线性恶化区第 9 篇那条悬崖不是山坡的曲线。热点 Key 的功课在这天收尾晚八点开抢的爆款提前两小时按第 5 篇流程预热进 L1/L2探测器的名单下发演练了一遍——预热没演练过等于没预热。T-020:03缓存分片惊魂零点峰值平稳过渡所有人开始松懈时真正的考题来了20:03缓存集群一个分片被变更脚本误重启命中率从 96% 掉到 61%回源洪峰砸向数据库。把当晚的两套走向各回放一遍DB 服务力 600 rps虚拟分钟时钟# 大促当晚回放(虚拟分钟时钟): 20:00 基线 2000 rps 线性爬坡, 21:00 峰值 ~13400# 20:03 缓存一个分片被误重启 - 命中率 96%-61%, 20:06 切回; DB 服务力上限 600 rpsSLOPE,POOL190,600HIT0,HIT_BAD0.96,0.61defsim(protect):backlog0.0print(场景: %s%(开启 DB 入口自适应拒绝ifprotectelseDB 不设防(现状)))forminrange(8):q2000SLOPE*m hitHIT_BADif3m5elseHIT0 demandq*(1-hit)servedmin(demand,POOL)ifprotect:print(20:%02d 前端 %5d rps | 要DB %5d | DB扛 %4d | 拒绝 %4d%(m,q,demand,served,demand-served))else:backlog(demand-served)*60# 一分钟排进的队print(20:%02d 前端 %5d rps | 要DB %5d | DB扛 %4d | 累计排队 %6d 请求%(m,q,demand,served,backlog))returnbacklog bsim(False)print(- DB 侧最多堆出 %d 个请求, 队尾等待 %.0f 秒: 上游全超时重试放大, 雪崩成立\n%(b,b/POOL))sim(True)print(- 排队变拒绝: DB 存活, 超额流量在前端表现为排队页/降级页(第4篇预案))运行输出场景: DB 不设防(现状) 20:00 前端 2000 rps | 要DB 80 | DB扛 80 | 累计排队 0 请求 20:01 前端 2190 rps | 要DB 87 | DB扛 87 | 累计排队 0 请求 20:02 前端 2380 rps | 要DB 95 | DB扛 95 | 累计排队 0 请求 20:03 前端 2570 rps | 要DB 1002 | DB扛 600 | 累计排队 24138 请求 20:04 前端 2760 rps | 要DB 1076 | DB扛 600 | 累计排队 52722 请求 20:05 前端 2950 rps | 要DB 1150 | DB扛 600 | 累计排队 85752 请求 20:06 前端 3140 rps | 要DB 125 | DB扛 125 | 累计排队 85752 请求 20:07 前端 3330 rps | 要DB 133 | DB扛 133 | 累计排队 85752 请求 - DB 侧最多堆出 85752 个请求, 队尾等待 143 秒: 上游全超时重试放大, 雪崩成立 场景: 开启 DB 入口自适应拒绝 20:00 前端 2000 rps | 要DB 80 | DB扛 80 | 拒绝 0 20:01 前端 2190 rps | 要DB 87 | DB扛 87 | 拒绝 0 20:02 前端 2380 rps | 要DB 95 | DB扛 95 | 拒绝 0 20:03 前端 2570 rps | 要DB 1002 | DB扛 600 | 拒绝 402 20:04 前端 2760 rps | 要DB 1076 | DB扛 600 | 拒绝 476 20:05 前端 2950 rps | 要DB 1150 | DB扛 600 | 拒绝 550 20:06 前端 3140 rps | 要DB 125 | DB扛 125 | 拒绝 0 20:07 前端 3330 rps | 要DB 133 | DB扛 133 | 拒绝 0 - 排队变拒绝: DB 存活, 超额流量在前端表现为排队页/降级页(第4篇预案)同一个故障、同一份流量两个世界的分岔只有一处超额的部分是排队还是被当场拒绝。不设防时 DB 的服务率没变每分钟照样 600变化的是队列悄悄堆到 8.6 万——队尾等待 143 秒早已越过所有上游的超时线超时触发重试重试再注入新流量这就是雪崩的动力学。而自适应拒绝版里三分钟内 1428 个请求被当场弹回用户看到的是第 1 篇精心设计的排队页不是第 3 篇最坏情况的白屏换来 DB 全程水位 600 一条直线。当晚真实走向是第二幕20:05 值班长按预案第 2 档降级非核心推荐切快照、下单链路保持20:06 分片切回全程无订单丢失代价是一千余人次用户在窗口内收到前方拥挤。T24h复盘与系列的最后一条建议复盘会按无指责blameless原则过三个问题探测为什么慢命中率监控 2 分钟粒度故障 90 秒即自愈型事件几乎不可见——改为 10 秒粒度加环比告警预案为什么只动到第 2 档第 4 篇的分级表里自动触发第 3 档的条件写的是 DB 连接数而不是排队深度这次排队深度恰好先于连接数越线——参数联动清单更新压测为什么没压出这颗雷压测剧本里没有依赖组件运行中被杀这一章——第 9 篇的常态化压测清单里加入故障注入。复盘产出的不是文档是带 owner 和期限的账当晚的行动项后来长成四件事一是监控资产化——“缓存命中率环比骤降”“DB 排队深度”fast-fail 计数这三个当晚救命的信号从个人经验变成全员订阅的标准面板每个治理机制限流拒绝数、熔断开闸事件、位点等待超时降级次数都必须有自己的指标熔而不觉、限而不查等于没做二是开关认领制——第 4 篇降级矩阵里的每一档开关登记唯一 owner 与 backup演练时随机点名答不出这个开关现在什么值、拉下去影响哪个指标的当场记缺三是参数回灌例会——每次大促和故障后的实测数字单机安全水位、读 P99、复制 lag 峰值回填进限流窗口、双删 delay、粘主时长这三张配置表参数改动走发布流程而不是口头共识四是混沌常态化——每月在低峰期随机杀一个缓存分片、注入一次从库延迟、制造一轮时钟回拨第 6 篇的老朋友让预案被触发从年度大事件变成月度演习科目真正的故障来临时所有人的肌肉记忆来自上个月而不是去年。这就是系列压轴的观点限流、熔断、降级、缓存、复制、压测不是六堆各自独立的开关而是一张互相咬合的网——第 1 到 5 篇管流量的形状总量分层拦、单键多级接、坏依赖快刀断、撑不住主动舍第 6 到 8 篇管数据的秩序写有唯一的名字、改有收敛的路径、读有可预期的新鲜度第 9、10 篇负责在和平时期演练前者、在战争时期兑现后者。这张网没有终态每次大促的曲线、每次故障的时间线都要回灌成下一版容量表和预案表。系列到此完结愿你的大促复盘文档永远只有预案生效这一种剧情。参考来源Google SRE Workbook: Postmortem Culture: Learning from Failure: https://sre.google/workbook/postmortem-culture/Google SRE Book: Handling Overload过载处理与限流拒绝: https://sre.google/sre-book/handling-overload/Wikipedia: Chaos engineering故障注入: https://en.wikipedia.org/wiki/Chaos_engineeringWikipedia: Postmortem documentation: https://en.wikipedia.org/wiki/Postmortem_documentation本系列已结集为免费专栏高并发流量治理实战从限流到全链路压测进阶推荐付费专栏提示词工程实战从入门到生产级 Prompt 设计限时 ¥19.9首篇免费试读
网站建设高端定制企业官网