函数计算性能福利篇(一) —— 系统冷启动优化

摘要: 背景 函数计算是一个事件驱动的全托管 serverless 计算服务。使用函数计算构建应用,用户只需要专注于实现应用层的逻辑实现;服务器等基础设施的容错、伸缩以及运维工作由平台来完成。因此用户能在很短的时间内实现弹性高可用的云原生应用。

背景
函数计算是一个事件驱动的全托管 serverless 计算服务。使用函数计算构建应用,用户只需要专注于实现应用层的逻辑实现;服务器等基础设施的容错、伸缩以及运维工作由平台来完成。因此用户能在很短的时间内实现弹性高可用的云原生应用。

函数计算在容器中执行用户函数代码,这样的环境我们称为函数实例。实例的生成需要一些额外的系统准备工作,比如选择执行函数的引擎,下载用户的代码,启动容器,加载函数等等。如果请求的调用链路里包含了上述环节,我们就称之为冷启动。实例一旦生成,会持续服务请求;当一段时间内没有请求后,系统将回收实例。因此,冷启动通常发生在函数首次调用或者负载升高需要更多的实例来处理对应的请求。

"冷启动"对于毛刺敏感的业务会显得不那么友好,所以冷启动的优化对于函数计算在延时敏感型场景中的应用尤为重要。

系统架构
在探讨调度优化之前,我们先简要介绍函数计算的架构以及调度方式,如下图所示。

API 服务层完成身份验证,元数据的读写等功能。同步调用函数时,API 服务模块从资源调度模块获取可用的函数执行引擎并发送请求,函数执行引擎根据函数相关信息准备执行所需环境,启动容器进行计算,最后取回结果。异步调用函数时,则将事件写入到消息队列后即返回。由事件分发模块分发事件,整个流程和同步调用类似。

资源调度模块主要负责函数计算分布式系统的负载均衡和实时弹性伸缩。当一个用户请求达到时,资源调度模块进行第一层调度——分配函数执行引擎,然后在函数执行引擎中进行第二层调度——分配函数实例,进而才开始执行用户函数。而当用户一段时间内不再请求,调度系统就会自动回收函数实例和函数执行引擎资源。如下为用户请求处理资源调度流程:

为了保证用户请求使用的资源,一个函数实例只能同时服务一个请求,所以在用户请求并发较大的情况下,系统会调度更多的资源来消费该用户的请求。

如架构图所示,系统层的"冷启动"就是从函数执行引擎的获取到函数实例创建的整个过程,主要的步骤如下:

而冷启动的快慢受限于很多情况,主要因素有用户代码大小、网络因素、runtime 环境因素等,所以,对于实时性要求高的业务场景来说,冷启动的存在是不友好的。

调优策略
冷启动问题导致了大量并发到来的时候,毛刺加剧,根源在现存的实例调度方式无法快速响应请求而引起请求在整条链路中长时间处于系统新资源的分配等待中。

所以,要提高实例调度速率、快速响应请求,减少排队请求数,主要着手于如下两个方面:

加快空闲实例投入使用,提高利用率;
在峰值到来时,加快新实例生成,增加实例储备。
加快空闲实例投入使用速率这一点,能很大程度上减少请求在链路上等待冷启动的时间,从而加快请求被处理的速率。在用户函数逻辑执行较快的情况下,实例能够被快速释放,如果此时一个正在等待冷启动的请求能够探测到已经有实例进入空闲状态,那么就会被处理。而之前的冷启动则转入后台继续进行,生成新的实例,增大实例储备,应对更多的请求处理。

另外一方面,因为用户的资源配额在系统层面有限制,比如在超大并发的请求下用户可能会遇到 ServiceUnavailable 错误。而调度策略上如果能够加快空闲实例投入使用的速率,那么实际上也减少了冷启动的次数,即减少了对资源配额的开销,增加资源利用率,从而减少了被系统流控的可能。

调优结果
根据用户实际使用场景,我们设计如下两种测试case来验证调优效果:

负载持续增加模式
波峰 burst 模式
测试函数的特性如下:

函数自身逻辑运行时间为 100ms;
函数代码包大小为 50MB;
runtime 为 python2.7;
Memory 为 3GB 。
这样的函数,如果带有冷启动,单次端到端的请求 latency 在 1.7s - 3s,不带冷启动的请求端到端 latency 在 105 - 120ms。

