开发函数计算的正确姿势 —— 使用 Fun Local 本地运行与调试

本文涉及的产品
函数计算FC,每月15万CU 3个月
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
简介: 前言 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传。函数计算准备计算资源,并以弹性伸缩的方式运行用户代码,而用户只需根据实际代码运行所消耗的资源进行付费。

前言

首先介绍下在本文出现的几个比较重要的概念:

函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传。函数计算准备计算资源,并以弹性伸缩的方式运行用户代码,而用户只需根据实际代码运行所消耗的资源进行付费。函数计算更多信息 参考

Fun: Fun 是一个用于支持 Serverless 应用部署的工具,能帮助您便捷地管理函数计算、API 网关、日志服务等资源。它通过一个资源配置文件(template.yml),协助您进行开发、构建、部署操作。Fun 的更多文档 参考

2.0 版本的 Fun,在部署这一块做了很多努力,并提供了比较完善的功能,能够做到将云资源方便、平滑地部署到云端。但该版本,在本地开发上的体验,还有较多的工作要做。于是,我们决定推出 Fun Local 弥补这一处短板。

Fun Local: Fun Local 作为 Fun 的一个子命令存在,只要 Fun 的版本大于等于 2.6.0,即可以直接通过 fun local 命令使用。Fun Local 工具可以将函数计算中的函数在本地完全模拟运行,并提供单步调试的功能,旨在弥补函数计算相对于传统应用开发体验上的短板,并为用户提供一种解决函数计算问题排查的新途径。

《开发函数计算的正确姿势》系列除本篇是为用户介绍 fun local 的使用方法外,其他几篇都会向用户展示 Fun Local 对于函数计算开发所带来的效率上的巨大提升。

注意:
Fun Local 现已集成到 VSCode、IDEA、Pycharm 等 IDE 的图形化插件中,相较于命令行,这些插件往往通过图形化的方式带来更好的使用体验,因此:

  • 如果您是 VSCode 用户,我们强烈推荐您直接使用 VSCode 插件
  • 如果您是 IDEA 或 Pycharm 用户,我们强烈推荐您直接使用 Cloud Toolkit 插件。

Fun Local 命令格式

使用 fun local invoke -h 可以查看 fun local invoke 的帮助信息:

$ fun local invoke -h
  Usage: invoke [options] <[service/]function>

  Run your serverless application locally for quick development & testing.

  Options:

    -d, --debug-port <port>  used for local debugging
    -c, --config <ide>       print out ide debug configuration. Options are VSCode
    -e, --event <path>       event file containing event data passed to the function
    -h, --help               output usage information

本地运行函数

运行函数的命令格式为:

fun local invoke [options] <[service/]function>

其中 options、service 都是可以省略的。
从调用方式上,可以理解为,fun local invoke 支持通过 函数名 调用,或者 服务名/函数名 的方式调用,即

fun local invoke function
fun local invoke service/function

比如,如果要运行名为 php72 的函数,可以直接通过以下命令完成:

fun local invoke php72

调用结果为:

再比如,要运行名为 nodejs8 的函数,可以使用:

fun local invoke nodejs8

会得到如下结果:

如果 template.yml 中包含多个服务,而多个服务中包含相同名称的函数时,通过函数名的方式调用 fun 只会运行第一个名称匹配的函数

如果想要精准匹配,可以使用 服务名/函数名 的方式。

比如想要调用 localdemo 下的 php72,可以使用:

fun local invoke localdemo/php72

在本例中,会得到和 fun local invoke php72 一致的结果。

以下是一个运行 nodejs8 函数的演示:

本地运行 java 类型的函数

java 不同于解释型的语言,在作为函数运行前,需要先编译。在我们的例子中,可以直接使用 fun build 函数名 的方式,在我们的例子中,函数名为 java8,因此编译命令如下:

fun build java8

可以看到 log:

using template: template.yml
start building function dependencies without docker

building localdemo/java8
running task flow MavenTaskFlow
running task: MavenCompileTask
running task: MavenCopyDependencies
running task: CopyMavenArtifacts

Build Success

Built artifacts: .fun/build/artifacts
Built template: .fun/build/artifacts/template.yml

Tips for next step
======================
* Invoke Event Function: fun local invoke
* Invoke Http Function: fun local start
* Deploy Resources: fun deploy

编译成功后,可以直接使用以下命令运行函数:

fun local invoke java8

