使用 initializer 接口解决函数计算上传代码包大小受限问题

本文涉及的产品
简介:

背景

未引入初始化函数功能前如何解决函数计算对上传代码包大小的限制问题?

阿里云 函数计算 为了保证函数计算系统的可用性更高,对用户上传的代码包做了 大小限制,要求原始代码包大小不超过 250MB,压缩后的代码包大小不超过 50MB。由于用户的函数逻辑可能需要大量的依赖库,所以代码包很容易达到函数计算设定的阈值。在未引入 initializer 接口之前,为解决这个问题,需要对代码包进行分类,除项目代码和少量依赖库可以在创建函数时上传,其他依赖库都需要预先上传到 OSS 中,当函数被触发时,再从 OSS 上下载并存放到磁盘指定目录。

解决了函数计算对代码包大小的限制后对用户有什么影响?

用户将部分依赖库预先上传到 OSS,并在函数被触发执行时开始从 OSS 上加载依赖, 这类依赖的加载操作均可定义应用层冷启动,当加载依赖结束后,应用层冷启动才结束,函数的处理逻辑才开始执行,应用层冷启动的开销往往会导致毛刺的产生,影响函数的性能。

如何做到既可以解决函数计算对上传代码包的限制问题,又不影响函数的性能呢?

为同时解决上述功能和性能问题,函数计算推出 initializer 功能。您可以将从 OSS 加载代码包的函数逻辑放在 initializer 函数中。函数计算保证在处理函数执行之前,initializer 函数成功执行过一次并且只有一次,从而可以保证在处理请求到达之前代码已全部加载完成,并且不会对处理函数逻辑的功能和性能产生影响。

案例实践

大部分场景中,用户代码包过大都是由于所依赖的库过大导致的,下文通过 python2.7 演示一个对图片旋转的案例。

图片旋转需要用到 tensorflow 和 opencv 库,两个库的大小还不及函数计算设置上传代码包大小的阈值,这里我们可假设已经超过了代码包大小的限制。

上传依赖库

本案例需要安装的依赖库有 tensorflow 和 opencv-python,需要提前在本地下载并打包上传到 OSS。推荐使用 fcli 工具的 sbox 命令,下面以 runtime 为 python2.7 进行操作:

cd <'此项目的根目录中'>
mkdir applib      // 创建存储所有应用依赖的目录
fcli shell        // fcli version >= 0.25
sbox -d applib -t python2.7
pip install -t $(pwd) tensorflow==1.8.0
pip install -t $(pwd) opencv-python

完成之后 exit 退出沙盒环境,并执行 exit 退出fcli。

编写函数

编写函数需要注意以下几点:

  • 定义 initializer 入口并实现其接口,将从 OSS 加载代码包的逻辑放入初始化函数中。
  • 由于对图片操作所用到的两个库需要在初始化函数中临时加载,所以可以把对函数处理的操作单独放到一个文件中,在处理函数中调用即可。
    综合上面两点考虑,我们的代码结构如下:
project root
└─ code
        ├─ loader.py     # 处理函数逻辑和 initializer 逻辑
        └─ index.py      # 图片旋转逻辑
        └─ pic
                 └─ e2.jpg  # 被操作图片

loader.py 代码如下:

# -*- coding:utf-8 -*-
import sys
import zipfile
import os
import oss2
import imp
import time

app_lib_object = os.environ['AppLibObject']
app_lib_dir = os.environ['AppLibDir']
model_object = os.environ['ModelObject']
model_dir = os.environ['ModelDir']

local = bool(os.getenv('local', ""))
print 'local running: ' + str(local)

