Serverless应用优化
4.4.1 资源评估依旧重要
Serverless架构虽然是按量付费的,但是并不代表它就一定比传统的服务器租用费用低。如果对自己的项目评估不准确,对一些指标设置不合理,Serverless架构所产生的费用可能是巨大的。
一般情况下,FaaS平台的收费和三个指标有直接关系,即所配置的函数规格(例如内存规格等)、程序所消耗的时间以及产生的流量费用。通常情况下,程序所消耗的时间可能与内存规格、程序本身所处理的业务逻辑有关。流量费用与程序本身和客户端交互的数据包大小有关。所以在这三个常见的指标中,可能因为配置不规范导致计费出现比较大偏差的就是内存规格。以阿里云函数计算为例,假设有一个Hello World程序,每天都会被执行10 000次,不同规格的内存所产生的费用(不包括网络费用)如表4-2所示。
表4-2 阿里云函数计算不同内存规格收费统计
通过表4-2可以看到,当程序在128MB规格的内存中可以正常执行,如果错误地将内存规格设置成3072MB,可能每月产生的费用将会暴涨25倍!所以在上线Serverless应用之前,要对资源进行评估,以便以更合理的配置来进一步降低成本。
4.4.2 合理的代码包规格
各个云厂商的FaaS平台中都对代码包大小有着限制。抛掉云厂商对代码包的限制,单纯地说代码包的规格可能会产生的影响,通过函数的冷启动流程可以看到,如图4-27所示。
图4-27 函数冷启动流程简图
在函数冷启动过程中,当所上传的代码包过大,或者文件过多导致解压速度过慢,就会使加载代码过程变长,进一步导致冷启动时间变久。
设想一下,当有两个压缩包,一个是只有100KB的代码压缩包,另一个是200MB的代码压缩包,两者同时在千兆的内网带宽下理想化(即不考虑磁盘的存储速度等)下载,即使最大速度可以达到125MB/s,那么前者的下载时间只有不到0.01秒,后者需要1.6秒。除了下载时间之外,加上文件的解压时间,那么两者的冷启动时间可能就相差2秒。一般情况下,对于传统的Web接口,如果要2秒以上的响应时间,实际上对很多业务来说是不能接受的,所以在打包代码时就要尽可能地降低压缩包大小。以Node.js项目为例,打包代码包时,我们可以采用Webpack等方法来压缩依赖包大小,进一步降低整体代码包的规格,提升函数的冷启动效率。
4.4.3 合理复用实例
为了更好地解决冷启动的问题、更合理地利用资源,各个云厂商的FaaS平台中是存在实例复用情况的。所谓的实例复用,就是当一个实例完成一个请求后并不会释放,而是进入静默的状态。在一定时间范围内,如果有新的请求被分配过来,则会直接调用对应的方法,而不需要再初始化各类资源等,这在很大程度上减少了函数冷启动的情况出现。为了验证,我们可以创建两个函数:
函数1:
# -*- coding: utf-8 -*- def handler(event, context): print("Test") return 'hello world'
函数2:
# -*- coding: utf-8 -*- print("Test") def handler(event, context): return 'hello world'
在控制台点击“测试”按钮,对上述两个函数进行测试,判断其是否在日志中输出了“Test”,统计结果如表4-3所示。
表4-3 函数复用记录
可以看到,其实实例复用的情况是存在的。进一步思考,如果print("Test")语句是一个初始化数据库连接,或者是函数1和函数2加载了一个深度学习模型,是不是函数1就是每次请求都会执行,而函数2可以复用已有对象?
所以在实际的项目中,有一些初始化操作是可以按照函数2实现的,例如:
- 在机器学习场景下,在初始化的时候加载模型,避免每次函数被触发都会加载模型。
- 在初始化的时候建立链接对象,避免每次请求都创建链接对象。
- 其他一些需要首次加载时下载、加载的文件在初始化时实现,提高实例复用效率。
4.4.4 善于利用函数特性
各个云厂商的FaaS平台都有一些特性。所谓的平台特性,是指这些功能可能并不是CNCF WG-Serverless Whitepaper v1.0中规定的能力或者描述的能力,仅仅是作为云平台根据自身业务发展和诉求从用户角度出发挖掘出来并且实现的功能,可能只是某个云平台或者某几个云平台所拥有的功能。这类功能一般情况下如果利用得当会让业务性能有质的提升。
1. Pre-freeze & Pre-stop
以阿里云函数计算为例,在平台发展过程中,用户痛点(尤其是阻碍传统应用平滑迁移至Serverless架构)如下。
- 异步背景指标数据延迟或丢失:如果在请求期间没有发送成功,则可能被延迟至下一次请求,或者数据点被丢弃。
- 同步发送指标增加延时:如果在每个请求结束后都调用类似Flush接口,不仅增加了每个请求的延时,对于后端服务也产生了不必要的压力。
- 函数优雅下线:实例关闭时应用有清理连接、关闭进程、上报状态等需求。在函数计算中实例下线时,开发者无法掌握,也缺少Webhook通知函数实例下线事件。
根据这些痛点,阿里云发布了运行时扩展(Runtime Extensions)功能。该功能在现有的HTTP服务编程模型上扩展,在已有的HTTP服务器模型中增加了PreFreeze和PreStop Webhook。扩展开发者负责实现HTTP handler,监听函数实例生命周期事件,如图4-28所示。
图4-28 扩展编程模型与现有编程模型处理的工作内容简图
- PreFreeze:在每次函数计算服务决定冷冻当前函数实例前,函数计算服务会调用HTTP GET/prefreeze路径,扩展开发者负责实现相应逻辑以确保完成实例冷冻前的必要操作,例如等待指标发送成功等,如图4-29所示。函数调用InvokeFunction的时间不包含PreFreeze Hook的执行时间。
图4-29 PreFreeze时序图
- PreStop:在每次函数计算决定停止当前函数实例前,函数计算服务会调用HTTP GET/prestop路径,扩展开发者负责实现相应逻辑以确保完成实例释放前的必要操作,如等待数据库链接关闭,以及上报、更新状态等,如图4-30所示。
图4-30 PreStope时序图
2. 单实例多并发
众所周知,各云厂商的函数计算通常是请求级别的隔离,即当客户端同时发起3个请求到函数计算,理论上会产生3个实例进行应对,这个时候可能会涉及冷启动以及请求之间状态关联等问题。因此,部分云厂商提供了单实例多并发的能力(例如阿里云函数计算)。该能力允许用户为函数设置一个实例并发度(InstanceConcurrency),即单个函数实例可以同时处理多个请求,如图4-31所示。
图4-31 单实例多并发效果简图
如图4-31所示,假设同时有3个请求需要处理,当实例并发度设置为1时,函数计算需要创建3个实例来处理这3个请求,每个实例分别处理1个请求;当实例并发度设置为10时(即1个实例可以同时处理10个请求),函数计算只需要创建1个实例就能处理这3个请求。
单实例多并发的优势如下。
- 减少执行时长,节省费用。例如,偏I/O函数可以在一个实例内并发处理请求,减少了实例数,从而减少总的执行时长。
- 请求之间可以共享状态。多个请求可以在一个实例内共用数据库连接池,从而减少和数据库之间的连接数。
- 降低冷启动概率。由于多个请求可以在一个实例内处理,创建新实例的次数会减少,冷启动概率降低。
- 减少占用VPC IP。在相同负载下,单实例多并发可以降低总的实例数,从而减少VPC IP的占用。
单实例多并发的应用场景比较广泛,例如函数中有较多时间在等待下游服务响应的场景就比较适合使用该功能。单实例多并发也有不适合应用的场景,例如函数中有共享状态且不能并发访问时,单个请求的执行要消耗大量CPU及内存资源,这时就不适合使用单实例多并发功能。
标签:Serverless,函数,并发,实例,冷启动,应用,优化,请求 From: https://www.cnblogs.com/muzinan110/p/17067644.html