负载持续增加模式
该模式下,用户的请求在一段时间内会持续增长。设计请求行为如下:

每波请求并发数翻倍递增: 1, 2, 4, 8, 16, 32;
每波请求的时间间隔为 10s。
TPS情况如下,增长率为100%:

优化前后对比
10s 聚合的 latency 指标如下监控:
优化前, 平均 latency 在 1000ms 左右,而99%的请求 latency 均在 1.8s 以上。

优化后,平均 latency 为 200ms 以下(排除第一个完全冷启动),99% 的请求 latency 大部分在 200ms 左右,较之前下降一个数量级。

单个请求情况分析
更直观的分析,我们把每一个请求的端到端 latency列出来比较,如下图。每一波请求中,都有一半的请求能够直接使用前一波请求现存下来的实例,而另一半请求都需要等待新的调度。明显看到,旧的调度策略上,这一半请求几乎全部都在傻傻等待处于完全冷启动状态;新的调度策略中,明显看到这一半请求都被调度到了提前释放的实例上被处理,从而大大优化了毛刺情况。

优化前:

优化后:

波峰 burst 模式
波峰burst模式是指用户请求比较平稳,但是会有突然的波峰流量场景。设计请求行为如下:

每波请求时间间隔 10s;
每波平稳请求数 2;
burst 请求数 20;
TPS请求如下,burst 流量猛增 10 倍:

优化前后对比
10s 聚合的 latency 指标如下监控:
对比99%的请求 latency,毛刺下降了整整一倍多。

优化前

优化后

单个请求情况分析
按处理顺序,我们罗列出优化前和优化后处于 burst 时期 20 个请求的每一个 latency 的情况,如下表。不难发现,除了最前面的两个请求直接使用了现存的 2 个实例,其他请求全部都是需要等待调度的。优化前,所有的请求都在完全等待冷启动;而优化后,不难发现,每两个请求的 latency 处于相同的水平,而前后两组之间相差 100ms (正好是函数执行时间),从而说明新的调度方式有效的复用了已有的"热"的容器。

实际在线用户请求优化结果
对在线某一用户的实时流量跟进分析,看到优化前后明显对比,如下图所示。优化前 TPS 在某一时间点从 11 上升到25,此时 99% 的 latency 出现一个明显的毛刺现象。在2个小时之后,优化开关打开,某一时间点 TPS 达到了 32,此时 latency 无明显波动。

总结
综上数据分析,在典型的负载变化情况下,冷启动对 99% 的请求 latency 的影响已经忽略不计,本次调度上的调优大大改善了函数计算在延时敏感场景下的表现。

原文链接

本文为云栖社区原创内容,未经允许不得转载。

原文地址:http://blog.51cto.com/13876536/2163516

时间: 2024-11-04 21:20:35

函数计算性能福利篇(一) —— 系统冷启动优化的相关文章

函数计算性能福利篇(二) —— 业务冷启动优化

继前一篇<函数计算性能福利篇--系统冷启动优化>,我们再来看看近期函数计算推出的 Initializer 功能之后,带来的一波高能性能优化成果. 背景函数计算是一个事件驱动的全托管 serverless 计算服务,用户可以将业务实现成符合函数计算编程模型的函数,交付给平台快速实现弹性高可用的云原生应用. 用户函数调用链路包括以下几个阶段: 系统为函数分配计算资源:下载代码:启动容器并加载函数代码;用户函数内部进行初始化逻辑:函数处理请求并将结果返回.其中前三步是系统层面的冷启动开销,通过对调度

linux小白-基础篇-系统简单优化

作为一个刚刚接触Linux的小白,通过一段时间的学习,将我自己的部分笔记整理后拿出来,请求大家指点:因为是"0"基础学起很多地方了解的都不够深入,希望各位前辈能够指点一下:予人玫瑰,手留余香,谢谢! 因为条件有限环境是用VM搭建起来的,下文主要是根据"老男孩教育视频"中的内容整理出来的系统简单优化,希望各位前辈看过以后可以给出建议: 已学习进步为目的,不喜勿喷!谢谢! 系统简单优化    命令 一.关闭selinux                         

【转】JS组件系列——Bootstrap组件福利篇:几款好用的组件推荐(二)

