目前阿里云的函数计算服务只支持 Nodejs、Python、PHP、Java、.Net。Deno 马上发布 1.0 正式版,于是我为阿里云打造了可运行 Deno 的 Serverless 环境。
GitHub 地址 :github.com/justjavac/deno_serverless_aliyun。
阿里云 serverless 除了支持几个主流平台外,还提供了 Custom Runtime 功能,也就是自定义的执行环境。本文基于 Custom Runtime 为阿里云函数计算提供了 Deno 运行时。
实现一个 Custom Runtime,只需要满足以下 3 个条件:
创建一个 HTTP Server,监听在固定端口(端口可以读取环境变量 FC_SERVER_PORT
,默认为 9000
)。
HTTP Serverr 需要在 15 秒内完成启动。
connection 最好设置为 keep alive,请求超时时间至少设置在 15 分钟以上。
Custom Runtime 本质上是一个 HTTP Server,代码里面包含一个名为 bootstrap 的启动文件,之后这个 HTTP Server 接管了函数计算系统的所有请求,包括事件调用或者 HTTP 函数调用等。
我们使用官方命令行工具 funcraft 初始化一个函数。默认的选项是没有 custom 的,因此我们初始化一个 Nodejs 环境,然后再修改 template.yml 文件:
ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
deno_demo:
Type: 'Aliyun::Serverless::Service'
Properties:
Description: 'helloworld'
fc_deno:
Type: 'Aliyun::Serverless::Function'
Properties:
Handler: index.handler
Runtime: custom
MemorySize: 512
CodeUri: './'
EnvironmentVariables:
'PATH': '/code/.fun/deno/bin'
Runtime 修改为 custom,并且增加一个环境变量 PATH: /code/.fun/deno/bin
,咱们的 Deno 可执行文件会安装在此目录。
其他配置可以根据自己的需要进行修改。
下一步创建一个 server.ts,为了遵守 Deno 的模块约定,我把这个文件起名为 mod.ts。
import {
ServerRequest,
listenAndServe,
} from "https://deno.land/[email protected]/http/server.ts";
async function handler(req: ServerRequest): Promise {
// 获取 request id
const rid: string = req.headers.get("x-fc-request-id") ?? "unknow";
记录日志
console.log(`FC Invoke Start RequestId: ${rid}`);
// 实现 echo 服务:原样返回用户的请求
req.respond({ body: req.body });
}
// 从环境变量获取端口号
const port = Deno.env("FC_SERVER_PORT") ?? "9000";
// 监听网络请求,并处理
listenAndServe(`:${port}`, handler);
// 记录启动日志
console.log("FunctionCompute Deno runtime inited.");
上面代码使用到了某些 es2020 语法,代码比较少,而且几乎每行都有注释,因此我就不单独解释了。
现在我们可以在本地运行如下命令来启动 Web Server。
deno --allow-net --allow-env mod.ts
--allow-net
参数表示 Deno 需要访问网络。
--allow-env
参数表示 Deno 需要读取环境变量。
然而这个程序还无法在阿里云 Serverless 环境运行,我们还需要配置 Deno 运行时环境。
新建 Funfile 文件,这个文件语法和 Dockerfile 类似:
RUNTIME custom
RUN mkdir -p /code/.fun/deno/bin
RUN cd /code/.fun/deno/bin \
&& curl --fail --location --progress-bar --output deno.zip https://cdn.devtips.cn/deno/releases/v0.41.0/deno-x86_64-unknown-linux-gnu.zip \
&& unzip -o deno.zip \
&& chmod +x deno \
&& rm deno.zip \
&& echo "Deno was installed successfully."
为了提升安装速度,我将 Deno 的二进制安装包放到了国内 CDN。
运行 fun build
构建 Deno Runtime。
新建 bootstrap 文件:
#!/bin/bash
deno --allow-net --allow-env mod.ts
至此一个最小化的 Deno Runtime 构建完了。使用 fun deploy -y
部署到阿里云。
运行 fun invoke -e "Hello World"
可以调用刚才部署的 Deno 函数。第一次运行时函数需要冷启,会稍微有点慢。
Duration: 5.58 ms, Billed Duration: 100 ms, Memory Size: 512 MB, Max Memory Used: 9.10 MB
Duration: 1.28 ms, Billed Duration: 100 ms, Memory Size: 512 MB, Max Memory Used: 9.19 MB
Duration: 0.86 ms, Billed Duration: 100 ms, Memory Size: 512 MB, Max Memory Used: 9.96 MB
Duration: 0.98 ms, Billed Duration: 100 ms, Memory Size: 512 MB, Max Memory Used: 9.96 MB
Duration: 0.97 ms, Billed Duration: 100 ms, Memory Size: 512 MB, Max Memory Used: 9.96 MB
可以看到冷启动耗时 5.58 毫秒,后续调用稳定在 1 毫秒左右,内存占用 10M。
对比官方例子中的 ts-node:
Duration: 10.08 ms, Billed Duration: 100 ms, Memory Size: 512 MB, Max Memory Used: 163.52 MB
Duration: 2.31 ms, Billed Duration: 100 ms, Memory Size: 512 MB, Max Memory Used: 163.56 MB
Duration: 1.03 ms, Billed Duration: 100 ms, Memory Size: 512 MB, Max Memory Used: 163.45 MB
Duration: 0.90 ms, Billed Duration: 100 ms, Memory Size: 512 MB, Max Memory Used: 163.45 MB
Duration: 1.20 ms, Billed Duration: 100 ms, Memory Size: 512 MB, Max Memory Used: 163.45 MB
Duration: 0.99 ms, Billed Duration: 100 ms, Memory Size: 512 MB, Max Memory Used: 163.45 MB
ts-node 冷启动耗时 10 毫秒,后续调用也稳定在了 1 毫秒左右,但是内存占用 163M(是 Deno 的 16 倍)。
如果你对 Deno 感兴趣可以点击左下角的阅读原文关注知乎专栏[Deno 开发者社区]。