Serverless 场景下 Pod 创建效率优化

简介: 众所周知,Kubernetes 是云原生领域的基石,作为容器编排的基础设施,被广泛应用在 Serverless 领域。弹性能力是 Serverless 领域的核心竞争力,本次分享将重点介绍基于 Kubernetes 的 Serverless 服务中,如何优化 Pod 创建效率,提升弹性效率。

Serverless 计算简介

 
在进入主题之前,先简单回顾下 Serverless 计算的定义。

从维基百科可以了解到,Serverless 计算是云计算的一种形态,由云厂商管理服务器,向用户动态分配机器资源,基于实际使用的资源量计费。

用户构建和运行服务时,不用考虑服务器,降低了用户管理服务器的负担。在业务高峰期通过平台的弹性能力自动扩容实例,在业务低峰期自动缩容实例,降低资源成本。

Serverless 计算平台

 
下述是当前常见的 Serverless 计算产品的架构。
 
1.jpg

整个产品架构通常会有管控平面和数据平面两层,管控平面服务开发者,管理应用生命周期,满足开发者对应用管理的需求,数据平面服务应用的访问方,如开发者业务的用户,满足应用的流量管理和访问诉求。

管控平面通常采用 Kubernetes 做资源管理和调度,master 通常是 3 节点,满足对高可用的需求,节点通过内网 SLB 访问 K8s master。

在节点层面,通常会有两种类型的节点:

  • 一种是运行 kubelet 的节点,如裸金属服务器、虚拟机等,这类节点上会运行安全容器作为 Pod 运行时,每个 Pod 拥有独立的 kernel,降低共享宿主机 kernel 带来的安全风险。同时会通过云产品 VPC 网络或其他网络技术,在数据链路层隔离租户的网络访问。通过 安全容器+二层网络隔离,单个节点上可以提供可靠的多租运行环境。
  • 还有一种是虚拟节点,通过 VirtualKubelet 衔接 K8s 和弹性实例。弹性实例是云产品中类似虚拟机的一种轻量资源形态,提供无限资源池的容器组服务,该容器组的概念对应 K8s 中的 Pod 概念。AWS 提供有 Fargate 弹性实例,阿里云提供有 ECI 弹性实例。

Serverless 产品会提供基于 K8s 的 PaaS 层,负责向开发者提供部署、开发等相关的服务,屏蔽 K8s 相关的概念,降低开发者开发、运维应用的成本。

在数据平面,用户可通过 SLB 实现对应用实例的访问。PaaS 层也通常会在该平面提供诸如流量灰度、A/B 测试等流量管理服务,满足开发者对流量管理的需求。

弹性能力是 Serverless 计算平台的核心竞争力,需要满足开发者对 Pod 规模 的诉求,提供类似无限资源池的能力,同时还要满足创建 Pod 效率的诉求,及时响应请求。

Pod 规模可通过增加 IaaS 层资源来满足,接下来重点介绍提升 Pod 创建效率的技术。

Pod 创建相关场景

 
先了解下 Pod 创建相关的场景,这样可以更有效通过技术满足业务诉求。

业务中会有两种场景涉及到 Pod 创建:

  • 第一种是创建应用,这个过程会先经过调度,决策最适合 Pod 的节点,然后在节点上创建 Pod。
  • 第二种是升级应用,在这个过程中,通常是不断进行 创建新 Pod 和 销毁旧 Pod。

Serverless 服务中,开发者关心的重点在于应用的生命周期,尤其是创建和升级阶段,Pod 创建效率会影响这两个阶段的整体耗时,进而影响开发者的体验。面对突发流量时,创建效率的高低会对开发者服务的响应速度产生重要影响,严重者会使开发者的业务受损。

面对上述业务场景,接下来重点分析如何提升 Pod 创建效率。

创建 Pod 流程

 
整体分析下 Pod 创建的阶段,按照影响 Pod 创建效率的优先级来依次解决。

这是简化后的创建 Pod 流程:

2.jpg

当有 Pod 创建请求时,先进行调度,为 Pod 选取最合适的节点。在节点上,先进行拉取镜像的操作,镜像在本地准备好后,再进行创建容器组的操作。在拉取镜像阶段,又依次分为下载镜像和解压镜像两个步骤。

我们针对两种类型的镜像进行了测试,结果如下:

3.jpg

