写点什么

Serverless 架构下还需要评估函数资源吗?

  • 2020-08-09
  • 本文字数:5664 字

    阅读完需:约 19 分钟

Serverless架构下还需要评估函数资源吗?

Serverless 布道师在讲述 Serverless 架构和云主机区别的时候,常会有这样的描述:


传统业务开发想要上线,需要先评估资源使用,并根据资源评估结果购买云主机,之后还要根据业务发展不断对主机等资源进行升级维护。而 Serverless 架构不需要这样复杂的流程,将函数部署到线上后,一切后端服务交给运营商来处理,哪怕是瞬时高并发,也有云厂商来自动扩缩。


但在实际生产生活中,Serverless 真的可以做到无需对资源评估吗?还是说在 Serverless 架构下,资源评估的内容或对象发生了变化,或者进行了简化?

探索 Serverless 下的资源评估

以国内某云厂商为例,在其云函数中,我们创建一个云函数之后,设置页面会出现可设置的选项:



这两个设置范围分别是从 64M-1536M 和 1-900S,这样的配置其实就涉及到资源评估了。


首先是超时时间,一个项目、函数或 Action 都有执行时间,如果超过某个时间没执行完就可以评估其为发生了“意外”,可以被“干掉“了,这个就是超时时间。例如一个获取用户信息的请求,在 10S 内没有返回,证明其不能满足业务需求,那么,我们就可以把超时设置为 10S。当一个运行速度很慢的业务,至少要 50S 才能执行完,那么这个值设置的时候就要大于 50,否则程序可能因为超时被强行停止。


然后是内存,内存是一个有趣的东西,可能衍生两个关联点。


关联点 1: 程序本身需要一定的内存,这个内存要大于程序本身的内存,以 Python 语言为例:


# -*- coding: utf8 -*-import jieba

def main_handler(event, context): jieba.load_userdict("./jieba/dict.txt") seg_list = jieba.cut("我来到北京清华大学", cut_all=True) print("Full Mode: " + "/ ".join(seg_list)) # 全模式
seg_list = jieba.cut("我来到北京清华大学", cut_all=False) print("Default Mode: " + "/ ".join(seg_list)) # 精确模式
seg_list = jieba.cut("他来到了网易杭研大厦") # 默认是精确模式 print(", ".join(seg_list))
seg_list = jieba.cut_for_search("小明硕士毕业于中国科学院计算所,后在日本京都大学深造") # 搜索引擎模式 print(", ".join(seg_list))

复制代码


对程序代码的说明:为了让结果更加直观,差距更加大,所以这里每次都重新导入了自带 dict,这个操作本身就是相对浪费时间和内存的。在实际使用中 jieba 自带缓存,并且无需手动导入本身的 dict


当导入一个自定义的 dict 到 jieba 中,如果此时函数内存设置的默认 128M 内存限制+3S 超时限制就会这样:



此时可以看到,由于在导入自定义 dict 时内存消耗过大, 默认的 128 不足以满足需求,所以需要将其修改成最大:



这时又再次提醒超时,还需要修改超时时间为适当的数值(此处设定为 10S):



总而言之,在关注程序本身的前提下,要将内存设置在一个合理范围内,这个范围是>=程序本身需要的内存数值。


关联点 2: 计费相关,在云函数的文档中,我们可以看到:


云函数 SCF 按照实际使用付费,采用后付费小时结,以 为单位进行结算。

SCF 账单由以下三部分组成,每部分根据自身统计结果和计算方式进行费用计算,结果以 为单位,并保留小数点后两位。

资源使用费用

调用次数费用

外网出流量费用


调用次数和出网流量都是与程序或者使用量相关的,无需格外关注,但在资源使用费用有一些注意点:


资源使用量 = 函数配置内存 × 运行时长

用户资源使用量,由函数配置内存,乘以函数运行时的计费时长得出。其中配置内存转换为 GB

单位,计费时长由毫秒(ms)转换为秒(s)单位,因此,资源使用量的计算单位为 GBs (GB-秒)。

例如,配置为 256MB 的函数,单次运行了 1760 ms,计费时长为 1760

ms,则单次运行的资源使用量为(256/1024)×(1760/1000) = 0.44 GBs。

针对函数的每次运行,均会计算资源使用量,并按小时汇总求和,作为该小时的资源使用量。


