Life is too short to waste a second

聊聊 Serverless

What is Serverless

关于无服务(Serverless)的介绍,我相信网上有更多更全的介绍,这里高度总结一下。个人认为,无服务是用 FaaS,BaaS 组合起来的,通过 FaaS 和 BaaS ,你可以将你的程序快速部署在 Serverless 提供方中,省去了购买主机,安装环境等操作。还不清楚什么是 FaaS BaaS?马上进行介绍。

FaaS (Function as a Service)

更多需要了解的是 FaaS (函数即服务)它是已函数为单位提供服务的,你只需要为每个函数的执行付费,相对于传统的 IaaS(基础设施即服务)和 PaaS(平台即服务),FaaS 的第一个优点就出来了,你不会维护你的服务器,或者是容器服务等。你只需要维护你的函数即可。同时,正如其名,无服务是没有没有服务状态的,无论是 IaaS 还是 PaaS,你都需要保证你的服务器或容器一直在运行,它们是有服务状态的。FaaS 只有在触发了相关操作时才会运行,这个操作可以是一个网络请求,也可以是定时循环等。那么 FaaS 的第二个优点也出来了,它的成本相当于其他的会减少很多,你可以理解为原来你的计算机需要保持开机状态以随时服务用户,而现在当用户有需求了,你的计算机再开机以服务用户。然而,成本的减少必然意味着你会损失其他的东西,拿我们刚刚举的开机的例子,你的计算机开机再服务很明显它的处理时长是没有一直开机的计算机处理快,我们稍候看看 FaaS 如何处理这个问题的。

BaaS (Backend as a Service)

BaaS(后端即服务)后端其实本来就是一个服务,这里的 BaaS 指的是后端需要使用到的一些资源,比如,数据库总得要有一个吧,你可以自己安装一个数据库,然后使用它,但是现在更加推荐的是使用云服务商提供的数据库。还有,后端偶尔也得存个文件吧,你可以放在你的服务器中,但是更加推荐使用对象存储,听起来很高深,把它当成云盘也差不多。BaaS 提供了大量的运行时资源,让你的后端程序不需要在本地安装任何额外的环境,直接通过网络调用数据库之类的即可。

FaaS + BaaS ≈ Serverless

介绍了 FaaS 和 BaaS,再回过头看 Serverless,举个例子,我们准备用 Node.js 搭建一个 RESTful 服务,我们可以用 Docker 部署,拉镜像,Node,Mysql,Nginx。 docker run 就部署好了,如果用 IaaS 可能会更加复杂一点点。我们再来看看 Serverless 怎么玩的,我们使用云数据库,所以 Mysql 或是其他 Nosql 数据库不需要安装了,这里用到的是 BaaS。程序得跑起来吧,我们把每个接口写成 Serverless 规范的函数,serverless deploy,好了,我们的 RESTful 服务已经上线了。serverless deploy是什么命令,一句命令就把服务上线了?这里我们已腾讯云的 Serverless Framework 为例,serverless deploy 将你的程序打包上传 cos(对象存储),然后再使用 SCF(云函数)将代码部署为一个或多个函数,这里的 SCF 就是腾讯云实现的 FaaS。部署成功后 ,腾讯云的 Serverless Framework 会返回一个地址,它就是你程序的公网地址了,当然,你可以自定义地址。看看我们使用 Serverless 部署花费的时间,大概是 15s 左右。即便你没有任何运维经验,你的服务依然上线了。通过一个 RESTful 实例,我们大概已经了解到了 Serverless 是如何结合 FaaS 和 BaaS 工作的,值得一提的,BaaS 不是必须的 它只是在大部分后端中需要使用的。如果你的程序根本不用到数据库之类的,Serverless 仅仅需要 FaaS 即可,例如一个爬虫,或是实时监控之类的。

Show me the code

刚刚讲了如何用 Serverless 部署一个服务,现在我们来实际操作一下。我们这里使用腾讯云的 Serverless Framework。嗯,已经有框架了,大概是今年 4 月上线的,不过国外的 AWS 才是 Serverless 的领头羊。

环境: yarn

我们使用 koa 框架来搭建一个简单的 http 服务器

创建 sls.js ,并写入代码

const koa = require('koa')
const app = new koa()

app.use(async (ctx) => {
  ctx.body = 'Hello Serverless'
})

// don't forget to export!
module.exports = app

注意,我们通常的 koa 入口为 app.js ,在腾讯云中我们要修改为 sls.js,腾讯云的文档本来还写的 app.js,我已经提交反馈并修改了。

可能你的代码会报错,因为我们还没引入依赖