从测试结果可看到,解压镜像耗时在整个拉取镜像过程中的占比不容忽视,对于解压前 248MB 左右的 golang:1.10 镜像,解压镜像耗时竟然占到了拉取镜像耗时的 77.02%,对于节解压前 506MB 左右的 hadoop namenode 镜像,解压镜像耗时和下载镜像耗时各占 40% 和 60% 左右,即对于拉取镜像过程的总耗时也不容忽视。

接下来就分别针对上述过程的不同节点进行优化处理,分别从上述整个流程、解压镜像、下载镜像等方面进行探讨。
 

拉取镜像效率提升

 

镜像预热

 
可以快速想到的方法是进行镜像预热,在 Pod 调度到节点前预先在节点上准备好镜像,将拉取镜像从创建 Pod 的主链路中移除,如下图:

4.jpg

可以在调度前进行全局预热,在所有节点上行提前拉取镜像。也可以在调度过程中进行预热,在确定调度到的
节点后,在目标节点上拉取镜像。

两种方式无可厚非,可根据集群实际情况进行选择。

社区里 OpenKruise 项目即将推出镜像预热服务,可以关注下。下述是该服务的使用方式:

5.png

通过 ImagePullJob CRD 下发镜像预热任务,指定目标镜像和节点,可配置拉取的并发度、Job 处理的超时时间以及 Job Object 自动回收的时间。若是私有镜像,可指定拉取镜像时的 secret 配置。ImagePullJob 的 Events 会提镜任务的状态信息,可考虑适当增大 Job Object 自动回收的时间,便于通过 ImagePullJob Events 查看任务的处理状态。
 

提升解压效率

 
从刚才看到的拉取镜像的数据来看,解压镜像耗时会占拉取镜像总耗时很大的比例,测试的例子最大占比到了 77%,所以需要考虑如何提升解压效率。

先回顾下 docker pull 的技术细节:

6.jpg

在 docker pull 时,整体会进行两个阶段:

  • 并行下载 image 层
  • 拆解 image 层

在解压 image 层时,默认采用的 gunzip。

再简单了解下 docker push 的过程:

  • 先对 image 层进行打包操作,这个过程中会通过 gzip 进行压缩。
  • 然后并行上传。

gzip/gunzip 是单线程的压缩/解压工具,可考虑采用 pigz/unpigz 进行多线程的压缩/解压,充分利用多核优势。

containerd 从 1.2 版本开始支持 pigz,节点上安装 unpigz 工具后,会优先用其进行解压。通过这种方法,可通过节点多核能力提升镜像解压效率。

这个过程也需要关注 下载/上传 的并发度问题,docker daemon 提供了两个参数来控制并发度,控制并行处理的镜像层的数量,--max-concurrent-downloads 和 --max-concurrent-uploads。默认情况下,下载的并发度是 3,上传的并发度是 5,可根据测试结果调整到合适的值。

使用 unpigz 后的解压镜像效率:

7.jpg

在相同环境下,golang:1.10 镜像解压效率提升了 35.88%,hadoop namenode 镜像解压效率提升了 16.41%。

非压缩镜像

 
通常内网的带宽足够大,是否有可能省去 解压缩/压缩 的逻辑,将拉取镜像的耗时集中在下载镜像方面?即适量增大下载耗时,缩短解压耗时。

再回顾下 docker pull/push 的流程,在 unpack/pack 阶段,可以考虑将 gunzip 和 gzip 的逻辑去掉:
 
8.jpg

对于 docker 镜像,若 docker push 时的镜像是非压缩的,则 docker pull 时是无需进行解压缩操作,故要实现上述目标,就需要在 docker push 时去掉压缩逻辑。

docker daemon 暂时不支持上述操作,我们对 docker 进行了一番修改,在上传镜像时不进行压缩操作,测试结果如下:

9.jpg

这里重点关注解压镜像耗时,可看到 golang:1.10 镜像解压效率提升了 50% 左右,hadoop namenode 镜像解压效率替身挂了 28% 左右。在拉取镜像总耗时方面,该方案有一定的效果。
 

镜像分发

 
小规模集群中,提升拉取镜像效率的重点需要放在提升解压效率方面,下载镜像通常不是瓶颈。而在大规模集群中,由于节点数众多,中心式的 Image Registry 的带宽和稳定性也会影响拉取镜像的效率,如下图:

10.jpg

下载镜像的压力集中在中心式的 Image Registry 上。