这里有一个非常重要的公式,那就是函数配置内存*运行时长。函数配置内存就是我们为程序选择的内存大小,运行时长就是运行程序之后得到的结果:



以这个程序为例,使用的是 1536MB,则使用量为(1536/1024) * (3200/1000) = 4.8GBs


当然,如果此时是 250MB,那程序也可以运行:



此时的资源使用量为(256/1024) * (3400/1000) = 0.85GBs


对比上一次,程序执行时间增加了 0.2S,但是资源使用量降低了将近 6 倍!


产品单价是:



虽然 GBs 的单价很低,但是业务量上来之后,这个数字也是要值得注意的。刚才的只是一个单次请求,如果每天有 1000 单次请求,那费用就会出现差距(仅计算资源使用量费用,而不计算调用次数/外网流量):


1536MB: 4.810000.00011108 = 0.5 元


256MB:0.8510000.00011108 = 0.09442 元


如果不是 1000 次调用,而是 10 万次调用,则就是 50 元和 9 元的区别,随着流量越大,差距越大。


当然,多数情况函数执行时间不会这么久,以下面函数为例:



计费时间均是 100ms,每日调用量在 6000 次左右:



如果按照 64M 内存来计算,单资源费用只要 76 元一年,而如果内存都设置为 1536,则一年要 1824 元!这个费用相当于:



所以,超时时间需要对代码和业务场景进行评估来进行设置,可能关系到程序运行的稳定和功能的完整性;内存则不仅仅在程序使用层面有着不同的需求,在费用成本等方面也占有极大的比重,所以内存设置需要对程序进行一个评估。那么问题来了,内存设置多大比较划算?同样是之前的代码,在本地进行简单的脚本编写:


from tencentcloud.common import credentialfrom tencentcloud.common.profile.client_profile import ClientProfilefrom tencentcloud.common.profile.http_profile import HttpProfilefrom tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKExceptionfrom tencentcloud.scf.v20180416 import scf_client, models
import jsonimport numpyimport matplotlib.pyplot as plt
try: cred = credential.Credential("", "") httpProfile = HttpProfile() httpProfile.endpoint = "scf.tencentcloudapi.com"
clientProfile = ClientProfile() clientProfile.httpProfile = httpProfile client = scf_client.ScfClient(cred, "ap-shanghai", clientProfile)
req = models.InvokeRequest() params = '{"FunctionName":"hello_world_2"}' req.from_json_string(params)
billTimeList = [] timeList = [] for i in range(1, 50): print("times: ", i) resp = json.loads(client.Invoke(req).to_json_string()) billTimeList.append(resp['Result']['BillDuration']) timeList.append(resp['Result']['Duration'])
print("计费最大时间", int(max(billTimeList))) print("计费最小时间", int(min(billTimeList))) print("计费平均时间", int(numpy.mean(billTimeList)))
print("运行最大时间", int(max(timeList))) print("运行最小时间", int(min(timeList))) print("运行平均时间", int(numpy.mean(timeList)))
plt.figure() plt.subplot(4, 1, 1) x_data = range(0, len(billTimeList)) plt.plot(x_data, billTimeList) plt.subplot(4, 1, 2) plt.hist(billTimeList, bins=20) plt.subplot(4, 1, 3) x_data = range(0, len(timeList)) plt.plot(x_data, timeList) plt.subplot(4, 1, 4) plt.hist(timeList, bins=20) plt.show()
except TencentCloudSDKException as err: print(err)
复制代码


运行之后会输出一个简单的图像:



从上到下分别是不同次数计费时间图、计费时间分布图以及不同次数运行时间图和运行时间分布图。256M 起步,1536M 终止,步长 128M,每个内存大小串行靠用 50 次,统计表:



注:为了让统计结果更加清晰,差异性比较明显,在程序代码中进行了部分无用操作用来增加程序执行时间。正常使用 jieba 的速度基本都是毫秒级的:



通过表统计可以看到在满足程序内存消耗的前提下,内存大小对程序执行时间的影响并不是很大,反而是对计费影响很大。


当然上面是两个重要指标,除此之外还有一个参数需要用户来评估:函数并发量,在项目上线之后,需要对项目可能产生的并发量进行评估,当评估的并发量超过默认的并发量,要及时联系售后同学或者提交工单进行最大并发量数值的提升。


