(为) 什么是 Serverless
在 Web 开发领域, Serverless 相比传统方式, 最大的优势在于
可以在低运维前提下实现水平扩展. 这样开发者得以将主要精力放在业务上,
而不是为了支持可能的高并发而过多关注繁杂的技术细节, 因为专注于业务,
大大提升了开发效率, 降低了开发成本.
同时弹性的水平扩展可以支持任何访问频次的业务需求, 而无需担心成本收益不符问题.
从日 1 PV 到日 1,000,000 PV 的应用都可以支持, 而无需进行额外配置,
不需要自己做集群管理, 也无需承担固定的费用, 按使用量付费即可.
我们可以把 Serverless 理解为无需自己管理的按需扩缩的容器集群.
在 Web 应用的开发上, 无论从技术角度, 还是成本角度, Serverless 都更有优势.
如何实现传统 Web 应用到 Serverless 的迁移呢?
理论上, 任何编程语言语言都可以在 Serverless 上进行使用.
不过在具体实现上, Serverless 提供了如下几种方法:
- 直接运行脚本语言. (Serverless 容器已经携带目标语言运行时, 仅上传代码即可)
- 运行时 + 语言脚本. (全部上传到 Serverless)
- 可执行文件. (在本地编译为可执行文件, 然后上传到 Serverless)
- 自定义容器. (目前阿里云 Serverless 支持 Docker 镜像以生成容器)
以上几种方法, 在阿里云 Serverless 上均支持.
对比以上几种方法的优缺点.
直接运行脚本语言是冷启动时间 (即代码执行前 Serverless 容器准备的时间) 最短的.
自定义容器是兼容性最好的. 而我们此处用到的是一个平衡做法: 自定义运行时.
之所以选择自定义运行时, 是因为我们采用的运行时是 Deno, 一款现代化 JS/TS 运行时.
一方面, 虽然 JS 是脚本语言, 但阿里云目前还不支持 Deno 运行时, 所以无法通过
直接运行脚本语言 的方式在 Serverless 上运行应用.
另一方面, Deno 提供类似 Go 语言的打包为可执行文件功能,
无需使用容器即可实现代码的跨平台运行.
(为) 什么是 Deno
Deno, 是一款 JS/TS 运行时, 与 Node.js 一样使用 V8 作为 JS 解释器, 保证了速度,
与 Node.js 不同的是, 使用 Rust 而非 C++ 作为开发语言, 与操作系统进行沟通.
(二者相同的另一点是发起人和最初的主要开发者均为 Ry, Ryan Dahl)
Node.js 作为后端 JS 运行时, 无疑是影响巨大且成功的. 但 Node.js 诞生在多年前,
随着 ECMAScript 的发展, JavaScript(JS) 已经今非昔比, 而为了保证生态兼容性,
Node.js 又难以进行大刀阔斧的改革. 这就是 Deno 诞生的大背景.
而对于开发者而言, Deno 除了更好的 ECMAScript 兼容性,
还提供开箱即用的 TypeScript (TS) 支持,
提供更健壮类型约束的同时大大降低了开发环境配置等不必要的消耗.
目前, 随着 Deno 版本的不断迭代, 在 Web 开发场景下,
Deno 已经可以实现大部分 Node.js 可以实现的功能.
使用 Deno 作为运行时对 JS 开发者来说可以快速上手, 不会有过大负担.
相比 Node.js, Deno 的最大优势有两个:
- 支持 Web API. (比如 fetch, crypto 等)
- 支持文件引用, 而不需要使用 npm 这样的包管理器.
支持 Web API 可以打通前后端技术栈, 而 npm 苦开发者久矣.
简单的 Deno Web 应用例子
使用 Deno 开发 Web 应用非常简单,
下面我们来快速创建一个简单的 Web 应用实现 UA 显示.
import { serve } from "https://deno.land/std@0.148.0/http/server.ts";
function handler(req: Request): Response {
return new Response(
["Hello, World!", req.method, req.url, req.headers.get("user-agent")].join(
"\n"
)
);
}
serve(handler, { port: 9000 });
现在我们将以上代码保存在 /User/zsqk/web/main.ts
地址中.
创建 Serverless 函数
有了代码, 我们还需要部署地址. 这里我们以阿里云函数计算为例.
首先是创建自定义运行时函数.
- 进入阿里云函数计算 Web 控制台.
- 点击左侧导航栏 "服务与函数".
- 点击 "创建服务" 进行服务的创建.
- 点击服务名称进入服务界面.
- 点击 "创建函数".
- 在创建函数时, 选择 "使用自定义运行时平滑迁移 Web Server", 然后进行函数创建.
然后需要绑定域名.
- 回到函数计算首页后, 点击左侧导航栏 "域名管理".
- 点击 "添加自定义域名".
- 在添加自定义域名时, 选择刚才我们创建的服务及函数.
此时我们就完成所有基础配置, 拿到了需要的参数:
- 服务名.
- 函数名.
- 访问域名.
在 Serverless 上一键部署 Deno Web 应用
在 Serverless 上部署 Deno Web 应用是很方便的. 我们可以实现一键部署.
利用阿里云 Serverless 的自定义运行时, 在本地构建出一个可执行文件,
然后通过 [Serverless Devs] 工具将代码部署到函数计算, 在 Serverless 上执行即可.
这里我们假定已经在本地环境安装好了 Deno 与 s 工具.
现在创建如下配置文件并放到 /User/zsqk/web/s.yaml
中.
edition: 1.0.0
name: zsqk-fc
access: default
services:
fc-z1-deno:
component: devsapp/fc
props:
region: ${地区}
service:
name: ${服务名}
function:
name: ${函数名}
instanceConcurrency: 5
instanceType: e1
memorySize: 128
runtime: custom
timeout: 3
codeUri: "./dist"
代码和部署配置文件都已经准备好, 下面只需要构建并上传代码即可.
首先进入 /User/zsqk/web/
目录中, 使用以下为使用 Deno 运行构建及上传命令的例子:
// 构建 deno 文件
const r = Deno.run({
cmd: [
`deno`,
"compile",
"--output",
"dist/bin/zsqk",
"--target",
"x86_64-unknown-linux-gnu",
"--allow-all",
"/User/zsqk/web/main.ts",
],
});
await r.status();
r.close();
Deno.writeTextFileSync(
`/User/zsqk/web/dist/bootstrap`,
"#!/bin/bash\n./bin/zsqk --allow-all"
);
// 准备上传
const r = Deno.run({
cmd: ["s", "deploy", "function", "--use-local"],
});
await r.status();
r.close();
当以上命令执行成功,
我们就完成了一键部署 Deno Web 应用到 Aliyun Serverless 的全部流程.
接写来我们可以使用上一章配置的访问域名来查看我们的 UA Web 是否正常工作.
至此, 我们就完成了整个工作. 之后, 如果每次需要应用代码变动,
只需要重新执行构建及部署命令即可.