云开发 Serverless 从入门到实战

Serverless

指构建和运行不需要服务器管理的应用程序的概念。
Serverless 是 FaaS 和 BaaS 的结合。Serverless = FaaS + BaaS。

FaaS(Function as a Service) 就是一些运行函数的平台,比如阿里云的函数计算、AWS 的 Lambda 等。
BaaS(Backend as a Service)则是一些后端云服务,比如云数据库、对象存储、消息队列等。利用 BaaS,可以极大简化我们的应用开发难度。

Serverless 的主要特点有:

  • 事件驱动
  • 函数在 FaaS 平台中,需要通过一系列的事件来驱动函数执行。
  • 无状态
  • 因为每次函数执行,可能使用的都是不同的容器,无法进行内存或数据共享。如果要共享数据,则只能通过第三方服务,比如 Redis 等。
  • 无运维
  • 使用 Serverless 我们不需要关心服务器,不需要关心运维。这也是 Serverless 思想的核心。
  • 低成本
  • 使用 Serverless 成本很低,因为我们只需要为每次函数的运行付费。函数不运行,则不花钱,也不会浪费服务器资源

前端工程师基于 Serverless 去写后端,最好也需要具备一定的后端知识。涉及复杂的后端系统或者 Serverless 不适用的场景,还是需要后端开发,后端变得更靠后了。

Serverless 开发最佳实践

将业务逻辑和函数依赖的 FaaS(如函数计算) 和 BaaS (如云数据库)分离。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Users {
constructor(db, mailer) {
this.db = db;
this.mailer = mailer;
}
save(email, callback) {
const user = {
email: email,
created_at: Date.now()
}
this.db.saveUser(user, function (err) {
if (err) {
callback(err);
} else {
this.mailer.sendWelcomeEmail(email);
callback();
}
});
}
}
module.exports = Users;

const db = require('db').connect();
const mailer = require('mailer');
const Users = require('users');
let users = new Users(db, mailer);
module.exports.saveUser = (event, context, callback) => {
users.save(event.email, callback);
};

将业务逻辑全都放在了 Users 这个类里面,Users 不依赖任何外部服务。

函数的性能

当驱动函数执行的事件到来的时候,首先需要下载代码,然后启动一个容器,在容器里面再启动一个运行环境,最后才是执行代码。前几步统称为冷启动(Cold Start)。传统的应用没有冷启动的过程。

当第一次请求(驱动函数执行的事件)来临,成功启动运行环境并执行函数之后,运行环境会保留一段时间,以便用于下一次函数执行。这样就能减少冷启动的次数,从而缩短函数运行时间。当请求达到一个运行环境的限制时,FaaS 平台会自动扩展下一个运行环境。

执行上下文重用

1
2
3
4
5
6
const mysql = require('mysql');
// 初始化数据库连接 const connection = mysql.createConnection({ /* ... */ });
connection.connect();
module.exports.saveUser = (event, context, callback) => {
connection.query('...');
};

这样就只有第一次运行环境启动的时候,才会初始化数据库连接。后续请求来临、执行函数的时候,就可以直接利用执行上下文中的 connection,从而提高后续高函数的性能。
大部分情况下,通过牺牲一个请求的性能,换取大部分请求的性能,是完全可以够接受的。

给函数预热

通过主动调用函数的方式,隔一段时间就冷启动一个运行环境,这样就能使得其他正常的请求都是热启动,从而避免冷启动时间对函数性能的影响。

需要注意:

  • 不要过于频繁调用函数,至少频率要大于 5 分钟
  • 直接调用函数,而不是通过网关等间接调用
  • 创建专门处理这种预热调用的函数,而不是正常业务函数

如果你的业务允许“牺牲第一个请求的性能换取大部分性能”,那也完全不必使用该方案,

阅读更多
You need to set client_id and slot_id to show this AD unit. Please set it in _config.yml.