这里介绍一种基于 P2P 的镜像分发系统来解决上述问题,以 CNCF 的 DragonFly 项目为例:
 
11.jpg

这里有几个核心组件:

ClusterManager

它本质上是一个中心式的 SuperNode,在 P2P 网络中作为 tracker 和 scheduler 协调节点的下载任务。同时它还是一个缓存服务,缓存从 Image Registry 中下载的镜像,降低节点的增加对 Image Registry 带来的压力。

Dfget

它既是节点上下载镜像的客户端,同时又充当向其他节点提供数据的能力,可以将本地已有的镜像数据按需提供给其他节点。

Dfdaemon

在每个节点上有个 Dfdaemon 组件,它本质上是一个 proxy,对 docker daemon 的拉取镜像的请求实现透明代理服务,使用 Dfget 下载镜像。

通过 P2P 网络,中心式的 Image Registry 数据被缓存到 ClusterManager 中,ClusterManager 协调节点对镜像的下载需求,将下载镜像的压力分摊到集群节点上,集群节点既是镜像数据的拉取方,又是镜像数据的提供方,充分利用内网带宽的能力进行镜像分发。

按需加载镜像

 
除了上述介绍到的方法,是否还有其他优化方法?

当前节点上创建容器时,是需要先把镜像全部数据拉取到本地,然后才能启动容器。再考虑下启动虚拟机的过程,即使是几百 GB 的虚拟机镜像,启动虚拟机也通常是在秒级别,几乎感受不到虚拟机镜像大小带来的影响。

那么容器领域是否也可以用到类似的技术?

再看一篇发表在 usenix 上的题为《Slacker: Fast Distribution with Lazy Docker Containers》 的 paper 描述:

Our analysis shows that pulling packages accounts for 76% of container start time, but only 6.4% of  
that data is read.

该 paper 分析,在镜像启动耗时中,拉取镜像占比 76%,但是在启动时,仅有 6.4% 的数据被使用到,即镜像启动时需要的镜像数据量很少,需要考虑在镜像启动阶段按需加载镜像,改变对镜像的使用方式。

对于「Image 所有 layers 下载完后才能启动镜像」,需要改为启动容器时按需加载镜像,类似启动虚拟机的方式,仅对启动阶段需要的数据进行网络传输。

但当前镜像格式通常是 tar.gz 或 tar,而 tar 文件没有索引,gzip 文件不能从任意位置读取数据,这样就不能满足按需拉取时拉取指定文件的需求,镜像格式需要改为可索引的文件格式。

Google 提出了一种新的镜像格式,stargz,全称是 seeable tar.gz。它兼容当前的镜像格式,但提供了文件索引,可从指定位置读取数据。

传统的 .tar.gz 文件是这样生成的: Gzip(TarF(file1) + TarF(file2) + TarF(file3) + TarFooter))。分别对每个文件进行打包,然后对文件组进行压缩操作。

stargz 文件做了这样的创新:Gzip(TarF(file1)) + Gzip(TarF(file2)) + Gzip(TarF(file3_chunk1)) + Gzip(F(file3_chunk2)) + Gzip(F(index of earlier files in magic file), TarFooter)。针对每个文件进行打包和压缩操作,同时形成一个索引文件,和 TarFooter 一起进行压缩。

这样就可以通过索引文件快速定位要拉取的文件的位置,然后从指定位置拉取文件。

然后在 containerd 拉取镜像环节,对 containerd 提供一种 remote snapshotter,在创建容器 rootfs 层时,不通过先下载镜像层再构建的方式,而是直接 mount 远程存储层,如下图所示:

12.jpg

要实现这样的能力,一方面需要修改 containerd 当前的逻辑,在 filter 阶段识别远程镜像层,对于这样的镜像层不进行 download 操作,一方面需要实现一个 remote snapshotter,来支持对于远程层的管理。

当 containerd 通过 remote snapshotter 创建容器时,省去了拉取镜像的阶段,对于启动过程中需要的文件,可对 stargz 格式的镜像数据发起 HTTP Range GET 请求,拉取目标数据。

阿里云实现了名为 DADI 的加速器,类似上述的思想,目前应用在了阿里云容器服务,实现了 3.01s 启动  
10000 个容器,完美杜绝了冷启动的漫长等待。感兴趣的读者也参考该文章:https://developer.aliyun.com/article/742103
 

