2024 年 12 月 11 日,太平洋标准时间下午 3:16 至 7:38,所有 OpenAI 服务都经历了严重的停机 。这一事件是由于 OpenAI 内部推出新的遥测服务 所导致的,并非由安全事件或最近的发布引起。所有产品从下午 3:16 开始出现显著的性能下降或完全不可用。
-
ChatGPT:显著恢复发生在下午5:45,完全恢复在下午 7:01。
-
API:显著恢复发生在下午 5:36,所有模型的完全恢复在下午 7:38。
-
Sora:在下午 7:01 完全恢复。
01
宕机事件及 根因分析
根据 OpenAI 的官方事故报告[1],该事故的时间线如下:
2024 年 12 月 10 日:新的遥测服务部署到预生产集群,并验证其按预期工作。
2024 年 12 月 11 日,
-
下午 2:23:引入新服务的更改被合并,部署管道被触发。
-
下午 2:51 至 3:20:更改被应用到所有集群。
-
下午 3:13:触发警报,通知工程师。
-
下午 3:16:开始出现轻微的客户影响。
-
下午 3:16:识别根本原因。
-
下午 3:27:工程师开始将流量从受影响的集群转移。
-
下午 3:40:客户影响达到最大。
-
下午 4:36:第一个集群恢复。
-
下午 7:38:所有集群恢复。
根本原因
报告指出,这个问题的根源在于一个新的遥测(Telemetry)服务的部署。该服务意外生成了大量 Kubernetes API 的请求负载,压垮了 OpenAI 的 Kubernetes 控制平面,并导致基于 DNS 的服务发现机制出现问题 ,从而引发了关键系统的连锁故障。
OpenAI 在全球运营着数百个 Kubernetes 集群。Kubernetes 本身包含一个负责集群管理的控制平面和一个实际提供工作负载(如模型推理)的数据平面。
为了努力提高企业可靠性,OpenAI一直在致力于改进集群范围的可观测性工具,以加强对系统状态的可见性。在下午 3:12,OpenAI 部署了一个新的遥测服务,以收集更为详细的 Kubernetes 控制平面指标。
遥测服务的影响范围非常广,这个新服务的配置导致所有集群中的每个节点都在执行资源密集型的 Kubernetes API 运算操作,其消耗的资源随集群规模大幅增长,这远远超出了预期。当数千个节点同时执行这些运算操作时,Kubernetes API 服务器不堪重负,导致大多数大集群的 Kubernetes 控制平面崩溃。集群规模越大,这个问题越明显,以前的测试过程没有发现这个问题------DNS 缓存使得这个问题在本次发布上线影响到全球范围之前几乎不可见。
Kubernetes 数据平面可以很大程度上独立于控制平面运行,但 DNS 服务依赖于控制平面,一旦 Kubernetes 控制平面挂了,那这些服务就无法互相通信。
在正常情况下,DNS 缓存可以有效缓解此类故障 ,甚至完全避免影响。DNS 通常将 Kubernetes 服务解析为 ClusterIP,而 Cluster IP 通常在 Service 创建后保持稳定,除非 Service 被显式修改,因此缓存的 Cluster IP 在 Pod 更新的过程中通常是稳定的,仅在 Service 创建或删除时需要更新缓存。而 Headless Service 的域名解析 则直接解析到 Pod IP,在 Pod 创建或删除时因为Pod IP变化,缓存需要频繁更新。
然而,大规模的大模型部署通常需要多个 Pod 协同工作 (比如 LWS),这相当于一个 Super Pod ,组内通信依赖 DNS 进行互相的服务发 现 。因为NodeLocalDNS 和 CoreDNS 的缓存均可能失效,而当 CoreDNS 缓存的 TTL 过期后,当API Server负载过高无响应,CoreDNS则无法从 API Server 获取更新数据,则可能导致服务解析失败。此时,服务发现的中断将导致 Pod 间通信出现问题,并对整体业务产生影响。
测试与部署
报告中指出,本次遥测服务的变更在上线之前于预生产集群中进行了测试 ,未观察到任何问题。影响仅限于超过一定规模的集群,并且每个节点的 DNS 缓存延迟了故障被发现的时间,直到上线发布以后才观察到问题。
OpenAI 在部署前的主要可靠性关注点是新遥测服务的资源消耗 。在部署前,OpenAI 评估了所有集群的资源利用率指标(CPU/内存),以确保部署不会中断正在运行的服务。虽然资源请求是基于每个集群进行调整的,但没有采取措施来评估 Kubernetes API 服务器的负载。本次上线发布过程监控了服务健康状况,但缺乏足够的集群健康监控协议 。
Kubernetes 数据平面(负责处理用户请求)被设计为独立于控制平面运行。然而,DNS 解析依赖于 Kubernetes API 服务器,DNS 解析是 OpenAI 许多服务的核心依赖。
最初出现问题时,DNS 缓存通过提供老旧但可用的 DNS 记录暂时缓解了影响。然而,随着缓存记录在接下来的 20 分钟内过期,许多服务开始因依赖实时 DNS 解析而失败。这个时机至关重要,因为它延迟了问题的可见性,大家还未完全了解问题影响的范围就上线发布了。一旦 DNS 缓存为空,DNS 服务器的负载就会成倍增加,这会进一步增加控制平面的负载,使得即时缓解更加复杂。
02
如何防范?
在应对类似问题时,我们如何能够更好地解决它们?同时,针对 Kubernetes 集群,我们可以采取哪些有效的措施来预防此类问题的发生呢?「DaoCloud 道客」的开发团队结合 OpenAI 披露的信息、社区的最佳实践以及 OpenAI 处理事故的思路,提出以下思考和总结。
API Server 压力较大,如何妥善处理?
OpenAI 在事故报告中提到了几个临时减小 API Server 压力的方法,以下是紧急情况下可以参考的方法。
-
扩展 Kubernetes API Server 数量: 该方法可以快速提供足够的请求处理能力,使得 OpenAI 后续的应用修复方法能够被响应。该方法的前提是 ETCD 还能够正常响应,API Server 是此时的性能瓶颈。
-
缩小集群规模: 这样可以快速减少了 Kubernetes API 的总负载。这里不得不提到,大规模集群在集群调度效率等角度有很大优势,但是大集群故障爆炸半径较大的问题需要得到重视。适中规模的多集群是在调度效率和故障域之间的权衡和妥协。Kubernetes 官网[2] 推荐的集群规模为不超过 5000 节点,这是因为 ETCD 的性能瓶颈导致的。早在 2021 年, OpenAI 在博客[3] 中就声称他们的集群规模达到了 7500 节点,这是通过一些调优手段达到的,Kubernetes 集群性能已经进行了多轮的压榨。中等规模的集群由于具有一定的压力缓冲区,在面对负载时不容易崩溃。
-
阻止对 Kubernetes 管理 API 的网络请求: 让 API Server 有时间恢复。
除此之外,在生产环境,还有哪些措施可以有效缓解 API Server 压力呢?
1、限流策略: 对于类似 OpenAI 事故中的 Telemetry 组件对于 Kubernetes API 的频繁调用,用户应该配置 Kube API Server 的全局或者局部的 API Priority and Fairness[4],以确保不同优先级的请求可以得到公平的处理。
2、读缓存: 在频繁的对于 Kubernetes 资源的【读】操作上,我们还可以借助 Clusterpedia 等工具,减轻对 API Server 以及 ETCD 的直接压力。Clusterpedia 通过聚合多集群资源,在兼容 Kubernetes OpenAPI 的基础上额外提供了更加强大的检索功能,让用户更快更方便地在多集群中获取到想要的任何资源。在大规模集群和多集群场景,Clusterpedia 使用非常广泛。
3、识别给 API Server 带来较大压力的组件,针对性地进行压力的拆分和优化。
-
切换存储方式: 举个例子,reports server[5] 项目启动的目的,就是把 Kyverno 之前产生的大量报告的部分从 APIServer 的 CRD 拆分出去,存储到外部的数据库。类似的,OpenAI 遥测服务如果有存储大量 CRD 的需求,可以考虑用类似的方法进行拆分。
-
隔离方法: 如果遥测服务对 API Server 压力非常大且是必须的,也可以考虑单独部署一个API Server来提供服务,这样也是有效减少爆炸半径的方案。
-
另外,常见的性能瓶颈在 ETCD,API Server 可以通过 --etcd-servers-overrides 支持对 ETCD 进行切分。 通常来说 /events (事件) , /leases(节点心跳等) 都是比较适合放在单独的 ETCD 里面,减小其他资源访问的 ETCD 压力。
测试方面:增加故障注入测试,加强控制平面和新 Operator 的大规模集群压测
如何才能阻止和识别对 API Server 产生更多新的昂贵请求?完善的监控可以帮助我们更快的发现这些请求 。故障注入测试能模拟更多场景以确保控制平面的健壮性。此外我们还可以通过压测 来确定控制平面新组件(例如新的 Operator 等,遥测服务也是一种)是否能在满足大规模集群的应用场景。
在大规模集群的创建和测试方面,不得不提 KWOK**[6]** (Kubernetes WithOut Kubelet,没有 Kubelet 的 Kubernetes)项目, KWOK 是一个工具包,能让你在几秒钟内创建数千个节点构成的集群 ,这是「DaoCloud 道客」的自主开源项目。在今年香港进行的 KubeCon China 2024 上,KWOK 的创始人和维护者,来自「DaoCloud 道客」的工程师张世明和 NVIDIA 的工程师陈源介绍了 KWOK 最近在大集群的可靠性测试和故障注入测试上的成果,这些测试可以保障各类控制平面在大规模 Kubernetes 集群中的稳定性。
在此之前,OpenAI 工程师曾在博客[7] 中明确提到,OpenAI 内部也正在使用 KWOK 进行相关的压测。这次 OpenAI 的事故是在"大型集群"里发生的,说明遥测代码在开发测试时并没有经过实际或者虚拟的大规模的验证,这个是由于大规模测试成本非常高。KWOK 通过模拟节点和 Pod 的方式,可以大幅度降低这方面的成本,让各种控制平面逻辑能够运行超大规模集群压测成为可能。
DNS 和 DNS 缓存
DNS 的缓存有很多方案,其中官方给出的节点缓存方案[8] 可以参考。
图片来源:
https://kubernetes.io/docs/tasks/administer-cluster/nodelocaldns/#architecture-diagram
DNS 缓存可以帮助减小总 DNS 的压力,但是同时也带来一个问题,就是集群 DNS 出现故障后,问题暴露会出现滞后。因此在部署 DNS 缓存的同时,我们需要加强相关的监控和告警,包括总 DNS 的健康情况,响应时延和错误率 。
对于 Kubernetes 的控制面,也要加强相应的监控和告警:比如 API-Server 的告警也不单单是只监控 KubeAPIDown 的情况,还需要监控 API Server 的请求压力变化sum(rate(apiserver_request_count[5m])), apiserver_request_terminations_total)、响应时延(apiserver_request_slo_duration_seconds_bucket, apiserver_request_duration_seconds_count , apiserver_current_inqueue_requests)和错误率(apiserver_request:burnrate1h)等。完善的监控和告警规则,可以避免 Local DNS 缓存掩盖问题而延误治疗时机。更多针对 Kubernetes api-server的监控告警实践,可以参考:Prometheus 针对 Kubernetes 的监控 RunBook[9] 和 Kubernetes 的指标清单[10]。
发布流程改进(滚动发布)
OpenAI 提到他们正在持续改进分阶段滚动发布和回滚能力,并加强对所有基础设施更改的监控,以确保任何故障的影响被限制在较小范围,并在早期被检测到。所有未来的基础设施相关配置更改将遵循稳健的分阶段滚动发布过程,并改进持续监控,确保服务负载和集群(包括 Kubernetes 控制平面)的健康状况。
将基础设施变更分阶段、逐步推送到不同的集群(地域) ,以确保在出现问题时能够快速回滚到前一个稳定状态,最小化对整个集群的影响。此外,变更需要提供灵活的回退方案 ,以及在重大操作前进行集群备份 ,都可以让变更回退成为可能。
紧急控制平面访问
OpenAI 提到目前他们还没有一种机制来确保在数据平面对控制平面施加太大压力时访问 API Server。OpenAI 将实施 break-glass 机制 ,以确保工程师可以在任何情况下访问 Kubernetes API Server。
-
比较简单的方法是部署单独的 API Server 给 Infra 工程师或者 SRE 使用,这样问题解决的方案可以较快的应用到 API Server 中。
-
此外,还可以通过 **Etcd auger[11]**项目 来完成这一点。Auger 提供了直接访问 ETCD 的方法,可以直接修改数据。在紧急情况下,这也是一个更高效和直接的手段。
众所周知,Kubernetes 已经成为了 AI 行业的重要支柱,然而,Kubernetes 的稳定性仍需通过精细的运维和优化来保障。大模型服务过程中的宕机现象的发生,给更多企业敲响了警钟,希望以上防范措施能对大家的实践有所帮助。
参考链接
[1] OpenAI 事故报告:
https://status.openai.com/incidents/ctrsv3lwd797
[2] kubernetes 官网:
https://kubernetes.io/docs/setup/best-practices/cluster-large/
[3] OpenAI 博客
https://openai.com/index/scaling-kubernetes-to-7500-nodes/
[4] API Priority and Fairness:
https://kubernetes.io/docs/concepts/cluster-administration/flow-control/
[5] reports server:
https://github.com/kyverno/reports-server
[6] KWOK:
https://github.com/kubernetes-sigs/kwok
[7] OpenAI 工程师博客:
https://www.awelm.com/posts/kube-scheduler/
[8] 节点缓存方案:
https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/nodelocaldns/
[9] Prometheus 针对 Kubernetes 的监控 RunBook:
https://github.com/prometheus-operator/runbooks/tree/main/content/runbooks/kubernetes
[10] Kubernetes 的指标清单:
https://kubernetes.io/docs/reference/instrumentation/metrics/
[11] auger:
https://github.com/etcd-io/auger
END
(版权归原作者所有,侵删)
免责声明:本文内容来源于网络,所载内容仅供参考。转载仅为学习和交流之目的,如无意中侵犯您的合法权益,请及时联系Docker中文社区!