运行结果如下:

以下是一个运行 java8 函数的演示:

本地调试

fun local invoke 支持 -d, --debug-port <port> 选项,可以对函数进行本地单步调试。本文档只介绍如何配置调试,并不涉及调试技巧,更多文章,请参考

备注:Fun Local 涉及到的 debugging 技术全部都基于各个语言通用的调试协议实现的,因此无论什么语言的开发者,即使不喜欢用 VSCode,只要使用对应语言的 remote debugging 方法都可以进行调试。

本地调试 nodejs、python 类型的函数

对于 nodejs6、nodejs8、python2.7、python3、java8 类型的函数,调试方法基本一致。下面拿 nodejs8 举例。

我们上面演示了可以通过 fun local invoke nodejs8 来运行名称为 nodejs8 的函数,如果想对该函数进行调试,只需要使用 -d 参数,并配置相应的端口号即可。

比如我们以调试方式运行函数,并将调试端口设定在 3000,可以通过下面的命令:

fun local invoke -d 3000 nodejs8

另外,推荐添加 --config 参数,在调试的同时,可以输出用来调试的 IDE 的配置信息:

fun local invoke -d 3000 --config VSCode nodejs8

命令执行结果如下:

skip pulling images ...
you can paste these config to .vscode/launch.json, and then attach to your running function
///////////////// config begin /////////////////
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "fc/localdemo/nodejs8",
            "type": "node",
            "request": "attach",
            "address": "localhost",
            "port": 3000,
            "localRoot": "/Users/tan/code/fun/examples/local/nodejs8",
            "remoteRoot": "/code",
            "protocol": "inspect",
            "stopOnEntry": false
        }
    ]
}
///////////////// config end /////////////////
Debugger listening on ws://0.0.0.0:3000/b65c288b-bd6a-4791-849b-b03e0d16b0ce
For help see https://nodejs.org/en/docs/inspector

程序会阻塞在这里,并不会继续往下执行。只有 IDE 的连接上来后,程序才会继续执行。接下来,我们针对 VSCode 配置、VSCode 调试两个方面分别进行讲解。

其中 VSCode 配置只有在第一次对函数进行调试时才需要,如果已经配置过,则不需要再次配置。

VSCode 配置

  1. 创建 vscode launch.json 文件
  2. 复制日志中的 config begin 与 config end 之间的配置到 launch.json 中。
  3. 完成上面配置后,在 Debug 视图可以看到配置的函数列表。

至此,VSCode 配置完成。VSCode 更多配置知识可以参考官方文档

VSCode 调试

VSCode 配置成功后,只需要在 VSCode 编辑器侧边栏单击设置断点,然后点击“开始调试”按钮,即可开始调试。

以下是一个 nodejs8 函数本地单步调试的流程例子:

本地调试 java 类型的函数

调试 java 函数的过程和 nodejs、python 是类似的。但由于 java 程序员通常喜欢用 IDEA、Eclipse 这样的 IDE,所以我们单独拿出来说一下。

使用 VSCode 调试 java

使用 VSCode 调试 java 时,需要安装两个插件:Language Support for Java(TM) by Red HatDebugger for Java。利用 VSCode 的插件市场安装插件很简单,可以 参考

以下是一个使用 VSCode 调试 java 类型函数的例子:

使用 IDEA 调试 java

IDEA 配置

IDEA 配置 remote debugging 还是比较简单的,首先在菜单栏依次点击 Run -> Edit Configurations...

然后新建一个 Remote Debugging:

然后我们随意输出一个名字,并配置端口号为 3000.

以下是一个配置 IDEA remote debugging 的完整流程演示:

使用 IDEA 开始调试

首先将 java 函数以 debug 的方式运行起来:

fun local invoke -d 3000 java8

可以看到函数卡在这里了,接着我们使用 IDEA 连接并开始调试。可以通过菜单栏上的 Run -> Debug... 或者工具栏直接点击 Debug 按钮,即可开始调试。

以下是一个用 IDEA 进行 remote debugging 的完整流程演示:

本地调试 php 类型的函数

php 的调试与其他类型的函数调试在流程上有一些不同。

首先,php 的运行通过 fun local invoke php72 命令完成,这与其他类型的函数一致。调试时,也像其他类型的函数一样,通过 -d 参数以调试模式启动函数:

fun local invoke -d 3000 --config VSCode php72

