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

继前一篇《函数计算性能福利篇——系统冷启动优化》,我们再来看看近期函数计算推出的 Initializer 功能之后,带来的一波高能性能优化成果。

背景
函数计算是一个事件驱动的全托管 serverless 计算服务,用户可以将业务实现成符合函数计算编程模型的函数,交付给平台快速实现弹性高可用的云原生应用。

用户函数调用链路包括以下几个阶段:

系统为函数分配计算资源;
下载代码;
启动容器并加载函数代码;
用户函数内部进行初始化逻辑;
函数处理请求并将结果返回。
其中前三步是系统层面的冷启动开销,通过对调度以及各个环节的优化,函数计算能做到负载快速增长时稳定的延时,细节详见 函数计算系统冷启动优化。
第4步是函数内部初始化逻辑,属于应用业务层面的冷启动开销,例如深度学习场景下加载规格较大的模型、数据库场景下连接池构建、函数依赖库加载等等。为了减小应用层冷启动对延时的影响,函数计算推出了 initializer 接口,便于用户抽离业务初始化逻辑。这样用户就能将自身业务的初始化逻辑和请求处理逻辑分离,分别是实现在 initializer 接口和 handler 接口中,使得系统能识别用户函数的初始化逻辑,从而在调度上做相应的优化。

Initializer 功能简介
引入 initializer 接口的价值主要体现在如下几个方面:

分离初始化逻辑和请求处理逻辑,程序逻辑更清晰,让用户更易写出结构良好,性能更优的代码;
用户函数代码更新时,系统能够保证用户函数的平滑升级,规避应用层初始化冷启动带来的性能损耗。新的函数实例启动后能够自动执行用户的初始化逻辑,在初始化完成后再处理请求;
在应用负载上升,需要增加更多函数实例时,系统能够识别函数应用层初始化的开销,更精准的计算资源伸缩的时机和所需的资源量,让请求延时更加平稳;
即使在用户有持续的请求且不更新函数的情况下,FC系统仍然有可能将已有容器回收或更新,这时没有平台方(FC)的冷启动,但是会有业务方冷启动,Initializer可以最大限度减少这种情况;
具体的 Initializer 功能设计和使用指南,请参考官方 Initiliazer 介绍 。

初始化场景性能对比
上一节已经简单了概括了 Initializer 的功能,这里,我们具体展示一下初始化场景下 Initializer 带来的巨大的性能提升效应。

函数实现
初始化应用场景,如果不使用 initializer,那么函数的主要实现方式应该是 Global variable 方式,下面提供两种实现方式的 demo ,仅供参考,下面的性能测试也是对比这两种函数实现方式进行了。

使用 global variables 实现业务层初始化逻辑:

-- coding: utf-8 --

import time
import json

isInit = False
def init_handler():
time.sleep(30)
global isInit
isInit = True

def handler(event, context):
evt = json.loads(event)
funcSleepTime = evt[‘funcSleepTime‘]
if not isInit:
init_handler()
time.sleep(funcSleepTime)
使用 initializer 的编程模型实现业务层初始化逻辑:

-- coding: utf-8 --

import time
import json

def init_handler(context):
time.sleep(30)

def handler(event, context):
evt = json.loads(event)
funcSleepTime = evt[‘funcSleepTime‘]
time.sleep(funcSleepTime)
两个 function 的逻辑相同:

函数实例运行时,先执行 init_handler 逻辑,执行时间 30s,进行业务层初始化;
如果已经初始化,那么就执行 handler 逻辑,执行时间 0.1s,进行请求处理;如果没有初始化,那么先进行初始化逻辑,再执行 handler 逻辑。
场景对比
这里根据生产用户请求场景,我们选择如下三种测试 case 来对比两种初始化函数实现的性能。

负载持续增加模式
波峰 burst 模式
业务逻辑升级模式
测试函数的特性如下:

函数 handler 逻辑运行时间为 100ms;
函数 初始化 逻辑运行时间为 30s;
函数代码包大小为 50MB;
runtime 为 python2.7;
Memory 为 3GB 。
这样的函数,系统层冷启动时间大约在 1s 左右,业务层冷启动在 30s,而函数自身请求执行时间为100-130ms。

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

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

注意:忽略第一批请求的完全冷启动的延时影响。

?不使用 initializer 实现的运行结果:


从每波请求的请求延时可以看出,虽然系统层的调度能够为后来的骤增的请求分配更多的函数实例,但是因为函数实例都没有执行过业务层的初始化逻辑,所以新的函数实例花费了大量的执行时间在初始化逻辑的执行上,所以看到 99th latency 都大于 30s 。实际上,系统层的调度优化在这样长时间的初始化场景中并起不了作用。

使用 initializer 实现的运行结果,可以看到使用 initializer 功能之后,请求增长率在 100% 的情况下不会再有函数实例执行初始化逻辑,相对于优化前,99th latency 下降了 30 倍以上。

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

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