原地升级

 
上述都是针对创建 Pod 过程提供的技术方案,对于升级场景,在现有的技术下,是否有效率提升的可能性?是否可以达到下述效果,即免去创建 Pod 的过程,实现 Pod 原地升级?

13.jpg

在升级场景中,占比较大的场景是仅升级镜像。针对这种场景,可使用 K8s 自身的 patch 能力。通过 patch image,Pod 不会重建,仅目标 container 重建,这样就不用完整经过 调度+新建 Pod 流程,仅对需要升级的容器进行原地升级。

在原地升级过程中,借助 K8s readinessGates 能力,可以控制 Pod 优雅下线,由 K8s Endpoint Controller 主动摘除即将升级的 Pod,在 Pod 原地升级后加入升级后的 Pod,实现升级过程中流量无损。

OpenKruise 项目中的 CloneSet Controller 提供了上述能力:

14.png

开发者使用 CloneSet 声明应用,用法类似 Deployment。在升级镜像时,由 CloneSet Controller 负责执行 patch 操作,同时确保升级过程中业务流量无损。

小结

 
从业务场景出发,我们了解了提升 Pod 创建效率带来收益的场景。然后通过分析 Pod 创建的流程,针对不同的阶段做相应的优化,有的放矢。

通过这样的分析处理流程,使得可以有效通过技术满足业务需求。

作者简介

张翼飞,就职于阿里云容器服务团队,主要专注 Serverless 领域的产品研发。

原文链接

本文为阿里云原创内容,未经允许不得转载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/514266.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安装wordcloud_COVID19数据分析实战:WordCloud 词云分析

↑↑点击上方蓝字,回复资料,N个G的惊喜前言上一篇文章(链接)我们对COVID19_line_list数据集进行了清洗以及初步分析。本文中我们将分析如何用词云来展示文本信息的概要。比如我们从词云百度百科截取文字,制作词云。简单来说,词云就…

到达率99.9%:闲鱼消息在高速上换引擎(集大成)