def download_and_unzip(objectKey, path, context):
    creds = context.credentials
    if (local):
        print 'thank you for running function in local!!!!!'
        auth = oss2.Auth(creds.access_key_id,
                         creds.access_key_secret)
    else:
        auth = oss2.StsAuth(creds.access_key_id,
                            creds.access_key_secret,
                            creds.security_token)

    endpoint = os.environ['Endpoint']
    bucket = os.environ['Bucket']

    print 'objectKey: ' + objectKey
    print 'path: ' + path
    print 'endpoint: ' + endpoint
    print 'bucket: ' + bucket

    bucket = oss2.Bucket(auth, endpoint, bucket)

    zipName = '/tmp/tmp.zip'

    print 'before downloading ' + objectKey + ' ...'
    start_download_time = time.time()
    bucket.get_object_to_file(objectKey, zipName)
    print 'after downloading, used %s seconds...' % (time.time() - start_download_time)

    if not os.path.exists(path):
        os.mkdir(path)

    print 'before unzipping ' + objectKey + ' ...'
    start_unzip_time = time.time()
    with zipfile.ZipFile(zipName, "r") as z:
        z.extractall(path)
    print 'unzipping done, used %s seconds...' % (time.time() - start_unzip_time)

def initializer(context):
    if not local:
        download_and_unzip(app_lib_object, app_lib_dir, context)
        download_and_unzip(model_object, model_dir, context)
    sys.path.insert(1, app_lib_dir)

def handler(event, context):
    desc = None
    fn, modulePath, desc = imp.find_module('index')
    mod = imp.load_module('index', fn, modulePath, desc)
    request_handler = getattr(mod, 'handler')
    return request_handler(event, context)

index.py 代码如下:

# -*- coding:utf-8 -*-

import cv2
import oss2
import tensorflow as tf

def handler(event, context):
    filename="pic/e2.jpg"
    image = cv2.imread(filename, 1)
    x = tf.Variable(image, name='x')
    model = tf.initialize_all_variables()
    with tf.Session() as session:
        x = tf.transpose(x, perm=[1, 0, 2])
        session.run(model)
        result = session.run(x)

    cv2.imwrite("/tmp/pic.jpg", result)
    cv2.waitKey (0)
    auth = oss2.Auth(<'Your access_key_id'>, <'Your access_key_secret'>)
    bucket = oss2.Bucket(auth, <'Your endpoint'>, <'Your bucket'>)
    bucket.put_object_from_file('picture', '/tmp/pic.jpg')
    return 'success'

pic/e2.jpg 如下:
image.png

部署

你可以通过 SDKAPIfun控制台 等多种方式进行部署,这里直接通过控制台上传代码包。

  • 首先选择一个 region 并创建一个函数。
  • 在新建函数的代码配置中选择文件夹上传,点击你的项目目录全部上传即可。
    image.png
  • 在环境配置中配置初始化函数,将函数入口和 initializer 入口分别设置为 loader.handlerloader.initializer,并配置合理的处理函数超时时间和初始化超时时间,配置结束后点击下一步即可。
    image.png

测试

功能测试

  • 在函数计算控制台执行函数,发现当引入 initializer 功能后,首次执行时间为 3205ms:
    image.png
  • 为验证函数是否执行成功,我们到 OSS 控制台查看指定 bucket 下面是否存在名为 picture 的 object,并验证是否旋转成功,图片如下,由此可见函数执行成功。
    image.png

性能测试

为验证 initializer 函数不仅可以解决上传代码包大小受限的问题,且可以规避加载代码包的冷启动时间,下面将对函数进行改造,关闭初始化功能。

  • 在函数概览页面中点击修改函数,并关闭 开启初始化功能 按钮:
    image.png
  • 将 initializer 函数中的逻辑放到到处理函数中,并删除原有初始化函数,点击执行查看运行结果:
    image.png
  • 函数产生日志如下:
    image.png

从上图中可以发现,在未引入 initializer 函数之前,首次函数函数执行时间约为 14159ms,从 OSS 加载过大的代码包会占用大量的冷启动时间,并且影响函数的性能。

总结