但不同的是,以 debug 方式运行 php 函数后,php 函数并没有阻塞等待 vscode 调试器的连接,而是直接运行结束。

skip pulling images ...
you can paste these config to .vscode/launch.json, and then attach to your running function
///////////////// config begin /////////////////
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "fc/localdemo/php72",
            "type": "php",
            "request": "launch",
            "port": 3000,
            "stopOnEntry": false,
            "pathMappings": {
                "/code": "/Users/tan/code/fun/examples/local/php7.2"
            },
            "ignore": [
                "/var/fc/runtime/**"
            ]
        }
    ]
}
///////////////// config end /////////////////
FunctionCompute php7.2 runtime inited.
FC Invoke Start RequestId: 6e8f7ed7-653d-4a6a-94cc-1ef0d028e4b4
FC Invoke End RequestId: 6e8f7ed7-653d-4a6a-94cc-1ef0d028e4b4
hello world


RequestId: 6e8f7ed7-653d-4a6a-94cc-1ef0d028e4b4          Billed Duration: 48 ms          Memory Size: 1998 MB        Max Memory Used: 58 MB

这是因为,对于 php 程序,需要首先启动 vscode 的调试器。

php 类型的函数启动 VSCode 调试器的流程与其他类型的函数一致:复制上面日志中的 vscode 配置到 launch.json,单击“开始调试”即可。

然后在终端重新以调试模式启动 php 函数即可开始调试:

fun local invoke -d 3000 php72

Event 事件源

函数计算提供了丰富的触发器,包括但不局限于对象存储触发器、日志服务触发器、CDN 事件触发器等。在本地无论是运行还是调试函数时,为了能够完全模拟线上环境,通常需要构造触发事件。

触发事件可以是一段可读的 json 配置,也可以是一段非可读的二进制数据。这里我们拿 json 举例,假设触发事件内容为:

{
    "testKey": "testValue"
}

想要将这段事件内容传给函数,可以通过以下三种途径:

  1. 管道: echo '{"testKey": "testValue"}' | fun local invoke nodejs8
  2. 文件: 将的 json 内容写入到文件,文件名随意,比如 event.json。然后通过 -e 指定文件名:fun local invoke -e event.json nodejs8
  3. 重定向: fun local invoke nodejs8 < event.json 或者 fun local invoke nodejs8 <<< '{"testKey": "testValue"}' 等等。更多信息可以参考这篇文章

环境变量

在 template.yml 中配置的 EnvironmentVariables 会与线上行为一致,当函数运行时,可以通过代码获取到。更多信息参考

在本地运行函数时,除了 EnvironmentVariables 配置的环境变量,fun 还会额外提供一个 local=true 的环境变量,用来标识这是一个本地运行的函数。

通过这个环境变量,用户可以区分是本地运行还是线上运行,以便于进行一些特定的逻辑处理。

Initializer

在 template.yml 中配置的 Initializer 属性会与线上行为一致,当函数运行时,会首先运行 Initializer 指定的方法。Initializer 更多信息 参考

Credentials

用户可以通过 Credentials 中存储的 ak 信息访问阿里云的其他服务。Fun local 在本地运行函数时,会按照与 fun deploy 相同的 策略 寻找 ak 信息。

关于函数计算 Credentials 的描述,可以参考

以下是一个根据本地、线上环境的不同,利用函数提供的 Credentials 配置 oss client 的例子:

local = bool(os.getenv('local', ""))
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)

附录

代码

本文讲解涉及到的 demo 代码,托管在 github 上。项目目录结构如下:

.
├── java8
│   ├── pom.xml
│   ├── src
│   │   └── main
│   │       └── java
│   │           └── example
│   │               └── App.java
│   └── target
│       └── demo-1.0-SNAPSHOT.jar
├── nodejs6
│   └── index.js
├── nodejs8
│   └── index.js
├── php7.2
│   └── index.php
├── python2.7
│   └── index.py
├── python3
│   └── index.py
└── template.yml

template.yml 定义了函数计算模型,其中定义了一个名为 localdemo 的服务,并在该服务下,定义了 6 个函数,名称分别是 nodejs6、nodejs8、php72、python27、python3、java8。它们对应的代码目录由 template 中的 CodeUri 定义,分别位于 nodejs6、nodejs8、php7.2、python2.7、python3、java8 目录。

更多参考

  1. Fun Repo
  2. Fun specs
  3. Fun examples
  4. Fun 发布 2.0 新版本啦
  5. 函数计算工具链新成员 —— Fun Local 发布啦