前言:上篇 JS组件系列——Bootstrap组件福利篇:几款好用的组件推荐 分享了几个项目中比较常用的组件,引起了许多园友的关注.这篇还是继续,因为博主觉得还有几个非常简单.实用的组件,实在不愿自己一人独享,没办法,谁让博主这么爱分享呢~~ 本文原创地址:http://www.cnblogs.com/landeanfen/p/5603790.html 七.多值输入组件manifest 关于文本框的多值输入,一直是一个比较常见的需求,今天博主推荐一款好用的多值输入组件给大家,不要谢我,请叫我“红

修改进程占用内存SetProcessWorkingSetSize函数(多篇相关文章值得学习)

物理内存和虚拟内存 物理内存,在应用中,自然是顾名思义,物理上,真实的插在板子上的内存是多大就是多大了.看机器配置的时候,看的就是这个物理内存. 如果执行的程序很大或很多,就会导致物理内存消耗殆尽.为了解决这个问题,Windows中运用了虚拟内存技术,即拿出一部分硬盘空间来充当内存使用,当内存占用完时,电脑就会自动调用硬盘来充当内存,以缓解内存的紧张. 一个程序,不可避免地要用到虚拟内存,因为不频繁执行或者已经很久没有执行的代码,没有必要留在物理内存中,只会造成浪费;放在虚拟内存中,等执行这部分

机房收费系统——登录优化

<机房收费系统个人版>基本上完工了,我的U层代码很多很乱.基本上是D层有几个函数,B层就对应有几个函数,U层使用对应B层中的每一个函数.比如说在登录中,U层首次要使用一个函数检查用户名和用户密码是否正确,然后再使用"添加用户上机记录"的函数.下面是登录的时序图: 登录业务比较简单,但是对于复杂的上机过程呢?U层要检查卡是否注册,余额是否充足,卡的状态是否在使用中,该卡是否现在不在线,通过这一系列检验后,还要查询学生表显示学生信息等等.这样就造成U层有好多函数,和B层的耦合度

qsort函数、sort函数 (精心整理篇)

先说明一下qsort和sort,只能对连续内存的数据进行排序,像链表这样的结构是无法排序的. 首先说一下, qsort qsort(基本快速排序的方法,每次把数组分成两部分和中间的一个划分值,而对于有多个重复值的数组来说,基本快速排序的效率较低,且不稳定).集成在C语言库函数里面的的qsort函数,使用 三 路划分的方法解决排序这个问题.所谓三路划分,是指把数组划分成小于划分值,等于划分值和大于划分值的三个部分. 具体介绍:-^^ void qsort( void *base, size_t n

FreeRTOS高级篇9---FreeRTOS系统延时

FreeRTOS提供了两个系统延时函数:相对延时函数vTaskDelay()和绝对延时函数vTaskDelayUntil().相对延时是指每次延时都是从任务执行函数vTaskDelay()开始,延时指定的时间结束:绝对延时是指每隔指定的时间,执行一次调用vTaskDelayUntil()函数的任务.换句话说:任务以固定的频率执行.在<FreeRTOS系列第11篇---FreeRTOS任务控制>一文中,已经介绍了这两个API函数的原型和用法,本文将分析这两个函数的实现原理. 1. 相对延时函数v

qsort函数、sort函数 (精心整理篇)(转载)

qsort函数.sort函数 (精心整理篇) 先说明一下qsort和sort,只能对连续内存的数据进行排序,像链表这样的结构是无法排序的. 首先说一下, qsort qsort(基本快速排序的方法,每次把数组分成两部分和中间的一个划分值,而对于有多个重复值的数组来说,基本快速排序的效率较低,且不稳定).集成在C语言库函数里面的的qsort函数,使用 三 路划分的方法解决排序这个问题.所谓三路划分,是指把数组划分成小于划分值,等于划分值和大于划分值的三个部分. 具体介绍:-^^ void qsor

项亮《推荐系统实践》读书笔记2-推荐系统冷启动问题

推荐系统冷启动问题 如何在没有大量用户数据的情况下设计个性化推荐系统并且让用户对推荐结果满意从而愿意使用推荐系统,就是冷启动问题. 冷启动问题主要分为三类: (1) 用户冷启动:如何给新用户做个性化推荐的问题,新用户刚使用网站的时候,系统并没有他的行为数据: (2) 物品冷启动:解决如何将新的物品推荐给可能对它感兴趣的用户: (3) 系统冷启动:如何在新开发网站设计个性化推荐系统,此时网站上用户很少,用户行为也少,只有一些商品的信息. 冷启动的主要解决方案: (1) 提供非个性化推荐:如热门排行