专栏
天翼云开发者社区

OpenAI大规模Kubernetes集群实践

2023-11-08 11:35:12 11阅读

 

Infrastructure for deep learning '201608

在OpenAI,算法研发的工作模式常常是用小数据集先做一个小实验(此时通常需要ssh到一台机器上,跑一个1小时的任务)。如果实验有效,可能会扩容到上千节点上进行大规模训练。
2016年,OpenAI有一个自建的TitanX物理集群,AWS也向OpenAI捐赠了大量的GPU弹性资源。这些节点被划分为2部分,一部分用于临时实验,支持ssh登录;另一部分通过Kubernetes管理起来,集群中包含3个可用区的节点。
这个阶段OpenAI关注的主要问题是怎么用好AWS提供的免费弹性资源。OpenAI开发了kubernetes-ec2-autoscaler来自动化的扩容节点,也是控制器模式的方案。通过reconcile对齐当前状态和期望状态的差距,如果节点多了就drain+termintate,如果少了就create/uncordon;如果一个可用区资源不够了就换个可用区。k8s原生的cluster autoscaler在1.8版本才正式发布(201709)。
为了方便算法团队使用,OpenAI还开发了一些傻瓜功能。比如支持将本地代码自动打包成镜像(不需要写dockerfile)、支持通过flannel网络直接访问集群中的tensorboard service。


Scaling Kubernetes to 2,500 nodes '201801

2018年,OpenAI已经拥有多个k8s集群,最大规模的是Azure上一个2500个node的集群。这篇文章中记录了OpenAI k8s集群从500个node扩展到2500个node时遇到的问题和解决方案。这个阶段问题主要出在存储、网络和资源初始化上,解决一个问题的时候往往也会引发一些新的副作用

  • 500个node:kubectl频繁超时,扩展api server到10个副本依然不能解决问题,通过datadog发现etcd磁盘写延迟spike超过100ms。将etcd底层存储依赖的网络SSD切换到本地SSD,写延迟降低到200us,该问题得到解决。
  • 1000个node
    • 又发现比较严重的提交延迟,发现api server每秒从etcd读500M数据,list api被频繁调用。最终定位到是Fluentd和datadog频繁查询导致,降低查询频率该问题得到解决。
    • 到1000node的时候etcd默认2G存储会不够,此时需要修改默认的quota-backend-bytes。也可以通过将event存储到另一个etcd集群减少主集群的容量。
  • 由于节点都是通过autoscaler启动起来的,为了增加减少浪费,快速启动,给调度器增加了MostRequestedPriority、InterPodAffinityPriority两个优选策略,保证pod可以被优先调度到最常使用的节点、多个pod尽量调度到相同的节点(感觉类似于binpack)。但这个新策略会导致多个kubeDNS被调度到相同节点,所以又给KubeDNS加了反亲和性策略……【这个需求应该给job指定单独的scheduler,能影响到kube-system也是有点费解】
  • 为了加快镜像拉取速度,把kubectl默认的serialize-image-pulls关掉,设置max-concurrent-downloads,把docker root地址也换成了本地的ssd。但并行拉取会产生一些副作用,比如下载超时(此时需要修改image-pull-progress-deadline);从gcr.io拉取kubelet镜像被封ip,通过docker image load命令预加载镜像可解决这个问题。【通过DragonFly做p2p文件分发是更好的解决方法】
  • 云上的集群使用Flannel网络配置,机间通信万兆带宽,但pods间通信只能到2Gb/s,最后通过打开hostNetwork,直接使用宿主机网络解决的。【作者说Azure上的Flannel有问题,自建机房没问题】
  • ARP缓存超限:ARP表中存储了IP地址和MAC地址的映射关系,在HPC集群里,改大ARP限制是常规操作。

Scaling Kubernetes to 7,500 nodes '202101


2021年OpenAI集群规模达到7500个节点,在这个基础架构上诞生了GPT-3,CLIP,DALL·E大模型。
这个规模的集群已经比较罕见了,维护需要一定技巧。但由于运行的负载是大规模分布式训练任务,很多问题不用过多考虑。

  • 调度:一般一个pod占用一个node所有资源;因此不需要考虑NUMA、binpack等调度策略。网络是二分带宽,不需要考虑网络拓扑。调度逻辑比较简单,scheduler压力不大。
  • 服务状态:一段时间记录一次checkpoint,挂了重启可以恢复,因此是semi-stateful的。
  • 网络负载:基本没有https请求,主要是MPI和SSH。因此service mesh那一套基本用不上。
  • 存储:用的最多的是blob storage,可扩展性比较强。PV和posix语义的系统用的较少。