yarn init --yes
yarn add koa
yarn add serverless

然后我们再创建 serverless.yml写入以下内容

# serverless.yml

org: orgDemo # (optional) serverless dashboard org. default is the first org you created during signup.
app: appDemo # (optional) serverless dashboard app. default is the same as the name property.
stage: dev # (optional) serverless dashboard stage. default is dev.
component: koa # (required) name of the component. In that case, it's koa.
name: koaDemo # (required) name of your koa component instance.

inputs:
  src:
    src: ./ # (optional) path to the source folder. default is a hello world app.
    exclude:
      - .env
  region: ap-guangzhou
  runtime: Nodejs10.15
  apigatewayConf:
    protocols:
      - http
      - https
    environment: release

serverless.yml 配置了你的服务名,运行环境,之类的,仔细看看应该都能理解

好,我们运行serverless deploy,腾讯云会显示一个二维码,扫码登陆腾讯云授权即可,不得不说还是国内企业懂我们,能扫码的就不自己写 access key 了,登陆后你会发现本地多了个.env文件,它里面就是你的 access key 了,如果要 git 的话不要将它上传至代码仓库

大概十多秒或者几秒,你就能看到 success 了,点击命令行中的 url 访问,你就能看到我们写的服务了,页面会显示 Hello Serverless

整个过程就是 编码 -> 部署,和以前的比比呢? 编码 -> 上传代码 -> 拉取代码 -> 重启服务。使用 serverless ,我们在十多秒就让我们的代码上线了。

接下来就是 CD(持续部署) 了吧,我们修改以下sls.js代码

const koa = require('koa')
const app = new koa()

app.use(async (ctx) => {
  ctx.body = 'I just changed the response'
})

// don't forget to export!
module.exports = app

然后部署serverless deploy,部署成功后我们再访问 url ,可以看到页面内容由 Hello Serverless 变成了 I just changed the response

以上就是 Serverless 的实战了

When Serverless

我们看到,使用 Serverless 让我们的程序部署更加方便,那么什么时候使用它呢?我们需要注意的是,Serverless 是无状态的。因此,如果你的函数想存储文件/日志到本地,那么 Serverless 是不支持的,因此你仅仅有云提供商的计算资源,没有存储资源,如果你尝试写入文件,你会收到 access denied 的提示,不过,只要智商不滑坡,办法总比困难多。我们前面提到了 BaaS,对象存储功能,因此,涉及到文件操作的业务,我们完全可以使用对象存储来处理。如果你还使用 session 之类的技术,那么 Serverless 还是不能支持的,曲线救国,我们可以使用 Redis 来实现,不过我更加推荐同样是无状态的 JWT 来实现验证功能。如果你的服务需要频繁的访问数据库,那么使用 Serverless 可能带来一些不便之处,为什么?因为我们往往是使用数据库连接池来操作数据库,而连接池是有状态的,这意味着一个函数执行完后,连接就断掉了,也就不存在连接池。因此,我们需要在每个函数前都先连接数据库,再执行业务。如何曲线救国?这就是我们最开始提到的一直开机的计算机和用户来了再开计算机的例子。通常,云服务商会保持一个函数运行一段时间,如果在这段时间中再次触发,那么函数的运行速度就和已经开机的计算机一样了。而第一次运行往往就会更慢一些,我们称之为冷启动,而在保持时间内再次运行,就是热启动。值得一提的是我尝试过将一个完善的 Koa 框架迁移至 Serverless ,但是经过测试它的运行速度和原来比慢了几倍,而这个差距就是数据库连接造成的,因此如果想把原有项目迁移至 Serverless ,你可能需要花费大量的时间进行优化,对于大型项目来说,往往是得不偿失的。同时,使用 Serverless 意味着你不能像本地开发一样调试错误,因为出现错误时你只能通过日志排错,无法逐步调试。所以,上线前的测试环节就很重要了。而且你也很难确保你的项目是完全无状态的。因此我更加推荐在新项目应用 Serverless ,或者是在不需要过多状态化的项目中使用。

Future

尽管上面提到了很多使用 Serverless 可能造成的问题,但是我们还是要勇于去尝试新的技术。没有什么技术一开始就是被看好的,我相信未来 Serverless 会针对这些问题做出优化。例如我们提到的计算机开机的例子,Serverless 能够通过保持函数运行来解决,至于数据库连接问题部分云服务商已经开发了 Serverless 数据库。我们一直在追寻更加优雅的开发过程,基于 Serverless 的秒级部署,Serverless 必然会越来越受到关注。

发表评论

电子邮件地址不会被公开。