从测试的结果可以发现,initializer 接口的引入解决了文章开篇提到的问题。即解决函数计算对上传代码包的限制问题,又规避了加载代码包的冷启动时间,极大的提升函数性能。

最后欢迎大家通过扫码加入我们用户群中,使用过程中有问题或者有其他问题可以在群里提出来。函数计算官网客户群(11721331)。

相关实践学习
基于函数计算一键部署掌上游戏机
本场景介绍如何使用阿里云计算服务命令快速搭建一个掌上游戏机。
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
目录
相关文章
|
15天前
|
运维 监控 Serverless
Serverless 应用引擎产品使用之在阿里函数计算中,在response.send()之后继续执行其它代码如何解决
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
162 0
|
15天前
|
运维 Serverless API
Serverless 应用引擎产品使用之在阿里函数计算中开启函数计算 API 接口如何解决
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
112 6
|
15天前
|
弹性计算 JSON 运维
Serverless 应用引擎产品使用之阿里云serverless的s deploy,本地的代码编译后的镜像无法推送上去如何解决
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
30 0
|
16天前
|
运维 监控 Serverless
【专栏】无服务器架构,一种云计算模型,让开发者专注编写代码而不必管理服务器(Serverless)
【4月更文挑战第28天】无服务器架构,一种云计算模型,让开发者专注编写代码而不必管理服务器。它基于事件驱动,自动扩展资源并按需计费。优势包括缩短开发周期、优化资源利用、降低成本、提高可用性及简化维护。然而,冷启动延迟、调试困难、性能监控、安全性和学习曲线等挑战仍需解决。随着技术进步,无服务器架构将在科技发展中发挥更大作用。
|
16天前
|
前端开发 Serverless Shell
Serverless 应用引擎操作报错合集之在阿里云函数计算中,laravel zip包使用示例的start.sh脚本启动时出现错误代码如何解决
Serverless 应用引擎(SAE)是阿里云提供的Serverless PaaS平台,支持Spring Cloud、Dubbo、HSF等主流微服务框架,简化应用的部署、运维和弹性伸缩。在使用SAE过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
26 3
|
17天前
|
弹性计算 Serverless 应用服务中间件
Serverless 应用引擎操作报错合集之阿里函数计算中{"ErrorCode":"AccessDenied","ErrorMessage":"Current user is in debt."}出现这个代码如何解决
Serverless 应用引擎(SAE)是阿里云提供的Serverless PaaS平台,支持Spring Cloud、Dubbo、HSF等主流微服务框架,简化应用的部署、运维和弹性伸缩。在使用SAE过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
28 1
|
2月前
|
Java Serverless 测试技术
Serverless 应用引擎常见问题之上传自定义jar包自动vpc启动报错如何解决
Serverless 应用引擎(Serverless Application Engine, SAE)是一种完全托管的应用平台,它允许开发者无需管理服务器即可构建和部署应用。以下是Serverless 应用引擎使用过程中的一些常见问题及其答案的汇总:
35 4
|
2月前
|
监控 Serverless 对象存储
Serverless 应用引擎常见问题之代码和普通版本不一样如何解决
Serverless 应用引擎(Serverless Application Engine, SAE)是一种完全托管的应用平台,它允许开发者无需管理服务器即可构建和部署应用。以下是Serverless 应用引擎使用过程中的一些常见问题及其答案的汇总:
26 1
|
15天前
|
运维 Serverless 应用服务中间件
Serverless 应用引擎产品使用之在阿里云Serverless中函数计算FC nginx 部署上去之后放置静态页面如何解决
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
221 0
|
15天前
|
弹性计算 运维 Serverless
Serverless 应用引擎产品使用之在阿里函数计算中,使数据库和阿里云函数计算位于同一个内网中如何解决
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
989 0
Serverless 应用引擎产品使用之在阿里函数计算中,使数据库和阿里云函数计算位于同一个内网中如何解决

热门文章

最新文章

相关产品

  • 函数计算