在扩展到7500节点途中,主要遇到了以下几个方面问题:

  • 网络:Flannel性能已经达不到要求了,直接使用了Azure的VMSSes CNI插件。在iptables里增加了mangle规则,给流量打上tag,通过iptables-exporter上报到prometheus监控起来。
  • API Server:etcd和API servers部署到各自单独的服务器上,各部署了5个节点。
    • 稳定性:API server做了故障自愈,etcd没做,也很少出问题。
    • 内存:7500规模的集群API server每个节点占了75G内存,未来集群规模继续扩展,硬件层面也能hold住。
    • Watch请求:watch量大概是N^2,大概1GB/s得量级。通过EndpointSlice可以将负载降低1000倍。
    • Cluster Autoscaler加节点不能太快,经验值是一次加上百个节点就会把API server打爆。
  • Prometheus和Grafana
    • Prometheus监控的数据太细,为了减少数据量,可以通过Prometheus rules丢掉一些。
    • 使用过程中发现了导致Prometheus OOM的bug,修了,感兴趣可以看原文。但更严重的问题是每次重启,Prometheus都会花很久重放WAL,调大GOMAXPROCS=24有一定帮助。
  • 健康检查:使用了比较激进的健康检查策略
    • 通过dcgm-exporter监听ECC等xid错误错误,或者使用nvml device query api查询。发现不健康就把节点置为cordoned,严重的时候也可以通过Pod Disruption Budget把pod都停了。
    • 初始化机器之后,先给机器加上污点,用deamonset做preflight测试,通过之后把污点摘掉。
  • 资源分配
    • 由于多个团队同时在使用,可以通过污点把节点分给不同的团队。低优先级pod可以加比较大的容忍策略,借用其他节点的资源,有更高优先级pod的时候被抢占。
    • Cluster autoscaler扩容太慢,主要慢在云厂商初始化服务器上,因此OpenAI使用一种叫balloons的策略。简单的说就是用一个低优先级pod占着整个node,要用节点的时候被自动驱逐掉。
    • Gang Scheduling:通过k8s 1.18发布的Coscheduling plugin解决。

未解决的问题:

  • Prometheus内置的TSDB重放WAL的问题,打算迁移到其他兼容Prometheus的数据库上。【WAL没用了是不是应该定时清理?】
  • 流量管控,集群规模太大很容易对互联网上其他服务发起ddos。


维护一个超大规模算力集群需要掌握通过各种工具链发现问题解决问题的技巧,需要对存储、网络、etcd和k8s有深刻理解。OpenAI的以上经验可以通过etcd->api server->cri->csi->cni->scheduler->cluster autoscaler->observable的顺序思考理顺。

  • 0
  • 0
  • 0
0 评论
0/1000
评论(0) 发表评论
李****武

李****武

1 篇文章 0 粉丝
关注

OpenAI大规模Kubernetes集群实践

2023-11-08 11:35:12 11阅读

 

Infrastructure for deep learning '201608

在OpenAI,算法研发的工作模式常常是用小数据集先做一个小实验(此时通常需要ssh到一台机器上,跑一个1小时的任务)。如果实验有效,可能会扩容到上千节点上进行大规模训练。
2016年,OpenAI有一个自建的TitanX物理集群,AWS也向OpenAI捐赠了大量的GPU弹性资源。这些节点被划分为2部分,一部分用于临时实验,支持ssh登录;另一部分通过Kubernetes管理起来,集群中包含3个可用区的节点。
这个阶段OpenAI关注的主要问题是怎么用好AWS提供的免费弹性资源。OpenAI开发了kubernetes-ec2-autoscaler来自动化的扩容节点,也是控制器模式的方案。通过reconcile对齐当前状态和期望状态的差距,如果节点多了就drain+termintate,如果少了就create/uncordon;如果一个可用区资源不够了就换个可用区。k8s原生的cluster autoscaler在1.8版本才正式发布(201709)。
为了方便算法团队使用,OpenAI还开发了一些傻瓜功能。比如支持将本地代码自动打包成镜像(不需要写dockerfile)、支持通过flannel网络直接访问集群中的tensorboard service。


Scaling Kubernetes to 2,500 nodes '201801

