摘要:遥感影像,作为地球自拍照,可能从更广大的视角,为人们提供更多维度的辅助信息,来帮忙人类感知自然资源、农林水利、交通灾祸等多畛域信息。
本文分享自华为云社区《AI+ 云原生,把卫星遥感虐的死去活来》,作者:tsjsdbd。
AI 牛啊,云原生牛啊,所以 1 +1>2?
遥感影像,作为地球自拍照,可能从更广大的视角,为人们提供更多维度的辅助信息,来帮忙人类感知自然资源、农林水利、交通灾祸等多畛域信息。
AI 技术,能够在很多畛域超过人类,要害是它是主动的,省时又省力。可显著晋升遥感影像解译的工作效率,对各类地物元素进行自动化的检测,例如建筑物,河道,路线,农作物等。能为智慧城市倒退 & 治理提供决策依据。
云原生技术,近年来堪称是一片炽热。易构建,可反复,无依赖等劣势,无论从哪个角度看都与 AI 算法天生一对。所以大家也能够看到,各畛域的 AI 场景,大都是将 AI 推理算法运行在 Docker 容器外面的。
AI+ 云原生这么 6,那么强强联手后,地物分类、指标提取、变化检测等高性能 AI 解译不就手到擒来?咱们也是这么认为的,所以基于 AI+Kubernetes 云原生,构建了反对遥感影像 AI 解决的空天地平台。
不过现实是好的,过程却跟西天取经个别,九九八十一难,最终修成正果。
业务场景介绍
遇到问题的业务场景叫影像交融(Pansharpen),也就是对地球自拍照进行“多镜头单干美颜”性能。(能够了解成:手机的多个摄像头,同时拍照,合并成一张高清黑白大图)。
所以业务简略总结就是:读取 2 张图片,生成 1 张新的图片。该性能咱们放在一个容器外面执行,每张交融后的后果图片大概 5GB。
问题的要害是,一个批次业务量须要解决的是 3000 多张卫星影像,所以每批工作只须要同时运行实现 3000 多个容器就 OK 啦。云原生 YYDS!
业务架构图示
为了帮忙了解,这里合成应用云原生架构实现该业务场景的逻辑图如下:
在云上,原始数据,以及后果数据,肯定是要寄存在对象存储桶外面的。因为这个数据量,只有对象存储的价格是适合的。(对象存储,1 毛钱 /GB。文件存储则须要 3 毛钱 /GB)
因为容器之间是相互独立无影响的,每个容器只须要解决本人的那幅影像就行。例如 1 号容器解决 1.tif 影像;2 号容器解决 2.tif 影像;一次类推。
所以管理程序,只须要投递对应数量的容器(3000+),并监控每个容器是否胜利执行结束就行(此处为简化阐明,理论业务场景是一个 pipeline 解决流程)。那么,需要曾经依照云原生现实的状态合成,咱们开始起 (tang) 飞(keng)吧~
注:以下形容的问题,是通过梳理后出现的,理论问题呈现时是相互交叉盘根错节的。
K8s 死掉了
当作业投递后,不多久零碎就显示作业纷纷失败。查看日志报调用 K8s 接口失败,再一看,K8s 的 Master 都曾经挂了。。。
K8s-Master 处理过程,总结版:
- 发现 Master 挂是因为 CPU 爆了
- 所以扩容 Master 节点(此次反复 N 次);
- 性能优化:扩容集群节点数量;
- 性能优化:容器分批投放;
- 性能优化:查问容器执行进度,少用 ListPod 接口;
具体版:
看监控 Master 节点的 CPU 曾经爆掉了,所以最简略粗犷的想法就是给 Master 扩容呀,嘎嘎的扩。于是从 4U8G 3 一路扩容一路测试一路失败,扩到了 32U64G 3。能够发现 CPU 还是爆满。看来简略的扩容是行不通了。
3000 多个容器,投给 K8s 后,大量的容器都处于 Pending 状态(集群整体资源不够,所以容器都在排队呢)。而正在 Pending 的 Pod,K8s 的 Scheduler 会不停的轮训,去判断是否有资源能够给它安顿上。所以这也会给 Scheduler 微小的 CPU 压力。扩容集群节点数量,能够缩小排队的 Pod 数量。
另外,既然排队的太多,不如就把容器分批投递给 K8s 吧。于是开始分批次投递工作,想着别一次把 K8s 压垮了。每次投递数量,缩小到 1 千,而后到 500,再到 100。
同时,查问 Pod 进度的时候,防止应用 ListPod 接口,改为间接查问具体的 Pod 信息。因为 List 接口,在 K8s 外部的解决会列出所有 Pod 信息,解决压力也很大。
这一套组合拳下来,Master 节点终于不挂了。不过,一头问题按上来了,另一头问题就冒出来了。
容器跑一半,挂了
尽管 Master 不挂了,然而当投递 1~2 批次作业后,容器又纷纷失败。
容器挂掉的处理过程,总结版:
- 发现容器挂掉是被 eviction 驱赶了;
- Eviction 驱赶,发现起因是节点报 Disk Pressure(存储容量满了);
- 于是扩容节点存储容量;
- 缩短驱赶容器(被动 kill 容器)前的容忍工夫;
具体版:
(注:以下问题是定位梳理后,按程序出现给大家。但其实出问题的时候,程序没有这么敌对)
容器执行失败,首先想到的是先看看容器外面脚本执行的日志呗:后果报日志找不到~
于是查问 Pod 信息,从 event 事件中发现有些容器是被 Eviction 驱赶干掉了。同时也能够看到,驱赶的起因是 DiskPressure(即节点的存储满了)。
当 Disk Pressure 产生后,节点被打上了驱赶标签,随后启动被动驱赶容器的逻辑:
因为节点进入 Eviction 驱赶状态,节点下面的容器,如果在 5 分钟后,还没有运行完,就被 Kubelet 被动杀死了。(因为 K8s 想通过干掉容器来腾出更多资源,从而尽快退出 Eviction 状态)。
这里咱们假如每个容器的失常运行工夫为 1~2 个小时,那么不应该一产生驱动就马上杀死容器(因为曾经执行到一半的容器,杀掉从新执行是有老本节约的)。咱们冀望应该尽量期待所有容器都运行完结才入手。所以这个 pod-eviction-timeout 容忍工夫,应该设置为 24 小时(大于每个容器的均匀执行工夫)。
Disk Pressure 的间接起因就是本地盘容量不够了。所以得进行节点存储扩容,有 2 个抉择:1)应用云存储 EVS(给节点挂载云存储)。2)扩容本地盘(节点自带本地存储的 VM)。
因为云存储(EVS)的带宽切实太低了,350MB/s。一个节点咱们能同时跑 30 多个容器,带宽齐全满足不了。最终抉择应用 i3 类型的 VM。这种 VM 自带本地存储。并且将 8 块 NVMe 盘,组成 Raid0,带宽还能 x8。
对象存储写入失败
容器执行持续纷纷失败。
容器往对象存储写入失败处理过程,总结版:
- 不间接写入,而是先写到本地,而后 cp 过来。
- 将一般对象桶,改为反对文件语义的并行文件桶。
具体版:
查看日志发现,脚本在生成新的影像时,往存储中写入时出错:
咱们整集群是 500 核的规模,同时运行的容器数量大略在 250 个(每个 2u2g)。这么多的容器同时往 1 个对象存储桶外面并发追加写入。这个应该是导致该 IO 问题的起因。
对象存储协定 s3fs,自身并不适宜大文件的追加写入。因为它对文件的操作都是整体的,即便你往一个文件追加写入 1 字节,也会导致整个文件从新写一遍。
最终这里改为:先往本地生成指标影像文件,而后脚本的最初,再拷贝到对象存储上。相当于减少一个长期存储直达一下。
在长期直达存储抉择中,2 种本地存储都试过:1)块存储带宽太低,350MB/ s 影响整体作业速度。2)能够抉择带本地存储的 VM,多块本地存储组成 Raid 阵列,带宽速度都杠杠滴。
同时,华为云在对象存储协定上也有一个扩大,使其反对追加写入这种的 POSIX 语义,称为并行文件桶。后续将一般的对象桶,都改为了文件语义桶。以此来撑持大规模的并发追加写入文件的操作。
K8s 计算节点挂了
So,持续跑工作。然而这容器作业,执行又纷纷失败鸟~
计算节点挂掉,定位梳理后,总结版:
- 计算节点挂掉,是因为好久没上报 K8s 心跳了。
- 没上报心跳,是因为 kubelet(K8s 节点的 agent)过得不太好(死掉了)。
- 是因为 Kubelet 的资源被容器抢光了(因为不想容器常常 oom kill,并未设置 limit 限度)
- 为了爱护 kubelet,所有容器全都设置好 limit。
具体版,间接从各类奇葩乱象等问题动手:
容器启动失败,报超时谬误。
而后,什么 PVC 共享存储挂载失败:
或者,又有些容器无奈失常完结(删不掉)。
查问节点 Kubelet 日志,能够看到充斥了各种超时谬误:
啊,这么多的底层容器超时,一开始感觉的 Docker 的 Daemon 过程挂了,通过重启 Docker 服务来试图修复问题。
前面持续定位发现,K8s 集群显示,好多计算节点 Unavailable 了(节点都死掉啦)。
持续剖析节点不可用(Unavailable),能够发现是 Kubelet 良久没有给 Master 上报心跳了,所以 Master 认为节点挂了。阐明不仅仅是 Docker 的 Daemon 受影响,节点的 Kubelet 也有受影响。
那什么状况会导致 Kubelet,Docker 这些主机过程都不失常呢?这个就要提到 Kubernetes 在调度容器时,所设计的 Request 和 Limit 这 2 个概念了。
Request 是 K8s 用来调度容器到闲暇计算节点上的。而 Limit 则会传递给 Docker 用于限度容器资源下限(触发下限容易被 oom killer 杀掉)。后期咱们为了避免作业被杀死,仅为容器设置了 Request,没有设置 Limit。也就是每个容器理论能够超出申请的资源量,去抢占额定的主机资源。大量容器并发时,主机资源会受影响。
思考到尽管不杀死作业,对用户挺敌对,然而平台本人受不了也不是个事。于是给所有的容器都加上了 Limit 限度,避免容器超限应用资源,强制用户过程运行在容器 Limit 资源之内,超过就 Kill 它。以此来确保主机过程(如 Docker,Kubelet 等),肯定是有足够的运行资源的。
K8s 计算节点,又挂了
于是,持续跑工作。不少作业执行又双叒失败鸟~
节点又挂了,总结版:
- 剖析日志,这次挂是因为 PLEG(Pod Lifecycle Event Generator)失败。
- PLEG 异样是因为节点下面存留的历史容器太多(>500 个),查问用时太久超时了。
- 及时清理曾经运行完结的容器(即便跑完的容器,还是会占用节点存储资源)。
- 容器接口各种超时(cpu+memory 是有 limit 爱护,然而 io 还是会被抢占)。
- 晋升零碎磁盘的 io 性能,避免 Docker 容器接口(如 list 等)超时。
具体版:
景象还是节点 Unavailable 了,查看 Kubelet 日志搜寻心跳状况,发现有 PLEG is not healthy 的谬误:
于是搜寻 PLEG 相干的 Kubelet 日志,发现该谬误还挺多:
这个谬误,是因为 kubelet 去 list 以后节点所有容器(包含曾经运行完结的容器)时,超时了。看了代码:https://github.com/kubernetes…
kubelet 判断超时的工夫,3 分钟的长度是写死的。所以当 pod 数量越多,这个超时概率越大。很多场景案例表明,节点上的累计容器数量达到 500 以上,容易呈现 PLEG 问题。(此处也阐明 K8s 能够更加 Flexible 一点,超时时长应该动静调整)。
缓解措施就是及时的清理曾经运行结束的容器。然而运行完结的容器一旦清理,容器记录以及容器日志也会被清理,所以须要有相应的性能来补救这些问题(比方日志采集零碎等)。
List 所有容器接口,除了容器数量多,IO 慢的话,也会导致超时。
这时,从后盾能够看到,在投递作业期间,大量并发容器同时运行时,云硬盘的写入带宽被大量占用:
对存储池的冲击也很大:
这也导致了 IO 性能变很差,也会肯定水平影响 list 容器接口超时,从而导致 PLEG 谬误。
该问题的解决措施:尽量应用的带本地高速盘的 VM,并且将多块数据盘组成 Raid 阵列,进步读写带宽。
这样,该 VM 作为 K8s 的节点,节点上的容器都间接读写本地盘,io 性能较好。(跟大数据集群的节点用法一样了,强依赖本地 shuffle~)。
在这多条措施施行后,后续多批次的作业都能够安稳的运行完。
总结:“AI+ 云原生”这条路
云原生是趋势,曾经成为大家的共识,各畛域也都开始以云原生为底座的业务尝试。AI 是将来,这也是以后不可阻挡的力量。然而当 AI 踏上这条云原生的路线却不那么一帆风顺。至多能够看到,华为云的云原生底座(当然,也包含存储、网络等周边基础设施)还能够有更多的提高空间。
然而,大家也不必放心太多,因为以后华为云的空天地平台,在经验了多年的 AI+ 云原生的积攒,目前能够很稳固的解决 PB 级每日的遥感影像数据,撑持各类空基、天基、地基等场景,并且在该畛域放弃相对当先的战斗值。尽管大家看到此间过程有点波折,然而所有的艰难都是涅槃的火种,克服过的艰难都是今后能够对客户做的承诺。在这里能够很明确的通知各位:AI+ 云原生 = 真香。
写这篇文章的目标,不是在论述艰难,而是为了总结分享。与同畛域的人分享并促成遥感畛域的疾速倒退,独特推动 AI+ 云原生的落地。
点击关注,第一工夫理解华为云陈腐技术~