为阿里云 serverless 打造 Deno 运行时

目前阿里云的函数计算服务只支持 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<void> {
  // 获取 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 开发者社区]。

猜你喜欢

转载自blog.csdn.net/vCa54Lu0KV27w8ZZBd/article/details/105851847
今日推荐