相关实践学习
【文生图】一键部署Stable Diffusion基于函数计算
本实验教你如何在函数计算FC上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。函数计算提供一定的免费额度供用户使用。本实验答疑钉钉群:29290019867
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
目录
相关文章
|
4月前
|
运维 负载均衡 Serverless
函数计算产品使用问题之在同一地域同一时刻最多可以同时运行多少个函数实例
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
4月前
|
消息中间件 SQL 监控
Serverless 应用的监控与调试问题之BMQ的架构是怎么支持流批一体的
Serverless 应用的监控与调试问题之BMQ的架构是怎么支持流批一体的
|
1月前
|
监控 安全 Serverless
"揭秘D2终端大会热点技术:Serverless架构最佳实践全解析,让你的开发效率翻倍,迈向技术新高峰!"
【10月更文挑战第23天】D2终端大会汇聚了众多前沿技术,其中Serverless架构备受瞩目。它让开发者无需关注服务器管理,专注于业务逻辑,提高开发效率。本文介绍了选择合适平台、设计合理函数架构、优化性能及安全监控的最佳实践,助力开发者充分挖掘Serverless潜力,推动技术发展。
61 1
|
2月前
|
监控 Serverless 云计算
探索Serverless架构:开发的未来趋势
【10月更文挑战第5天】Serverless架构,即无服务器架构,正逐渐成为云计算领域的热点。它允许开发者构建和运行应用程序而无需管理底层服务器。本文介绍了Serverless架构的基本概念、核心优势及挑战,并展示了其在事件驱动编程、微服务架构和数据流处理等场景中的应用。通过优化冷启动、使用外部存储等实战技巧,开发者可以更好地利用Serverless架构提升开发效率和应用性能。随着技术的成熟,Serverless将在未来软件开发中扮演重要角色。
|
4月前
|
存储 缓存 监控
函数计算产品使用问题之调用sd生图时,怎么保证高并发场景正常运行
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
4月前
|
前端开发 大数据 数据库
🔥大数据洪流下的决战:JSF 表格组件如何做到毫秒级响应?揭秘背后的性能魔法!💪
【8月更文挑战第31天】在 Web 应用中,表格组件常用于展示和操作数据,但在大数据量下性能会成瓶颈。本文介绍在 JavaServer Faces(JSF)中优化表格组件的方法,包括数据处理、分页及懒加载等技术。通过后端分页或懒加载按需加载数据,减少不必要的数据加载和优化数据库查询,并利用缓存机制减少数据库访问次数,从而提高表格组件的响应速度和整体性能。掌握这些最佳实践对开发高性能 JSF 应用至关重要。
72 0
|
4月前
|
存储 设计模式 运维
Angular遇上Azure Functions:探索无服务器架构下的开发实践——从在线投票系统案例深入分析前端与后端的协同工作
【8月更文挑战第31天】在现代软件开发中,无服务器架构因可扩展性和成本效益而备受青睐。本文通过构建一个在线投票应用,介绍如何结合Angular前端框架与Azure Functions后端服务,快速搭建高效、可扩展的应用系统。Angular提供响应式编程和组件化能力,适合构建动态用户界面;Azure Functions则简化了后端逻辑处理与数据存储。通过具体示例代码,详细展示了从设置Azure Functions到整合Angular前端的全过程,帮助开发者轻松上手无服务器应用开发。
31 0
|
4月前
|
机器学习/深度学习 监控 Serverless
Serverless 应用的监控与调试问题之Flink在内部使用的未来规划,以及接下来有什么打算贡献社区的创新技术
Serverless 应用的监控与调试问题之Flink在内部使用的未来规划,以及接下来有什么打算贡献社区的创新技术
|
4月前
|
机器学习/深度学习 监控 大数据
Serverless 应用的监控与调试问题之Flink在整个开源大数据生态中应该如何定位,差异化该如何保持
Serverless 应用的监控与调试问题之Flink在整个开源大数据生态中应该如何定位,差异化该如何保持
|
4月前
|
存储 监控 Serverless
Serverless 应用的监控与调试问题之Pravega和Flink实现端到端的auto-scaling要如何操作
Serverless 应用的监控与调试问题之Pravega和Flink实现端到端的auto-scaling要如何操作

热门文章

最新文章

相关产品

  • 函数计算