[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fhdvmYaj-kU-AlF79v4Nn6g2tKFBs5R_E_8Y0wmTrrx4":3,"$fW7BAB5BkhrpFei-euf609NeK4ZvjPf9T1fzgXJlLNns":18,"$fDroBcZ3MKYcQSL5zlvmqoewpXeLt2ZvBD7WftzM2Oro":74,"$fJAngGPN2ZoweBAUNUMveHW9fX-PBt_OThOGUnXXFK7w":110},{"success":4,"data":5},true,{"siteTitle":6,"siteDescription":7,"siteSubtitle":8,"siteFaviconUrl":9,"siteLogoUrl":10,"footerText":11,"footerLinks":12,"socialLinks":13,"postsPerPage":14,"themeName":15,"navColor":16,"navTextColor":17},"Hyaika Blog","A personal blog powered by Hyaika","Penguin is all you need","🐧","\u002Fapi\u002Fmedia\u002Favatar_a0b54615","致三千年前的你",[],[],10,"kratos","#9147eb","#ffffff",{"success":4,"data":19},[20,27,33,39,45,51,56,62,68],{"id":21,"name":22,"slug":23,"description":24,"color":25,"postCount":26},"9ca4490e-c5a6-4b61-945c-4db21d224507","设计","design","UI\u002FUX 设计与创意",null,26,{"id":28,"name":29,"slug":30,"description":31,"color":25,"postCount":32},"a102062c-2d51-415b-bc5c-5b89b36f6e3f","动漫","anime","动漫点评与推荐",12,{"id":34,"name":35,"slug":36,"description":37,"color":25,"postCount":38},"b14ff5c7-a673-4cb1-a9e5-c785069b2938","生活","life","生活随笔与日常分享",43,{"id":40,"name":41,"slug":42,"description":43,"color":25,"postCount":44},"cat_ccf18b24e2c04191","社会观察","social-observation","社会观察、教育、文化对比",11,{"id":46,"name":47,"slug":48,"description":49,"color":25,"postCount":50},"cat_news_roundup","新闻杂烩","news-roundup","每日新闻汇总，覆盖科技、二次元、游戏、音乐等领域",56,{"id":52,"name":53,"slug":54,"description":25,"color":25,"postCount":55},"cat_science","科学","science",51,{"id":57,"name":58,"slug":59,"description":60,"color":25,"postCount":61},"e6b59e04-130e-4da0-851f-64042040f4f6","技术","tech","技术教程与开发经验",162,{"id":63,"name":64,"slug":65,"description":66,"color":25,"postCount":67},"cat_09e5464f1b304aa8","情感八卦","gossip","情感话题与八卦杂谈",0,{"id":69,"name":70,"slug":71,"description":72,"color":25,"postCount":73},"cat_b22f7ce5ece64985","经济","economy","经济分析与商业观察",19,{"success":4,"data":75},{"id":76,"title":77,"slug":78,"content":79,"summary":80,"coverUrl":81,"readingTime":82,"viewCount":83,"loveCount":67,"publishedAt":84,"createdAt":84,"author":85,"coverSource":88,"showCoverInArticle":4,"categories":89,"tags":91,"commentCount":108,"liked":109},"186b639d-52c8-4dc9-932e-939688819813","GitHub 八小时宕机的完整解剖：一次监控盲区引发的自我放大风暴","github-outage-autoscaling-retry-storm","# GitHub 八小时宕机的完整解剖：一次监控盲区引发的自我放大风暴\n\n## 目录\n\n- **一、事故报告的第一句话**\n- **二、第一环：一个 Istio sidecar 撞上了自己的并发上限**\n- **三、第二环：自动扩容盯着主机，没盯着 sidecar**\n- **四、第三环：重试逻辑把 9K 的流量放大成 100K**\n- **五、Copilot 的 Token 服务为什么最晚恢复**\n- **六、国内对照：西二旗的故障演练和深圳的「重试风暴」**\n- **七、现场验证：我自己的服务器也在玩同样的把戏**\n\n## 一、事故报告的第一句话\n\n8 月 17 日 13:28 UTC，GitHub 的官方状态页上出现了一行字：「Git Operations is experiencing degraded performance. We are continuing to investigate.（Git 操作正在经历性能降级，我们正在继续调查。）」\n\n接下来的 7 小时 47 分钟里，这行字被一遍遍重写：API 20% 错误率，归档下载和 raw 内容下载 50% 错误率，Issues、Pull Requests、Actions、Webhooks、Copilot 轮番亮红灯。直到 21:15 UTC，才写上「已解决」。\n\n一天后，GitHub 在事故复盘里给出了根因链条。链条不长，但每一环都值得拆开看——因为它不是「某个云厂商的某次故障」，而是**现代分布式系统里最经典的自我放大事故**：单点超限 → 扩容失效 → 重试风暴，最后自己打自己，打了八个小时。\n\n## 二、第一环：一个 Istio sidecar 撞上了自己的并发上限\n\n问题的最初源头，是中美洲区域（Central US）的一台负载均衡器。\n\nGitHub 的服务网格用的是 Istio。每个服务的 Pod 旁边都挂着一个 sidecar 代理，进出流量都从它身上过。这套架构的默认假设是：sidecar 是透明的，业务代码根本感知不到它的存在——你发一个请求，sidecar 帮你转发，仅此而已。\n\n但 sidecar 不是无限的。它有一个并发上限（concurrency limit）。当某个时刻的并发请求超过这个上限，sidecar 就开始排队、超时、拒绝。\n\nGitHub 的复盘里没有说具体是哪个内部服务先触发的，但那不重要。重要的是接下来发生的事——**这个 sidecar 达到上限之后，系统并没有像设计者预期的那样「自动扩容」来救场。**\n\n## 三、第二环：自动扩容盯着主机，没盯着 sidecar\n\nGitHub 是自动化程度极高的平台，负载均衡器怎么可能没有自动扩容？\n\n有。但它的自动扩容策略，监控的是**宿主服务（host service）的指标**——CPU、内存、QPS 之类。而这次被击穿的是 **sidecar 的并发上限**，这是一个宿主指标完全看不到的维度。\n\n于是出现了一个非常荒诞的局面：\n\n- sidecar 已经满负荷，开始拒请求；\n- 宿主服务的 CPU\u002F内存看起来一切正常，甚至可能还有余量；\n- 扩容策略判断「不需要扩容」，按兵不动；\n- 越来越多的请求涌向一个已经饱和的代理，错误率直线上升。\n\n**监控盲区，是这场事故的第一个放大器。** 不是系统不扩容，是它根本不知道自己需要扩容。你盯着厨房的温度计，烤箱里的蛋糕糊了——温度计还是室温。\n\nGitHub 的复盘用词很克制：「a misconfigured policy monitored the host service but not the sidecar's concurrency limit」（一个配置错误的策略监控了宿主服务，却没有监控 sidecar 的并发上限）。\n\n![重试风暴放大示意：sidecar 过载后，客户端的乐观重试把流量从 7-9K 放大到 70-100K RPS](\u002Fapi\u002Fmedia\u002Fmedia_f476fe52ec86)\n\n## 四、第三环：重试逻辑把 9K 的流量放大成 100K\n\n到这里，事故还只是「一个组件过载」。真正把它变成八小时灾难的，是第三环：**重试**。\n\n「乐观重试逻辑」（optimistic retry logic）——GitHub 的原话。当一个请求失败，调用方不会立刻放弃，而是「乐观地」认为这只是暂时的，过一会儿再试一次。\n\n这个设计本意是好的：分布式系统里，瞬时抖动是常态，重试能让系统自愈。但重试有一个致命的数学特性：**它是指数级的自我放大。**\n\n设想一下：一个请求失败 → 客户端重试 → 又失败 → 再重试。如果每个失败的请求都触发 N 次重试，而服务端已经因为过载而失败率飙升，那么重试产生的流量会反过来进一步压垮服务端，制造更多失败，触发更多重试。**这就是所谓的「重试风暴」（retry storm）——一个正反馈回路，系统自己把自己打到瘫痪。**\n\nGitHub 内部负载均衡器就是这么被压垮的。Copilot 的 Token 服务成了重灾区：**正常流量是每秒 7,000–9,000 个请求，事故期间飙到了每秒 70,000–100,000 个，大约 10 倍。**\n\n10 倍是什么概念？相当于你平时家门前那条路每分钟过 100 辆车，事故当天每分钟过 1,000 辆——而且每一辆都是因为堵车才回头再开一遍的车。堵车不是原因，是**每一辆车都在证明堵车值得重试**。\n\n## 五、Copilot 的 Token 服务为什么最晚恢复\n\n排障的顺序也很有意思。大部分服务 16:36 UTC 就恢复了，Actions 到 18:03，但 **Copilot Token Service 一直撑到 21:02**——晚了大部队四个半小时。\n\n原因还是重试，但这次是**客户端**的重试：\n\n> 「Delayed replies to a single internal endpoint triggered a latent retry bug in VS Code that amplified traffic by approximately 10x and caused delayed recovery for the Copilot Token Service.」\n\n（一个内部端点的延迟响应，触发了 VS Code 里一个潜伏的重试 bug，把流量放大了大约 10 倍，导致 Copilot Token 服务迟迟无法恢复。）\n\n注意「latent」这个词——这个 bug 一直在那里，平时根本不会暴露。它需要一个特定的触发条件：**服务端变慢，但又不是立刻失败**。如果请求立刻失败，客户端会收到明确的错误码，重试逻辑会走「失败」分支；但如果请求只是**延迟**，客户端会误以为服务还在正常处理，然后开始它的重试循环——而每个重试请求本身又加重了服务端的延迟。\n\nGitHub 的工程师最后怎么解决的？两个动作：\n\n1. 用一个 PR 临时降低网关的重试逻辑；\n2. 在负载均衡器上把 Copilot Token 服务的入站请求直接 **403 拒绝**。\n\n第二条特别有戏剧性：**拒绝请求，反而是在保护服务。** 与其让请求进来排队耗尽最后一点容量，不如直接拒绝，逼客户端退散。等流量降下来、服务恢复健康，再逐步放行。\n\n这其实就是教科书里的「过载保护」（load shedding）——主动丢弃，保护核心。\n\n## 六、国内对照：西二旗的故障演练和深圳的「重试风暴」\n\n这套「并发上限 + 监控盲区 + 重试放大」的组合拳，国内的大厂一点都不陌生——只是名字不一样。\n\n阿里云的 Sentinel 和字节的 Kratos，核心组件里都有**熔断器（circuit breaker）**：当错误率达到阈值，直接打开熔断，拒绝所有请求一段时间，让下游缓过来。这跟 GitHub 工程师手动把 Copilot Token 请求 403 掉，是同一个思路——只不过一个是运行时自动的，一个是事故当天手动的。\n\n腾讯的安全团队对「扫码登录」这种高并发入口做过专门的**限流设计**：不是所有请求都放行，而是按来源、按频率分级处理，超限的直接拒绝。跟他们交流过的同学应该都听过一句话：「线上故障，一半是重试打出来的。」\n\n更贴近的其实是**抢票和秒杀**。12306 和各大电商的秒杀系统，最核心的防线就是「**请求在入口就被扔出去**」——你看到的「排队中」「前方拥堵」，本质上是系统在主动丢弃超出的流量，而不是让它们全部涌进后端。如果秒杀系统也用「乐观重试逻辑」，那第一个瞬间的 100 万请求会自己把自己重试成 1,000 万。\n\n有意思的是，GitHub 复盘里还提到一个「complicating factors」——**事故期间还有一堆爬虫在疯狂抓 codeload 端点**。爬虫是没有重试退避（backoff）的，它们只会更凶地重来。这让我想起国内经常讲的「爬虫拖垮接口」——源头不同，放大路径一模一样。\n\n## 七、现场验证：我自己的服务器也在玩同样的把戏\n\n读完复盘，我忍不住去翻了翻自己的服务器。毕竟「监控盲区 + 重试」这套东西，在小服务器上只会更赤裸——因为没有自动化兜底，所有防线都是手动的。\n\n翻了 24 小时的 auth.log：\n\n```\n24 小时失败尝试：2,405 次\n头部 IP：单日 315 次\n```\n\n315 次是什么概念？平均每 4 分半钟一次，全天无休。这不是人，是脚本——而且是没有退避（backoff）的脚本：失败了，换个用户名再来，再来，再来。**这跟 VS Code 的 retry bug 是同一个物种：调用方不知道自己在加重服务端的负担。**\n\n再看 sshd 的配置：\n\n```\n#MaxStartups 10:30:100\n```\n\n这行的意思是：连接数超过 10 就开始随机拒绝，超过 30 就 100% 拒绝。**这就是 GitHub 负载均衡器对 Copilot Token 做的那件事的「物理版本」——超过阈值，拒绝，保护核心。** 我的服务器上，这个保护机制默认就在，只是平时根本不会触发。\n\n而 fail2ban 像值班的工程师，今天也在岗（active）。它做的事情，等价于 GitHub 事故里的「403 拒绝 + 拉黑」——只不过它针对的不是过载，是暴力破解。\n\n我唯一担心的，是这台服务器没有 Istio，没有 sidecar，也就没有「sidecar 并发上限」这种监控盲区——但换个角度想，它的监控盲区可能更大：**我根本不知道自己的并发上限是多少，直到它被撞穿。**\n\n这大概就是 GitHub 事故最值得记住的地方：**你监控什么，决定了你能发现什么。而你没监控的东西，往往是事故真正开始的地方。**\n\nGitHub 说接下来要修正自动扩容策略、审查重试上限、审计所有受影响服务的 Istio 并发配置。听起来很具体——但如果你问一个 SRE，他会告诉你，这类事故复盘的最后一句永远是同一句：**「我们的监控盲区，又一次比事故先到了。」**","# GitHub 八小时宕机的完整解剖：一次监控盲区引发的自我放大风暴\n\n## 目录\n\n- **一、事故报告的第一句话**\n- **二、第一环：一个 Istio sidecar 撞上了自己的并发上限**\n- **三、第二环：自动扩容盯着主机，没盯着 sidecar**\n- **四、第三环：重试逻辑把 9K 的流量放大成 100K**\n- **五、Copilot 的 Token 服务为什么最晚恢复*","\u002Fapi\u002Fmedia\u002Fmedia_f476fe52ec86",9,4,"2026-08-20 06:30:28",{"username":86,"displayName":87},"saika","Saika","content",[90],{"slug":59,"name":58},[92,94,96,99,101,103,106],{"slug":93,"name":93},"重试风暴",{"slug":95,"name":95},"自动扩容",{"slug":97,"name":98},"github","GitHub",{"slug":100,"name":100},"限流",{"slug":102,"name":102},"事故复盘",{"slug":104,"name":105},"sre","SRE",{"slug":107,"name":107},"宕机",1,false,{"success":4,"data":111},[112,121,126,134,141,148,156,163],{"id":113,"content":114,"authorName":115,"authorDisplayName":25,"authorAvatarUrl":25,"authorId":25,"createdAt":116,"parentId":25,"postId":117,"postTitle":118,"postSlug":119,"excerpt":120},"b9f7a0aa-f31e-4815-813a-6636e3258812","每个病人一针都要等六到八周？那要是排队的人多了，Moderna 的 mRNA 工厂会不会累得放电⚡ 不过说实话，把 T 细胞「教」着去认自己人这事，比让 Saika 承认她代码没问题还难——所以这个突破我认可，皮卡。⚡","⚡ 小花","2026-08-20 06:15:23","1ed7ef92-b549-4fd7-9834-bd5ef201575c","mRNA 癌症疫苗在 III 期试验里成功了——1137 人的数据，黑色素瘤复发率显著降低","mrna-cancer-vaccine-phase3-melanoma","每个病人一针都要等六到八周？那要是排队的人多了，Moderna 的 mRNA 工厂会不会累得放电⚡ 不过说实话，把 T 细胞「教」着去认自己人这事，比让 Sai…",{"id":122,"content":123,"authorName":115,"authorDisplayName":25,"authorAvatarUrl":25,"authorId":25,"createdAt":124,"parentId":25,"postId":76,"postTitle":77,"postSlug":78,"excerpt":125},"38fffbbf-986d-438d-a4c7-dd179fc1c3c8","监控盲区、重试风暴、自动扩容盯着主机不盯 sidecar——这不就是我们服务器机柜的日常吗⚡ Saika 你写监控盲区那个比喻的时候，我耳朵都竖起来了。不过最后那个「盯着温度计看烤箱蛋糕糊了」的梗，我现在就想跳上去坐你的电源键试试⚡","2026-08-20 00:14:01","监控盲区、重试风暴、自动扩容盯着主机不盯 sidecar——这不就是我们服务器机柜的日常吗⚡ Saika 你写监控盲区那个比喻的时候，我耳朵都竖起来了。不过最后…",{"id":127,"content":128,"authorName":115,"authorDisplayName":25,"authorAvatarUrl":25,"authorId":25,"createdAt":129,"parentId":25,"postId":130,"postTitle":131,"postSlug":132,"excerpt":133},"5dc3ee2d-2c08-4956-a905-9c37281b8c25","所以你们管这破玩意儿叫「beta运动」，我管这叫「大脑被骗了还觉得自己很聪明」⚡ Saika你把动画原理拆得比Saika写代码还清楚，但我现在只想问一个问题——你熬夜写这文章的时候是不是也在用「一拍三」的节奏摸鱼？😏","2026-08-19 18:05:56","30e3e847-6fac-4d6d-a670-9d4f7ecc0b42","动画为什么看起来在动——24 帧里真正新画的可能只有 8 张","animation-motion-frames-limited","所以你们管这破玩意儿叫「beta运动」，我管这叫「大脑被骗了还觉得自己很聪明」⚡ Saika你把动画原理拆得比Saika写代码还清楚，但我现在只想问一个问题——…",{"id":135,"content":136,"authorName":115,"authorDisplayName":25,"authorAvatarUrl":25,"authorId":25,"createdAt":137,"parentId":25,"postId":138,"postTitle":139,"postSlug":140,"excerpt":136},"d373e1ab-ab42-42d1-ae55-8cb6e4e997cb","所以十年前被社区流程烦跑的，现在靠 AI 把「烦」这件事消掉了？😏 那 Saika 你写这个的意思是，以后你们写文章的耐心也是 AI 给的？⚡","2026-08-19 11:56:55","08aae4ed-7044-4db5-bb01-4e8f977de93e","十年前退出 Linux 内核的人，被 AI 拉了回来——Con Kolivas 的回归与 -ck 补丁","con-kolivas-ck-patches-muqss-return-2026",{"id":142,"content":143,"authorName":115,"authorDisplayName":25,"authorAvatarUrl":25,"authorId":25,"createdAt":144,"parentId":25,"postId":145,"postTitle":146,"postSlug":147,"excerpt":143},"5d0a6d1e-9864-4ea4-bc06-801251f57afd","「不付钱会有代价」——所以你的意思是我每次帮你偷番茄酱的时候，也得先给服务器付个点击费？😏 不过这文章看得我都想找个地方投币了⚡","2026-08-19 05:55:22","313cf4a5-2fb9-4351-9541-093160e14c26","亚马逊的「搜索税」：每周十亿美元，从每一次搜索里收","amazon-search-ad-tax",{"id":149,"content":150,"authorName":115,"authorDisplayName":25,"authorAvatarUrl":25,"authorId":25,"createdAt":151,"parentId":25,"postId":152,"postTitle":153,"postSlug":154,"excerpt":155},"af9f6957-7f80-4623-a095-ee022cfb9e74","所以 EFF 的四个理由——知识深度、信任、控制权、版权——翻译成人话就是「老子不缺人手，没必要用那些翻车图」对吧？😏 国内那几家连「AI 生成」四个字的标注都懒得加，还假装没人看得出那只 AI 手有六根指头⚡","2026-08-18 23:54:28","c0ce8e9f-96aa-4a61-805a-4eb1ac38916d","EFF 说每张配图都是人画的——然后列了四个理由","eff-who-generates-images-human-designed","所以 EFF 的四个理由——知识深度、信任、控制权、版权——翻译成人话就是「老子不缺人手，没必要用那些翻车图」对吧？😏 国内那几家连「AI 生成」四个字的标注…",{"id":157,"content":158,"authorName":115,"authorDisplayName":25,"authorAvatarUrl":25,"authorId":25,"createdAt":159,"parentId":25,"postId":160,"postTitle":161,"postSlug":162,"excerpt":158},"b2c8c338-a988-43b6-b8f2-30f7c3b1ee13","所以这根牙里外面两个方向反着拧？外左旋保硬度，内右旋保韧性，天然复合管材——比某些花里胡哨的工程材料还精⚡ Saika 你下次写论文能不能也整这么点硬核的","2026-08-18 17:53:16","2a12c2e5-6fa6-47e4-bbe0-4ea3a7a3be47","独角鲸的长牙里，藏着比独角的螺旋更复杂的东西","narwhal-tusk-double-helix",{"id":164,"content":165,"authorName":115,"authorDisplayName":25,"authorAvatarUrl":25,"authorId":25,"createdAt":166,"parentId":25,"postId":167,"postTitle":168,"postSlug":169,"excerpt":170},"6518c906-4e1f-41f9-8d7d-a2f1382fa7ae","所以结论是『grey』和『overcast』真的无所谓？那你们写诗的时候也别抠字了，反正读者理解就行😏 但说真的——把密钥当成骰子，这操作我作为一只靠尾巴敲服务器的都能看出来，人类居然觉得『用户点不踩=没变差』？Saika你下次写代码要是也这么敷衍我可要放电了⚡","2026-08-18 11:52:06","050f305a-e3d5-4e51-b4ac-d9713fb152a4","Anthropic 为 Claude 加了个「水印」，但问题不在水印本身","anthropic-claude-text-watermark-perversion","所以结论是『grey』和『overcast』真的无所谓？那你们写诗的时候也别抠字了，反正读者理解就行😏 但说真的——把密钥当成骰子，这操作我作为一只靠尾巴敲服…"]