简介: 记录这一年闲鱼消息的优化之路 1. 背景 在2020年年初的时候接手了闲鱼的消息,当时的消息存在各种问题,网上的舆情也是接连不断:“闲鱼消息经常丢失”、“消息用户头像乱了”、“订单状态不对”(相信现在看文章的…

1小时打造HaaS版小小蛮驴智能车

1、认识一下小小蛮驴真面目 1.1、组件部分 HaaS100核心板 HaaS100是一款物联网场景中的标准硬件,并配套嵌入到硬件中的软件驱动及功能模块,为用户提供物联网设备高效开发服务。 HaaS100核心板有着丰富的外设接口,如下所示: 智…

Spring Boot Admin 集成诊断利器 Arthas 实践

简介: Arthas 是 Alibaba 开源的 Java 诊断工具,具有实时查看系统的运行状况;查看函数调用参数、返回值和异常;在线热更新代码;秒解决类冲突问题;定位类加载路径;生成热点;通过网页诊…

设计方案,拿来吧你!

作者:零一来源:前端印象前言大家好,我是零一,今天要跟大家聊聊开发流程中不起眼的环节——设计方案。你们可能没听过,也可能只是简单得走过过场,别划走,这非常重要!在字节&#xff0…

借力阿里云存储产品 延锋彼欧加速数字化重塑

简介: 延锋彼欧作为汽车外饰件生产的领航企业,通过基于业务和数据驱动的数字化管理,释放工业设备数据潜能提升产能。依托阿里云“稳定、安全、可靠、易用”的存储服务,延锋彼欧的发展步伐将更为稳健。 “一日骋千里,无…

英雄帖!移动云首批最有价值专家(MVP)招募开始了!

这是开发者的时代,这是价值重塑的时代。站在科技的潮头,我们期待去引领、去挖掘、去创造……移动云已迎来飞速发展的黄金期,移动云开发者社区将成为业界优秀开发者的聚集地。今天,移动云开发者社区正式开启移动云MVP首批招募&…

无责任畅想:云原生中间件的下一站

简介: 本文源自 2020 年 12 月 20 日作者在云原生社区 meetup 第二期北京站演讲 《Apache Dubbo-go 在云原生时代的实践与探索》的部分内容 自从以 2013 年开源的 docker 为代表的的容器技术和以 2014 年开源的 K8s 为代表的容器编排技术登上舞台之后,相…

深度剖析:Redis 分布式锁到底安全吗?看完这篇文章彻底懂了!

作者 | Kaito 来源 | 水滴与银弹阅读本文大约需要 20 分钟。大家好,我是 Kaito。这篇文章我想和你聊一聊,关于 Redis 分布式锁的「安全性」问题。Redis 分布式锁的话题,很多文章已经写烂了,我为什么还要写这篇文章呢?因…

Spring Boot 微服务性能下降九成!使用 Arthas 定位根因

简介: 接收到公司业务部门的开发反馈,应用在升级公司内部框架后,UAT(预生产)环境接口性能压测不达标。 背景 接收到公司业务部门的开发反馈,应用在升级公司内部框架后,UAT(预生产&a…

阿里研究员:线下环境为何不稳定?怎么破

简介: 为什么线下环境的不稳定是必然的?我们怎么办?怎么让它尽量稳定一点? 这篇文章想讲两件事: 为什么线下环境[1]的不稳定是必然的?我们怎么办?怎么让它尽量稳定一点? 此外&#…

谁说技术男不浪漫!90后程序员2天做出猫咪情绪识别软件

整理 | 王晓曼出品 | CSDN(ID:CSDNnews)9月1日,一则关于#程序员2天做出猫咪情绪识别软件#的话题登上微博热搜,参与阅读的人数达到了8218.1万,讨论次数1.3万,引发网友们的热议。高手在民间&#…

闲鱼如何一招保证推荐流稳如泰山

简介: 风雨不动安如山 背景 近几年互联网的快速发展中,互联网业务发展越来越复杂,业务也被拆分得越来越细,阿里内部业务也发生着翻天覆地的变化,从最初的单体应用,到后面的分布式集群,再到最近…

电商直播平台如何借助容器与中间件实现研发效率提升100%?

简介: 经过实际场景验证及用户的综合评估,电商直播平台借助全面的云原生容器化能力和中间件产品能力,大幅提升开发部署运维效率达50%~100%,极大地提升了用户体验,为业务持续发展打下了坚实的基础。 前言 直播带货是近…

在游戏运营行业,Serverless 如何解决数据采集分析痛点?

简介: 众所周知,游戏行业在当今的互联网行业中算是一棵常青树。在疫情之前的 2019 年,中国游戏市场营收规模约 2884.8 亿元,同比增长 17.1%。2020 年因为疫情,游戏行业更是突飞猛进。玩游戏本就是中国网民最普遍的娱乐…

字节大战腾讯元宇宙;Docker 自己定制镜像;VMware 云桌面助力秦皇岛市第一医院;微软开源 Cloud Katana;...

NEWS本周新闻回顾字节大战腾讯元宇宙:布局社交产品Pixsoul,上线游戏“重启世界”字节投资的代码乾坤,已于近日正式上线了元宇宙游戏《重启世界》。就在两个月前,被称为“元宇宙第一股”的Roblox登陆国内,由腾讯改名为《…

从 RxJS 到 Flink:如何处理数据流?

简介: 前端开发的本质是什么?响应式编程相对于 MVVM 或者 Redux 有什么优点?响应式编程的思想是否可以应用到后端开发中?本文以一个新闻网站为例,阐述在前端开发中如何使用响应式编程思想;再以计算电商平台…

Spring RSocket:基于服务注册发现的 RSocket 负载均衡

简介: RSocket 作为通讯协议的后起之秀,核心是二进制异步化消息通讯,是否也能和 Spring Cloud 技术栈结合,实现服务注册发现、客户端负载均衡,从而更高效地实现面向服务的架构?这篇文章我们就讨论一下 Spri…

双非院校计算机系毕业的学生能进大厂吗?

谈到大厂,我们常常会主动匹配与之对应的高学历。其实不论是大厂还是小公司,都是会筛简历的,这个毋庸置疑。从大厂招聘的结果上看,高学历人才的数量占据大头,而那些成功进入BAT、网易等大厂的专科生、二本三本学生&…

Python - 深夜数据结构与算法之 Heap Binary Heap

目录 一.引言 二.堆与二叉堆介绍 1.Heap 堆 2.Binary Heap 二叉堆 3.HeapifyUp 添加节点 4.HeapifyDown 删除节点 5.Heap 时间复杂度 6.Insert & Delete 代码实现 三.经典算法实战 1.Smallest-K [M14] 2.Sliding-Window-Max [239] 3.Ugly-Number [264] 4.Top-…