注意:忽略第一批请求的完全冷启动的延时影响。???

?不使用 initializer 实现的运行结果:


使用 initializer 实现的运行结果,对于 burst 的流量,基本能够将 latency 的增长控制在 函数处理逻辑 6 倍以内,99th 的 latency 被优化到原来的 2.9% 。


? 业务逻辑升级模式
业务逻辑升级模式是指用户请求比较平稳,但是用户函数会持续 UpdateFunction,变更业务逻辑,进行用户业务升级。设计请求行为如下:

每波请求时间间隔 35s;
每波平稳请求数 2;
每 6 波请求进行一次 UpdateFunction 操作;
TPS 如下:

注意:忽略第一批请求的完全冷启动的延时影响。

?不使用 initializer 实现的运行结果,这个时候请求又会重新执行一次初始化逻辑,导致毛刺出现。


使用 initializer 实现的运行结果,基本看出,UpdateFunction 操作对请求已经没有影响,业务层无感知。
?

总结
综上数据分析,函数计算的 Initializer 功能极大的优化了业务层冷启动的毛刺影响:

在用户请求存在明显 burst 或者在以一定速率增长的情况下,能够极大的缓解性能影响,如上,在负载持续增加模式和波峰模式场景下,请求平均 latency 仅仅增加 3 倍,99th latency 只增加了 5 倍,99th latency 仅为优化前的 2.9% ,整整下降了 33 倍之多。
在用户有持续的请求且不更新函数的情况下,优化之后更新函数,业务层能够做到无感知,平滑热升级。
Initializer 功能对业务层冷启动的优化,又一次大大改善了函数计算在延时敏感场景下的表现!

原文地址:http://blog.51cto.com/14031893/2330124

时间: 2024-11-02 22:58:46

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

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

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

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

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

SQL Server调优系列玩转篇二(如何利用汇聚联合提示(Hint)引导语句运行)

原文:SQL Server调优系列玩转篇二(如何利用汇聚联合提示(Hint)引导语句运行) 前言 上一篇我们分析了查询Hint的用法,作为调优系列的最后一个玩转模块的第一篇.有兴趣的可以点击查看:SQL Server调优系列玩转篇(如何利用查询提示(Hint)引导语句运行) 本篇继续玩转模块的内容,同样,还是希望扎实掌握前面一系列的内容,才进入本模块的内容分析. 闲言少叙,进入本篇的内容. 技术准备 数据库版本为SQL Server2012,利用微软的以前的案例库(Northwind)进行分析,

Qt学习总结-ui篇(二)

qccs定义圆角 border-radius:10px; 如果想给特定位置定义圆角,如: 左上角:border-left-top-radius:10px; 右下角色:border-right-bottom-rasius:10px; 半透明效果 只需要在css中使用rgba(100,100,100,40)这种形式来表示颜色即可. 为可执行文件添加图标 1.新建文件:finename.rc 文件名无所谓,只要后缀为rc就可以. 2.编辑新建的文件,输入以下内容: IDI_ICON1 ICON DIS

Oracle内存管理理论篇二

目标 了解oracle内存管理方式 掌握ASMM管理方式 掌握AMM管理方式 监控内存使用 学习一个知识点时,最好先了解其历史.ORACLE近期的版本都对内存管理做了简化,从9i通过PGA_AGGREGATE_TARGET参数实现PGA的自动管理,10g通过Automatic Shared Memory Management(ASMM)实现SGA的自动管理,到11g通过Automatic Memory Management(AMM)实现内存(SGA+PGA)的自动管理.目前的11G版本,DBA只

php基础篇-二维数组排序 array_multisort

原文:php基础篇-二维数组排序 array_multisort 对2维数组或者多维数组排序是常见的问题,在php中我们有个专门的多维数组排序函数,下面简单介绍下: array_multisort(array1,sorting order, sorting type,array2,array3..)是对多个数组或多维数组进行排序的函数. array1 必需.规定输入的数组. sorting order 可选.规定排列顺序.可能的值是 SORT_ASC 和 SORT_DESC. sorting t

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

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

SQL Server调优系列基础篇(并行运算总结篇二)

原文:SQL Server调优系列基础篇(并行运算总结篇二) 前言 上一篇文章我们介绍了查看查询计划的并行运行方式. 本篇我们接着分析SQL Server的并行运算. 闲言少叙,直接进入本篇的正题. 技术准备 同前几篇一样,基于SQL Server2008R2版本,利用微软的一个更简洁的案例库(Northwind)进行解析. 内容 文章开始前,我们先来回顾上一篇中介绍的并行运算,来看文章最后介绍的并行运算语句: SELECT B1.[KEY],B1.DATA,B2.DATA FROM BigTa

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

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