函数计算|如何使用层解决依赖包问题?

2022-12-30 0 738

原副标题:表达式排序|怎样采用层化解倚赖包难题?

概要: 在采用阿里云表达式排序网络平台时,假如您曾碰到过下列难题,责任编辑假如会对您略有协助: 服务器端倚赖包太大,每天预览标识符都十分费时,即使会再次出现少于标识符包管制的情形,我该咋办? 加装服务器端倚赖TNUMBERZG,能在邻近地区运转获得成功,上传至阿里云表达式排序网络平台上就会收起,这是甚么情形? 有许多常见的倚赖包,许多使用者假如单厢加进,阿里云表达式排序非官方无法间接内建到运转时自然环境中么? 我在数个表达式完全相同的倚赖包,我该怎样管理工作那些完全相同的倚赖包?

在采用阿里云表达式排序网络平台时,假如您曾碰到过下列难题,责任编辑假如会对您略有协助:

服务器端倚赖包太大,每天预览标识符都十分费时,即使会再次出现少于代码包管制的情形,我该咋办? 加装服务器端倚赖TNUMBERZG,能在邻近地区运转获得成功,上传至阿里云表达式排序网络平台上就会收起,这是甚么情形? 有许多常见的倚赖包,许多使用者假如单厢加进,阿里云表达式排序非官方不能间接内建到运转时自然环境中么? 我在数个表达式完全相同的倚赖包,我该怎样管理工作那些完全相同的倚赖包?

层 提供更多了INS13ZD,跨数个机能且能够共享资源标识符和统计数据的方法。

2021 年 1 月,阿里云表达式排序正式发布了 “自订层”机能,让使用者能自订层,并全力支持跨表达式共享资源。2022 年 8 月,阿里云表达式排序正式发布“公用层”机能,提供更多了非官方公用层,供使用者间接采用,进一步提高了使用者新体验。

接下去他们先如是说下 “自订层” 的机能和作用。

自订层

在层机能正式发布以后,必须将标识符与标识符的倚赖项一同装箱和布署,那些倚赖项在相同表达式中可能是完全相同的,许多情形下那些倚赖项的大小不一,相比之下小于标识符的大小不一。

但是在层机能正式发布后,他们能将标识符的倚赖项,或是数个表达式中共享资源的部分装箱成 Zip 剪贴板,并作为表达式排序的自订层正式发布,相同表达式都能采用该自订层。

阿里云表达式排序会在初始化时将层与表达式标识符一同读取。可参照variations文件格式:建立自订层[1]、在表达式中实用性自订层[2]

为甚么采用自订层?

采用自订层有下列竞争优势:

(1)跨表达式F83E43Se标识符

将数个表达式中的通用型标识符或统计数据抽取出来,装箱成 Zip 包,弄成自订层,供相同表达式引用,避免了在数个地方维护通用型的标识符或统计数据。

与此同时,也实现了倚赖项和业务逻辑的分离,使用者能专注于核心的业务逻辑。

(2)使标识符包更小

表达式的标识符包越来越大时,布署速度也会越来越慢,导致表达式的维护和测试愈加困难。

此外表达式标识符包大小不一也有管制,比如阿里云表达式排序的标识符包管制为 500MB (2022 年 9 月),层是突破该管制的方法之一。层也有大小不一管制,目前单个层的标识符包大小不一管制为 500MB,单个表达式最多可实用性 5 个层,总大小不一无法少于 2GB。

(3)加速标识符布署,简化表达式管理工作

表达式标识符包越小,标识符包的布署就越快。尤其是一些大型倚赖项时,核心机能标识符可能只有几兆字节,但倚赖项可能有几百兆。比如 Puppeteer 倚赖包少于 100MB,阿里云的 DataX 倚赖包少于 800MB。

一般来讲,那些倚赖项很少修改,因此将他们装箱成层后,能避免在核心标识符修改时频繁修改那些大型倚赖项。对那些倚赖项也能拆分成数个层,每天修改一个机能时,只需要预览其中一个层。

比如他们实现了自订运转时 Python3.10 以及该运转时兼容的科学排序库 SciPy,能将自订运转时和倚赖包拆成两个层,当需要预览倚赖包时,只需要预览依赖包的层,而自订运转时的层保持不变。

自订层的困境

(1)制作层有一定门槛

层的 Zip 包有一定的格式规范,使用者需要按照该规范进行制作。以 Python 的 requests 库为例,倚赖装箱后的文件结构为:

my-layer-code.zip

└── python

└── requests

为甚么有这种要求呢?这个涉及到相同运转时在搜索服务器端倚赖包的实现逻辑,以 Python 为例,Python 运转时会在 sys.path 路径下搜索倚赖包,上面的 Zip 包会解压到表达式实例的 /opt 目录下,解压后 requests 这个包就放到了 /opt/python 目录下。