除了上面的简单评估,有兴趣的同学也可以进行多进程/多线程与函数执行时间/内存关系的评估,但是考虑到很多时候云函数的业务都不涉及到多进程/多线程,所以这里不仅行单独测试。

应该如何设置函数的内存与超时时间

上一部分主要说了 Serverless 架构与资源评估:性能与成本探索​。探索之后,就不得不引出一个新的问题:在使用 Serverless 架构时如何来设置运行内存和超时时间呢?


评估方法有很多,我的做法是先将函数上线,选择一个稍大的内存执行一次。



得到上图结果,再函数设置为 128M 或者 256M,超时时间设置成 3S,接着运行一段时间,例如接口每天触发次数大约为 4000+次:



将函数日志写成脚本,重新做统计:


import json, time, numpy, base64import matplotlib.pyplot as pltfrom matplotlib import font_managerfrom tencentcloud.common import credentialfrom tencentcloud.common.profile.client_profile import ClientProfilefrom tencentcloud.common.profile.http_profile import HttpProfilefrom tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKExceptionfrom tencentcloud.scf.v20180416 import scf_client, models
secretId = ""secretKey = ""region = "ap-guangzhou"namespace = "default"functionName = "course"
font = font_manager.FontProperties(fname="./01.ttf")
try: cred = credential.Credential(secretId, secretKey) httpProfile = HttpProfile() httpProfile.endpoint = "scf.tencentcloudapi.com"
clientProfile = ClientProfile() clientProfile.httpProfile = httpProfile client = scf_client.ScfClient(cred, region, clientProfile)
req = models.GetFunctionLogsRequest()
strTimeNow = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(time.time()))) strTimeLast = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(time.time()) - 86400)) params = { "FunctionName": functionName, "Limit": 500, "StartTime": strTimeLast, "EndTime": strTimeNow, "Namespace": namespace } req.from_json_string(json.dumps(params))
resp = client.GetFunctionLogs(req)
durationList = [] memUsageList = []
for eveItem in json.loads(resp.to_json_string())["Data"]: durationList.append(eveItem['Duration']) memUsageList.append(eveItem['MemUsage'] / 1024 / 1024)
durationDict = { "min": min(durationList), # 运行最小时间 "max": max(durationList), # 运行最大时间 "mean": numpy.mean(durationList) # 运行平均时间 } memUsageDict = { "min": min(memUsageList), # 内存最小使用 "max": max(memUsageList), # 内存最大使用 "mean": numpy.mean(memUsageList) # 内存平均使用 }
plt.figure(figsize=(10, 15)) plt.subplot(4, 1, 1) plt.title('运行次数与运行时间图', fontproperties=font) x_data = range(0, len(durationList)) plt.plot(x_data, durationList) plt.subplot(4, 1, 2) plt.title('运行时间直方分布图', fontproperties=font) plt.hist(durationList, bins=20) plt.subplot(4, 1, 3) plt.title('运行次数与内存使用图', fontproperties=font) x_data = range(0, len(memUsageList)) plt.plot(x_data, memUsageList) plt.subplot(4, 1, 4) plt.title('内存使用直方分布图', fontproperties=font) plt.hist(memUsageList, bins=20)
# with open("/tmp/result.png", "rb") as f: # base64_data = base64.b64encode(f.read())
print("-" * 10 + "运行时间相关数据" + "-" * 10) print("运行最小时间:\t", durationDict["min"], "ms") print("运行最大时间:\t", durationDict["max"], "ms") print("运行平均时间:\t", durationDict["mean"], "ms")
print("\n")
print("-" * 10 + "内存使用相关数据" + "-" * 10) print("内存最小使用:\t", memUsageDict["min"], "MB") print("内存最大使用:\t", memUsageDict["max"], "MB") print("内存平均使用:\t", memUsageDict["mean"], "MB")
print("\n")
plt.show(dpi=200)


except TencentCloudSDKException as err: print(err)
复制代码


运行结果:


----------运行时间相关数据----------运行最小时间:   1 ms运行最大时间:   291 ms运行平均时间:   63.45 ms

----------内存使用相关数据----------内存最小使用: 21.20703125 MB内存最大使用: 29.66015625 MB内存平均使用: 24.8478125 MB
复制代码



通过上图可以看出,近 500 次,每次函数的时间消耗和内存使用。时间消耗基本在 1S 以下,所以此处超时时间设置成 1S 是合理的,而内存使用基本是 64M 以下,所以此时内存设置成 64M 就可以。当然,通过这个图可以看出云函数在执行时可能会有一定的波动,所以无论是内存使用还是超时时间,都可能会出现一定的波动,可以根据自身的业务需求来做一些舍弃,将资源使用量压到最低,节约成本。

总结

综上所述,Serverless 架构也是需要资源评估的,而且资源评估同样是和成本直接挂钩的,只不过这个资源评估的对象逐渐发生了变化,相对之前的评估维度、难度而言,都是大幅度缩小或者降低的。


上线函数之前,进行资源评估的做法基本是分为两步走:


  • 简单运行两次,评估一下基础资源使用量,然后设置一个稍微偏高的值;

  • 函数运行一段时间,得到一定的样本值,在进行数据可视化和基本的数据分析,得到一个相对稳定权威的数据;


2020-08-09 22:052085

评论

发布
暂无评论
发现更多内容

基于虚拟仿真技术的汽车燃油泵控制

DevOps和数字孪生

数字孪生 虚拟仿真 汽车行业

协同创新、奔赴未来——“华为云杯”2023人工智能创新应用大赛华丽谢幕

科技热闻

斯坦福发布 最新 GPT 模型排行榜 AlpacaEval【AI工具免费使用】

袁袁袁袁满

大模型 GPT AI绘画 ChatGPT

Javascript抓取京东、淘宝商品数据

Noah

Zbrush 2023(数字雕刻和绘画程序)激活版mac/win

iMac小白

ZBrush破解版 ZBrush2023 ZBrush下载

乡村体育赛事火爆出圈原因,赛事直播源码搭建观赛平台如何成为带动产业发展

软件开发-梦幻运营部

开发者故事 | 我和openGemini有个约会

华为云开源

时序数据库 开源社区 开发者故事

半导体即国家,日本做了啥?最大的 AI 模型并不十分透明;特斯拉安全数据报告缺失近一年丨 RTE 开发者日报 Vol.70

声网

集结AI创新力量,“华为云杯”2023人工智能应用创新大赛圆满落幕

科技热闻

国内仅有的两个“代码生成型”低代码平台之对比

编程之成住坏空

低代码 无代码 代码生成 代码自动生成 代码生成器

7款最佳免费需求管理工具详细对比

爱吃小舅的鱼

需求管理 需求管理工具

使用 Jenkins 与 KubeVela 实现应用的持续交付

高端章鱼哥

JavaScript node.js API

突破放量困境:百度营销放量神器的高级应用指南!

Geek_2d6073

泛微全新低代码平台e-builder发布,让应用构建更智能、协同、全程数字化

Geek_2d6073

IBM SPSS Statistics 26 (spss统计软件)中文特别版mac/win

iMac小白

IBM SPSS Statistics中文 IBM SPSS Statistics 26 spss统计软件

软件研发降本增效:寻求高效研发团队还是选择软件外包?

SoFlu软件机器人

软件开发 软件定制

语音识别技术在医疗领域的应用与前景

来自四九城儿

数字孪生:助力机载软件构型管理

DevOps和数字孪生

数字孪生 机载软件

PHP-FFMpeg 操作音视频

极客飞兔

php 音视频 ffmpeg 经验总结

谈国产替代---从新出发

统信软件

操作系统 国产化替代

我用低代码平台,简单搭建了一套管理系统

互联网工科生

低代码 低代码平台

选择低代码开发的理由

树上有只程序猿

软件开发 低代码 传统开发

复杂业务逻辑的判断与优化

ZA技术社区

大数据 科技 保险科技 众安保险 ZA技术社区

红楼梦人物关系图怎么画?超详细的人物关系图绘制教程来了。

彭宏豪95

阅读 在线白板 办公软件 绘图软件 绘图工具

Nxyz是怎么样的一个搜索平台?

币离海

区块链 Web3.0 nxyz

“火焰杯”软件测试赛,河南工业大学人工智能与大数据学院获奖

测试人

Serverless架构下还需要评估函数资源吗?_服务革新_刘宇_InfoQ精选文章