V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
scf10cent
V2EX  ›  推广

Serverless 的资源评估与成本探索

  •  
  •   scf10cent · 2020-02-13 16:20:12 +08:00 · 1817 次点击
    这是一个创建于 1506 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Serverless 布道师在讲解 Serverless 架构和云主机等区别的时候,总会有类似的描述:

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

    但是在实际生产中,Serverless 真的无需评估资源么?还是说在 Serverless 架构下,资源评估的内容、对象发生了变化,或者简化呢?

    腾讯云云函数 中,我们创建一个云函数之后,有这么几个设置项:

    设置项

    内存设置范围为 64~1536M,超时时间范围为 1~900s。这些设置项其实已经涉及到了资源评估。

    超时时间

    先说超时时间,一个项目或者一个函数,一个 Action 都是有执行时间的。如果超过某个时间没执行完,就可以评估其为发生了「意外」,可以被「干掉」了,这个就是超时时间。

    例如一个获取用户信息的简单请求,假设 10s 内没有返回,证明已经不满足业务需求,此时就可以将超时设置为 10s。如果有另一个业务,运行速度比较慢,至少要 50s 才能执行完,那么这个值的设置就要大于 50,否则程序可能因为超时被强行停止。

    内存

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

    关联点 1:

    程序本身需要一定的内存,这个内存要大于程序本身的内存。

    以 Python 语言为例:

    # encoding=utf-8
    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 的时候,内存消耗过大, 默认值 128M 不能满足需求,此时将其修改成最大:

    修改为最大值

    系统提醒时间超时,因此还需要再修改超时时间为适当的数值(此处设定为 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.8 GBs

    当然,250MB 的情况下,程序也可以运行:

    250M

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

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

    尽管 GBs 的单价很低,但是当业务量上来之后,也不能忽略。刚才的只是一个单次请求,如果每天有 1000 此次请求,那:

    • 1536 MB:4.810000.00011108 = 0.5 元
    • 25 MB:0.8510000.00011108 = 0.09442 元

    仅计算资源使用量费用,而不计算调用次数 /外网流量)

    如果是一万次调用,那就是 50 元和 9 元的区别。随着流量越大,差距越大。

    当然很多时候函数执行时间不会这么久,以个人的某函数为例:

    一个例子

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

    详细数据

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

    等效费用

    所以说,「超时时间」的设置需要评估代码和业务场景,它关系到程序运行的稳定性和功能完整性。同时,「内存」也不仅仅影响程序的使用层面,还关乎费用成本。那么,既然资源评估如此重要,如何评估呢?

    还是以上述代码为例,在本地进行简单的脚本编写:

    from tencentcloud.common import credential
    from tencentcloud.common.profile.client_profile import ClientProfile
    from tencentcloud.common.profile.http_profile import HttpProfile
    from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
    from tencentcloud.scf.v20180416 import scf_client, models
    
    import json
    import numpy
    import 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 中文网,您可以在 最佳实践 里体验更多关于 Serverless 应用的开发!

    15 条回复    2020-04-13 16:10:02 +08:00
    yyfearth
        1
    yyfearth  
       2020-02-13 16:49:19 +08:00
    我觉得这里内存设置不应该直接用来计费 应该和时间一样 要看用量来计费比较合适
    可以给一个最小内存和最大内存的设置会更加合理一些 实际使用内存不小于最小内存 不能大于最大内存

    因为如果是用容器或者轻量 VM 实现 内存应该都是共享的 那么设置一个初始内存 加上一个最大内存限制 应该可以实现
    akira
        2
    akira  
       2020-02-13 17:35:41 +08:00
    综上,Serverless 架构也是需要资源评估的,而且资源评估同样和成本是直接挂钩。只不过这个资源评估的对象逐渐发生了变化,相对之前的评估维度、难度而言,都是大幅度缩小或者降低的。
    ---------------------
    我怎么觉得是反过来,评估难度更大了呢
    whileFalse
        3
    whileFalse  
       2020-02-13 17:53:20 +08:00
    你好。我刚才浏览了一下 serverless.com ,没有找到答案,故来询问。

    我对 AWS Lambda 和 CloudFormation 十分熟悉。我也具有一定的后端 web 开发经验。
    但是我对于传统 Web 开发工程师如何在 Serverless 环境下(并非特指 serverless 框架)进行高效业务开发没有一个明确的方向。我稍微浏览了一下 serverless 框架的简单 example,发现框架本身似乎没有提供类似 flask 或 express 那样强大的功能。那么 serverless 对于我这样的人来说有什么益处呢?(我不需要多平台部署)
    rayhy
        4
    rayhy  
       2020-02-13 18:05:20 +08:00 via Android
    @whileFalse flask 也不是不能用。比如 tencent-flask 这个官方组件。只是传统的框架移植上去总有一些很麻烦的地方,用的不是那么舒服
    whileFalse
        5
    whileFalse  
       2020-02-13 18:28:22 +08:00
    @rayhy #4 嗯,但我希望用相对比较原生的方式。我特别讨厌整个业务都绑定到同一个 fuction 中的这种半半落落的方案。
    gwy15
        6
    gwy15  
       2020-02-13 19:07:51 +08:00
    @whileFalse 我使用的是阿里云 FC,它的 python3 环境是基于 WSGI 接口的,因此可以直接这样用 flask 框架:
    handler = app

    但是对非 ascii 字符有 bug,可以这样进行 workaround:
    https://www.gwy15.com/2019/12/17/%E9%98%BF%E9%87%8C%E4%BA%91%E5%87%BD%E6%95%B0%E8%AE%A1%E7%AE%97%E7%9A%84-bug-%E4%B8%8E-workaround/

    对我来说,面向 serverless (阿里云 FC )环境开发和面向 VPS 环境开发没什么区别,无非就是加个 __import__('sys').path.append('lib') 然后导出第三方库到 lib 文件夹、打包上传。不过目前阿里云 FC 不支持限速、不支持自定义 header (默认全部 host 都做了 CORS,没法白名单黑名单)、不支持方便的自定义域名,还有待改善。
    whileFalse
        7
    whileFalse  
       2020-02-13 22:59:56 +08:00
    @gwy15 #6 用 Flask 冷启动很慢吧。
    scf10cent
        8
    scf10cent  
    OP
       2020-02-14 11:40:29 +08:00
    @yyfearth 这里确实可以这样考虑。但实际上 SCF 目前是有热启动的。如果函数使用频繁,那么很可能就会有很多容器被启动起来。那么这个时候内存设置的多少可能就涉及到多少台上层机器待命。例如说宿主机是 4G 内存,用户设置的是 1G 的配置和设置 128M 的配置,我们在这个宿主机上,同时启动的容器数量应该是不同的,如果因为共享原因,启动相同数量的机器,很可能在并发上来的时候就挂掉了。所以,这个时候让用户配置更合理的内存,是合理的,毕竟直接涉及到占用的资源多少。
    scf10cent
        9
    scf10cent  
    OP
       2020-02-14 11:43:42 +08:00
    @akira 相对来说,我觉得评估难度量是降低了,虽然说,可能每个接口都要评估工作量,但是实际上并不用这样的,例如我近期开发了一个博客系统,前端有 10 个接口,涉及到了 10 个函数,每个函数都是增删改查,没有太复杂的逻辑,所以每个函数我都设置了 64M 的内存。这样就足够了。
    scf10cent
        10
    scf10cent  
    OP
       2020-02-14 11:57:03 +08:00
    @whileFalse 是这样的,Serverless 架构可以认为还是“新的东西”,既然是新的东西那么就会有一定的发展坎坷。首先这对你说的,Serverless 开发貌似没有 Flask 这些框架好用。是的,可能在刚接触的过程中,确实 Flask 这样的框架用顺手了,感觉更爽,更方便,尤其是保持登录态等很多地方,也确实是 Serverless 架构的缺点,这个不得不承认的。
    但是:1 ) Flask 这样的框架,是可以部署到 Serverless 架构上的; 2 ) Serverless 架构也会逐渐的有很多自己框架诞生; 3 )使用 Serverless 架构很多的好处并不是单单说,他比 Flask 框架开发方便多少(其实本身也没复杂多少),而是说你在开发项目过程中关注点是否发生了变化,项目运营过程中,运维工作是否发生转变......
    一个简单的例子,传统的项目上线了,要有人看着你的机器的,如果某一段时间并发突然增多,要有人做扩容,如果流量下来,要有人做缩容,如果有一个机器挂了,要有人把它剔除,修好,再加回。那么在 Serverless 架构下,这些事情,否不需要用户自己考虑,他完全可以把这些工作交给服务上来解决。
    关于开发,传统情况下,我们开发一个 web 服务,或者说,我么就要一个接口,我们要做什么操作?有一个服务器,安装服务器软件,(以 Flask 为例)安装 Python,安装 Flask,开发完成,运行;那么在 Serverless 架构下,我要做一个接口呢?写函数代码,部署上线。如果是简单一些的代码,都可以不用再本地写,可以直接在线上写。
    所以说其实 Serverless 架构下的方便与不方便是相对的。如果你说我在 flask 取传递的参数(例如 post,get 等传递的内容),我保持登录态,有个缓存什么的,这些一定是 flask 方便,但是你要说我从大局来看,其实还是 Serverless 更加方便一些。

    还有,最后最后,要和你说的一件事是:Serverless.com 虽然叫 Serverless Framework 但是实际上他并不是 Serverless 架构,它实际上是多云的 Serverless 开发者工具(至少你暂时可以这样认为),他只是名字叫了 Serverless。就像中国电信和电信一样,可能只是一个名字相同,中国电信是中国电信行业的一个运行商。Serverless Framework 是多云的 Serverless Framework 开发者工具。

    当然既然是做开发者工具,自然就不能太寒酸。Serverless Framework ( serverless.com )目前已经集成了多云,并且对 AWS,Tencent 的函数服务,提供了更加强大的支持,例如部署 Flask 框架,部署 Express,部署 Koa........
    scf10cent
        11
    scf10cent  
    OP
       2020-02-14 11:57:44 +08:00
    @rayhy 是的,总会有一些麻烦的地方,但是这些麻烦的地方也会被逐渐的消灭。
    scf10cent
        12
    scf10cent  
    OP
       2020-02-14 12:00:04 +08:00
    @whileFalse 所有业务绑定在同一个函数中是否有意义,其实这个还要根据跟人需求而定。
    据一个我的个人博客例子,我的博客,前端有 10 个函数,负责常用逻辑的处理,后台使用了一个 Flaks 框架用了 Flask-admin 来做的,就直接一股脑放在了一个函数中,这样前端性能有保证,后台自己用,对性能没太多要求,开发起来反而更加方便。
    scf10cent
        13
    scf10cent  
    OP
       2020-02-14 12:00:56 +08:00
    @whileFalse 是的,Flask 这样的框架,如果一股脑放入函数中,是可能带来启动速度慢的问题,但是各个厂商也都在优化冷启动问题,可能不久的将来,就会基本消灭冷启动。
    whileFalse
        14
    whileFalse  
       2020-02-14 13:34:01 +08:00
    @scf10cent #12
    你提到自用的后端对性能不敏感,是 Flask ;前端是独立的函数。那你前端还是几乎不依赖框架裸写咯?在生产场景下,普通的后端程序员不依赖框架的工作效率是很低的。至于对性能不敏感的管理端,部署在 lambda 中也没有太大意义。

    厂商是在优化冷启动问题,但更多的是用户代码之外的冷启动速度优化。Flask 作为用户代码,几乎没法优化冷启动效率。
    Aceyclee
        15
    Aceyclee  
       2020-04-13 16:10:02 +08:00
    写得好详细
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2871 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 11:38 · PVG 19:38 · LAX 04:38 · JFK 07:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.