然后,表达式排序网络平台会将一些特定的目录放到运转时语言的倚赖搜索路径上,比如 Python 运转时就会将 /opt/python 放到 sys.path 中,这样,标识符中就能间接引用 requests 库了。其他运转时的采用方法可参照variations文件格式-建立自订层。当然,你也能不按照这个格式规范来制作层,此时就需要在标识符中添加对应的搜索路径了,具体方法可参照variations文件格式-怎样在 Custom Runtime 中引用层中的倚赖?[3]

需要在指定操作系统和处理器架构下制作层。有一些倚赖是与操作系统和处理器架构有倚赖关系的,比如 Python 的科学排序库 NumPy,假如你在 M1 芯片的 MacOS 下加装,其版本为:

numpy-1.23.3-cp39-cp39-macosx_11_0_arm64

可看到兼容的操作系统为 mac os, 处理器架构为 arm64。但在表达式排序网络平台的实例自然环境为 Linux x86_64,操作系统目前使用的发行版为 Debian 9,因此在 M1 Mac 下加装的 NumPy 库无法在阿里云表达式排序网络平台采用。他们推荐在 Debian 9 系统下进行加装,但使用者邻近地区可能没有该自然环境,您能采用在线构建依赖库或是采用表达式排序非官方运转时镜像来构建,此处不再赘述。

层需要包含新增的共享资源动态库。有些倚赖库需要加装额外的共享资源动态库,在构建层的 Zip 包时也需要包含那些共享资源动态库。例如 Nodejs 的倚赖库 Puppeteer,需要额外加装二十数个共享资源动态库(如 libxss1,libnspr4 等),那些倚赖库都要装箱到层 Zip 包中。怎样获得成功的加装 Puppeteer 库并不是简单的事情。共享资源动态库推荐放到 Zip 包的 lib 目录下,表达式排序网络平台会将/opt/lib 目录添加到 LD_LIBRARY_PATH(仅限于内建运转时)。

(2)无法跨账号共享资源

自订层默认只能在同账号同地域的相同表达式之间共享资源,无法进行跨账号共享资源。因此,使用者 A 建立的自订层无法给使用者 B 采用,这不仅给使用者带来了重复的工作量,也不利于宿主机上完全相同层的F83E43Se。

公用层

由于自订层的那些痛点,阿里云表达式排序在 2022 年 8 月正式发布了公用层机能。实现层跨账号共享资源,并提供更多了一些非官方公用层[6]供使用者间接采用,方便使用者快速开发示例原型。阿里云表达式排序网络平台主要提供更多了三类非官方公用层:

自订运转时(如 Python 3.10、Nodejs17、PHP 8.1、Java17、.NET 6 等) 常见倚赖库(如 PyTorch、Scipy、Puppeteer 等) 阿里云 SDK(如 Aliyun DataX )

详情可参照variations非官方文件格式-在表达式中实用性非官方公用层[4],目前非官方公用层仍在持续补充,假如您有需要的运转时或是倚赖库想通过非官方公用层的方式采用,可通过钉钉答疑群(钉钉群号:11721331)与他们联系,也能间接在 Github[5]上提交 issue。

怎样公开自订层?

目前,层公开机能在内测中,如有需求能通过钉钉联系他们。同时,他们也十分欢迎大家贡献公用层到仓库,他们很快会在该仓库提供更多公用层贡献的方法和示例。

示例

非官方公用层的最新版本和采用说明可参照 Github,下面他们如是说一些采用非官方公用层的典型示例。

示例一、基于 Nodejs16 + Puppeteer 实现网页截图示例程序

Puppeteer 是一个 Nodejs 库,它提供更多了高级的 API 并通过 DevTools 协议来控制 Chrome(或 Chromium)。通俗来说就是一个 headless chrome 浏览器,能使用它完成许多自动化的事情,比如:

生成网页截图或是 PDF 做表单的自动提交、UI 的自动化测试、模拟键盘输入等 more…

本示例采用 Puppeteer 完成一个网页截图示例程序。

首先,他们采用内建运转时 Nodejs16 建立一个表达式 start-puppeteer,其中请求处理程序类型选择“处理 HTTP 请求”。

然后,在高级实用性中将内存规格设置为 1GB,示例程序的内存使用大概在550MB左右。

建立获得成功后,在控制台上打开 index.js文件,将下面的标识符拷贝并覆盖该文件,点击布署按钮。

const fs = require(fs);

const puppeteer = require(puppeteer);