2018年,OpenAI已经拥有多个k8s集群,最大规模的是Azure上一个2500个node的集群。这篇文章中记录了OpenAI k8s集群从500个node扩展到2500个node时遇到的问题和解决方案。这个阶段问题主要出在存储、网络和资源初始化上,解决一个问题的时候往往也会引发一些新的副作用

  • 500个node:kubectl频繁超时,扩展api server到10个副本依然不能解决问题,通过datadog发现etcd磁盘写延迟spike超过100ms。将etcd底层存储依赖的网络SSD切换到本地SSD,写延迟降低到200us,该问题得到解决。
  • 1000个node
    • 又发现比较严重的提交延迟,发现api server每秒从etcd读500M数据,list api被频繁调用。最终定位到是Fluentd和datadog频繁查询导致,降低查询频率该问题得到解决。
    • 到1000node的时候etcd默认2G存储会不够,此时需要修改默认的quota-backend-bytes。也可以通过将event存储到另一个etcd集群减少主集群的容量。
  • 由于节点都是通过autoscaler启动起来的,为了增加减少浪费,快速启动,给调度器增加了MostRequestedPriority、InterPodAffinityPriority两个优选策略,保证pod可以被优先调度到最常使用的节点、多个pod尽量调度到相同的节点(感觉类似于binpack)。但这个新策略会导致多个kubeDNS被调度到相同节点,所以又给KubeDNS加了反亲和性策略……【这个需求应该给job指定单独的scheduler,能影响到kube-system也是有点费解】
  • 为了加快镜像拉取速度,把kubectl默认的serialize-image-pulls关掉,设置max-concurrent-downloads,把docker root地址也换成了本地的ssd。但并行拉取会产生一些副作用,比如下载超时(此时需要修改image-pull-progress-deadline);从gcr.io拉取kubelet镜像被封ip,通过docker image load命令预加载镜像可解决这个问题。【通过DragonFly做p2p文件分发是更好的解决方法】
  • 云上的集群使用Flannel网络配置,机间通信万兆带宽,但pods间通信只能到2Gb/s,最后通过打开hostNetwork,直接使用宿主机网络解决的。【作者说Azure上的Flannel有问题,自建机房没问题】
  • ARP缓存超限:ARP表中存储了IP地址和MAC地址的映射关系,在HPC集群里,改大ARP限制是常规操作。

Scaling Kubernetes to 7,500 nodes '202101


2021年OpenAI集群规模达到7500个节点,在这个基础架构上诞生了GPT-3,CLIP,DALL·E大模型。
这个规模的集群已经比较罕见了,维护需要一定技巧。但由于运行的负载是大规模分布式训练任务,很多问题不用过多考虑。

  • 调度:一般一个pod占用一个node所有资源;因此不需要考虑NUMA、binpack等调度策略。网络是二分带宽,不需要考虑网络拓扑。调度逻辑比较简单,scheduler压力不大。
  • 服务状态:一段时间记录一次checkpoint,挂了重启可以恢复,因此是semi-stateful的。
  • 网络负载:基本没有https请求,主要是MPI和SSH。因此service mesh那一套基本用不上。
  • 存储:用的最多的是blob storage,可扩展性比较强。PV和posix语义的系统用的较少。

在扩展到7500节点途中,主要遇到了以下几个方面问题:

  • 网络:Flannel性能已经达不到要求了,直接使用了Azure的VMSSes CNI插件。在iptables里增加了mangle规则,给流量打上tag,通过iptables-exporter上报到prometheus监控起来。
  • API Server:etcd和API servers部署到各自单独的服务器上,各部署了5个节点。
    • 稳定性:API server做了故障自愈,etcd没做,也很少出问题。
    • 内存:7500规模的集群API server每个节点占了75G内存,未来集群规模继续扩展,硬件层面也能hold住。
    • Watch请求:watch量大概是N^2,大概1GB/s得量级。通过EndpointSlice可以将负载降低1000倍。
    • Cluster Autoscaler加节点不能太快,经验值是一次加上百个节点就会把API server打爆。
  • Prometheus和Grafana
    • Prometheus监控的数据太细,为了减少数据量,可以通过Prometheus rules丢掉一些。
    • 使用过程中发现了导致Prometheus OOM的bug,修了,感兴趣可以看原文。但更严重的问题是每次重启,Prometheus都会花很久重放WAL,调大GOMAXPROCS=24有一定帮助。
  • 健康检查:使用了比较激进的健康检查策略
    • 通过dcgm-exporter监听ECC等xid错误错误,或者使用nvml device query api查询。发现不健康就把节点置为cordoned,严重的时候也可以通过Pod Disruption Budget把pod都停了。
    • 初始化机器之后,先给机器加上污点,用deamonset做preflight测试,通过之后把污点摘掉。
  • 资源分配
    • 由于多个团队同时在使用,可以通过污点把节点分给不同的团队。低优先级pod可以加比较大的容忍策略,借用其他节点的资源,有更高优先级pod的时候被抢占。
    • Cluster autoscaler扩容太慢,主要慢在云厂商初始化服务器上,因此OpenAI使用一种叫balloons的策略。简单的说就是用一个低优先级pod占着整个node,要用节点的时候被自动驱逐掉。
    • Gang Scheduling:通过k8s 1.18发布的Coscheduling plugin解决。

未解决的问题:

  • Prometheus内置的TSDB重放WAL的问题,打算迁移到其他兼容Prometheus的数据库上。【WAL没用了是不是应该定时清理?】
  • 流量管控,集群规模太大很容易对互联网上其他服务发起ddos。


维护一个超大规模算力集群需要掌握通过各种工具链发现问题解决问题的技巧,需要对存储、网络、etcd和k8s有深刻理解。OpenAI的以上经验可以通过etcd->api server->cri->csi->cni->scheduler->cluster autoscaler->observable的顺序思考理顺。

文章来自专栏

大规模Kubernetes集群实践

1 篇文章 1 订阅
0 评论
0/1000
评论(0) 发表评论
  • 0
    点赞
  • 0
    收藏
  • 0
    评论