function autoScroll(page) {

return page.evaluate(() => {

return new Promise((resolve, reject) => {

var totalHeight = 0;

var distance = 100;

var timer = setInterval(() => {

var scrollHeight = document.body.scrollHeight;

window.scrollBy(0, distance);

totalHeight += distance;

if (totalHeight >= scrollHeight) {

clearInterval(timer);

resolve();

}

}, 100);

})

});

}

module.exports.handler = function (request, response, context) {

console.log(Node version is: + process.version);

(async () => {

const browser = await puppeteer.launch({

headless: true,

args: [

–disable-gpu,

–disable-dev-shm-usage,

–disable-setuid-sandbox,

–no-first-run,

–no-zygote,

–no-sandbox

]

});

let url = request.queries[url];

if (!url) {

url = https://www.serverless-devs.com;

}

if (!url.startsWith(https://) && !url.startsWith(http://)) {

url = http:// + url;

}

const page = await browser.newPage();

await page.emulateTimezone(Asia/Shanghai);

await page.goto(url, {

waitUntil: networkidle2

});

await page.setViewport({

width: 1200,

height: 800

});

await autoScroll(page)

let path = /tmp/example;

let contentType = image/png;

await page.screenshot({ path: path, fullPage: true, type: png });

await browser.close();

response.setStatusCode(200);

response.setHeader(content-type, contentType);

response.send(fs.readFileSync(path))

})().catch(err => {

response.setStatusCode(500);

response.setHeader(content-type, text/plain);

response.send(err.message);

});

};

简要如是说一下上述到运转实例的 /tmp/example文件中,然后将该文件作为HTTP请求的返回体间接返回。

然后,他们需要实用性 Puppeteer 公用层,在表达式实用性中找到层,点击编辑,选择添加非官方公用层。

选择非官方公共层 Puppeteer17x,目前最新的层版本为1。

函数计算|如何使用层解决依赖包问题?

参照非官方公用层 Nodejs-Puppeteer17x README 添加自然环境变量,对于版本1,需要添加 LD_LIBRARY_PATH=/opt/lib/x86_64-linux-gnu:/opt/lib自然环境变量。

函数计算|如何使用层解决依赖包问题?

最后,采用触发器管理工作中的测试地址进行测试验证。

函数计算|如何使用层解决依赖包问题?

测试结果如下所示,已获得成功将 Serverless Devs 非官方进行截图。

函数计算|如何使用层解决依赖包问题?

示例二、基于公用层快速实现 .NET 6 自订运转时

首先,通过控制台建立 .NET 6 自订运转时。在最上层选择 “采用自订运转时建立”,选择“处理 HTTP 请求”,选择 .NET 6运转时,其他实用性使用默认值。

函数计算|如何使用层解决依赖包问题?

建立获得成功后,能通过 WebIDE 看到示例标识符 Program.cs

函数计算|如何使用层解决依赖包问题?

示例标识符中需要注意四个部分:

该示例监听了0.0.0.0的9000端口,Custom Runtime启动的服务一定要监听0.0.0.0:CAPort或*:CAPort端口,无法监听127.0.0.1或 localhost。详情参照文件格式 Custom Runtime>基本原理。 添加路由 /,间接返回字符串 “Hello World!” 添加路由/invoke,该路由为采用事件请求处理程序的路径,可参照文件格式 Custom Runtime >事件请求处理程序(Event Handler) 添加路由 /initialize,该路由为表达式初始化回调程序对应的路径,该方法会在示例初始化时执行一次,可参照文件格式 Custom Runtime >表达式实例生命周期回调

首先,他们间接采用触发器管理工作页面中的测试地址进行测试,此时不添加任何 PATH 信息,结果如下图所示:

然后,他们测试添加 /invoke路径进行测试,因为该路由方法为 POST,他们间接采用 curl -XPOST测试:

同样,他们用这种方法测试一下/initialize

注意:此处只是做测试,初始化回调表达式不需要主动初始化,表达式排序网络平台会在实例启动后自动初始化该回调方法(不要忘记在实用性里启用 initializer 回调程序)

最后,他们再做一个小测试,在触发器管理工作页面将HTTP触发器删除,删除后该表达式类型会转换成事件请求处理程序,在表达式实用性中,将 Initializer 回调程序启用

在控制台上测试该表达式,结果如下图所示:

点击实时日志按钮,能看到在该请求执行前,已经执行了 Initialize 回调方法。

层的最佳实践是甚么?

前文如是说了甚么是自订层,为甚么采用自订层,甚么是公用层,并如是说了两个非官方公用层的示例。但他们对层的采用仍然还有一些疑惑,比如甚么场景下推荐采用层?层与标识符包有甚么区别?有没有与层相似的机能?与那些相似机能相比,层的优缺点是甚么?接下去尝试回答一下那些难题。

甚么场景下推荐采用层?

目前,采用层的场景主要有两类,一类是自订运转时,另一类是各种语言的倚赖库。强烈推荐通过层来构建并采用自订运转时,但对于各类语言的倚赖库,能参照下面那些建议:

推荐优先采用非官方公用层 非编译型语言的倚赖库推荐采用层来管理工作,对编译行语言需要根据实际情形进行判断(比如,对自订运转时,假如采用JAR包的方式运转 Java 程序,则无法引入层中的倚赖,可参照文件格式 怎样在Custom Runtime中引用层中的倚赖?) 假如倚赖库较大,并且没有少于层的管制大小不一,推荐采用层 假如倚赖库需要额外加装共享资源动态库,推荐采用层(假如构建比较复杂,可联系表达式排序团队制作) 假如在数个表达式、数个账号之间有共享资源代码或统计数据的需求,推荐采用层

层与标识符包有甚么区别?

直观上看,层就是把原来标识符包的一部分内容拆分出来,再重新建一个标识符包而已,那为甚么又建立一个层的概念呢?这里的主要区别是层与标识符包的设计理念相同。

层有更简洁的版本管理工作方案

层的版本是从 1 开始自动递增的,目前一个层最大全力支持 100 个可用版本(不包括已删除的版本);而对标识符包来讲没有版本的概念,只有在服务层面上有版本概念,相对层的版本会更加复杂。

-层版本是只读的,不可变的

一个层的版本在建立后内容是无法改变的(权限除外),假如想修改层的内容,只能正式发布一个新的版本。层版本的只读特性能够避免了层的改动对表达式的影响。

层的共享资源能力

层能跨表达式、跨账号进行共享,而标识符包不全力支持。

层版本的软删除策略

层版本删除后,不会影响已经实用性改层版本的表达式的正常运转。因为在层版本删除是,阿里云表达式排序网络平台并不会间接将层版本的标识符删掉,而是先进行一次软删除操作,避免新的表达式采用已删除的层版本,当该层版本没有表达式引用时,才会彻底删除该层版本。

表达式排序没有与层相似的机能?与相似机能相比,层的优缺点是甚么?

在阿里云表达式排序网络平台中,与层类似的机能是服务实用性中的“挂载NAS文件系统”和“挂载 OSS 对象存储”机能,层与挂载NAS/OSS在机能和应用场景上有一些明显的差异:

简单总结一下,假如标识符或统计数据的大小不一少于层的管制,则推荐采用挂载 NAS/OSS 的方式;假如标识符或数据会镜像改动,或是有运转时修改统计数据的需求,那么这里也推荐采用挂载 NAS/OSS 的方式。

结语

在阿里云表达式排序中,层的定位是一种不可变的基础设施,通过层版本的只读特性保证层的一致性和可靠性。责任编辑首先介绍了自订层的特点和困境,然后如是说了近期正式发布的公用层机能,详细陈述了基于非官方公用层实现的两个示例程序,最后探讨了层的最佳实践是甚么,希望通过责任编辑能让读者更好的理解层的概念及其应用场景。

层的机能仍在持续完善中,接下去他们会在一下几个方向进行重点优化:

完善非官方公用层新体验,补充更多的常见倚赖库或自订运转时作为非官方公用层,并提供更多完善的应用示例。 提供更多公用层贡献的方法和示例,促进公用层的开源共建。

假如对层的采用有任何的疑惑或是建议,欢迎搜索(群号:11721331)进入阿里云表达式排序钉钉群联系他们。

更多内容关注 Serverless 微信公众号(ID:serverlessdevs),汇集 Serverless 技术最全内容,定期举办 Serverless 活动、直播,使用者最佳实践。

More:

建立自订层 :

https://help.aliyun.com/document_detail/193057.html

在表达式中实用性自订层:

https://help.aliyun.com/document_detail/193058.html

怎样在Custom Runtime中引用层中的倚赖?

https://help.aliyun.com/document_detail/71142.htm?spm=a2c4g.11186623.0.0.2c77481ftZBbfb#task-1881232

在表达式中实用性非官方公用层

https://help.aliyun.com/document_detail/451191.html

阿里云表达式排序 公用层github:

github.com/awesome-fc/awesome-layers

非官方公用层

Nodejs-Puppeteer17x README

Custom Runtime 基本原理

https://help.aliyun.com/document_detail/425055.html#section-ffl-tm3-txg

Custom Runtime 事件请求处理程序

https://help.aliyun.com/document_detail/191342.html

Custom Runtime 表达式实例生命周期回调

https://help.aliyun.com/document_detail/425056.html

原文链接:https://click.aliyun.com/m/1000362244/

责任编辑为阿里云原创内容,未经允许不得转载。

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务