Blog | Phodal - A Growth Engineerhttp://www.phodal.com/blog/2017-11-20T13:40:39.867756+00:00BlogServerless 架构的优点和缺点2017-11-20T13:36:14+00:002017-11-20T13:40:39.867756+00:00Phodal Huanghttp://www.phodal.com/blog/author/root/http://www.phodal.com/blog/serverless-architecutre-cons-and-pros/
Serverless 的优势
---
在我使用 Serverless Framework 开发 AWS Serverless 应用的过程中,最方便的莫过于,第一次部署和第二次、第三次部署没有什么区别。只需要执行 ``serverless deploy``,几分钟后,我们代码就运行在线上。如果是一个传统的 AWS 应用,我需要 SSH 到我的服务器上部署,这样才能写好我的自动部署脚本。除此,我还需要担忧这个过程中,有哪些用户有使用。
除了,我觉得的部署方便,还有就是价格合理。我的 AWS EC2 实例上运行着我的博客、以及其他的一些网络。然而,我那 PV 只有 500 左右的博客,大部分时间都是在空转。便觉得有些浪费,可是运行才收费的 Serverless 就不会有这样的问题。可以让我大胆地去使用这些服务。当然了,还有其它一些显著的优势。
### 降低启动成本
当我们作为一家公司开发一个 Web 应用时,在开发的时候,我们需要版本管理服务器、持续集成服务器、测试服务器、应用版本管理仓库等作为基础的服务。线上运行的时候,为了应对大量的请求,我们需要一个好的数据库服务器。当我们的应用面向了普通的用户时,我们需要:
- 邮件服务,用于发送提醒、注册等服务
- 短信服务(依国家实名规定),用于注册、登录等用户授权操作
对于大公司而言,这些都是现成的基础设施。可对于新创企业来说,这都是一些启动成本。
#### 减少运营成本
对于初创公司来说,他们没有基础设施,也没有财力,也可能没有能力去建设基础设施。采用云服务往往是最好的选择,可以节省大量的资金。他们可以将注意力放在:创造对用户有价值的产品上。如果一家创业公司采用云服务,而不是自己搭建服务器。那么,他就会拥有**更多的时间**开发业务功能,而不是关注在这些。只需要为运行时的软件付钱。
而采用**函数计算**的 Serverless 与云服务器最大的不同之处在于:**云服务器需要一直运行,而函数计算是按需计算**。按需计算就意味着,在请求到来的时候,才运行函数。没有请求的时候,是不算钱的。
项目初期,其用户数往往是缓慢增长的,而我们在选择服务器的时候,往往会依可能出现的用户来估算。在这个时候,往往会浪费一些不必要的成本。不过,就算用户突然间爆发,Serverless 应用也可以轻松处理。只需要修改一下数据库配置,再重新部署一份。
#### 降低开发成本
一个成功的 Serverless 服务供应商,应该能提供一系列的**配套服务**。这意味着,你只需要在配置文件上写下,这个数据库的表名,那么我们的数据就会存储到对应的数据库里。甚至于,**如果一个当服务提供者提供一系列的函数计算模板,那么我们只需要写好我们的配置即可。这一系列的东西都可以自动、高效的完成。
在这种情况下,**使用某一个云服务,就会调用某一个系统自带的 API 一样简单**。
当然,将应用设计成无状态应用,对于早期的系统,可能是一种挑战。除此,诸如 AWS 这样庞大的系统,对于新手程序员来说,也不能容易消化掉的一个系统。
### 实现快速上线
对于一个 Web 项目来说,启动一个项目需要一系列的 hello, world。当我们在本地搭建环境的时候,是一个 hello, world,当我们将程序部署到开发环境时,也是一个部署相关的 hello, world。虽然看上去有些不同,但是总的来说,都是 it works!。
Serverless 在部署上的优势,使得你可以轻松地实现上线。
#### 更快的部署流水线
实际上,Serverless 应用之所以在部署上有优势,是因为其相当于**内建自动化部署**——我们在开发应用的时候,已经在不断地增强部署功能。
在我们日常的开发中,为了实现自动化部署,我们需要先手动部署,以设计出一个相关无错的部署配置,如 Docker 的 Dockerfile,又或者是 Ansible 的 playbook。除此,我们还需要设计好蓝绿发布等等的功能。
而在函数计算、Serverless 应用里,这些都是由供应商提供的功能。每次我们写完代码,只需要运行一下:``sls deploy`` 就足够了。在诸如 AWS Lambda 的函数计算里,函数一般在上传后几秒钟内,就能做好调用准备。
这就意味着,当我们和日常一样,使用一个模板来开发我们的应用。我们就可以在 Clone 完代码后的几分钟内,完成第一次部署。
唯一的难点,可能是要选用什么配置类型的服务,如选用哪个级别吞吐量的 DynamoDB、哪个内存大小的 Lambda 计算。
#### 更快的开发速度
由于 Serverless 服务提供者,已经准备好了一系列的基础服务。作为开发人员的我们,只需要关注于如何更好去实现业务,而非技术上的一些限制。
服务提供者已经向我们准备,并测试好了这一系列的服务。它们基本上是稳定、可靠的,不会遇上特别大的问题。事实上,当我们拥有足够强大的代码,如使用测试来保证健壮性,那么结合持续集成,我们就可以在 PUSH 代码的时候,直接部署到生产环境。当然,可能不需要这么麻烦,我们只需要添加一个 predeploy 的 hook,在这个 hook 里做一些自动测试的工作,就可以在本地直接发布新的版本。
这个过程里,我们并不需要考虑太多的发布事宜。
### 系统安全性更高
依我维护我博客的经验来看,要保持服务器一直运行不是一件容易的事。在不经意的时候,总会发现有 Cracker 在攻击你网站。我们需要防范不同类型的攻击,如在我的服务器里一直有黑客在尝试密码登录,可是我的博客的服务器是要密钥才能登录的。在一次神奇的尝试登录攻击后,我的 SSH 守护进程崩溃了。这意味着,我只能从 EC2 后台重启服务器。
有了 Serverless,我不再需要担心有人尝试登录系统,因为我都不知道怎么登录服务器。
我不再需要考虑系统底层安全问题,每次登录 AWS EC2,我总需要更新一遍软件;每当我看到某个软件有漏洞时,如之前的 OpenSSH,我就登录上去看一下版本,更新一下软件。真 TM 费时又费力,还没有一点好处。
唯一需要担心的,可能是有人发起 DDOS 攻击。而根据[Could Zombie Toasters DDoS My Serverless Deployment?](https://thenewstack.io/zombie-toasters-eat-startup/)的计算,每百万的请求,大概是 0.2 刀,每小时 360000000 个请求,也就 72 刀。
### 适应微服务架构
如我们所见在最近几年里看到的那样,微服务并不没有大量地替换掉单体应用——毕竟使用新的架构来替换旧的系统,在业务上的价值并不大。因此,对于很多企业来说,并没有这样的强烈需求及紧迫性。活着,才是一件更紧迫的事。
而 Serverless 天生就与微服务架构是**相辅相成**的。一个 Serverless 应用拥有自己的网关、数据库、接口,你可还以使用自己喜欢的语言(受限于服务提供者)来开发服务。换句话来说,在这种情形下,一个 Serverless 可能是一个完美的微服务实例。
在可见的一二年里,Serverless 将替换到某些系统中的一些组件、服务。
### 自动扩展能力
Serverless 的背后是 诸如 AWS Lambda 这样的 FaaS(Function as a Services)。
对于传统应用来说,要应对更多的请求的方式,就是部署更多的实例。然而,这个时候往往已经来不及了。而对于 FaaS 来说,我们并不需要这么做,FaaS 会自动的扩展。它可以在需要时尽可能多地启动实例副本,而不会发生冗长的部署和配置延迟。
这依赖于我们的服务是无状态的,我们才能次无忌惮地不断运行起新的实例。
Serverless 的问题
---
作为一个运行时,才启动的应用来说,Serverless 也存在着一个个我们所需要的问题。
### 不适合长时间运行应用
Serverless 在请求到来时才运行。这意味着,当应用不运行的时候就会进入 “休眠状态”,下次当请求来临时,应用将会需要一个启动时间,即**冷启动**。这个时候,可以结合 CRON 的方式或者 CloudWatch 来定期唤醒应用。
如果你的应用需要一直长期不间断的运行、处理大量的请求,那么你可能就不适合采用 Serverless 架构。在这种情况下,采用 EC2 这样的云服务器往往是一种更好的选择。因为 EC2 从价格上来说,更加便宜。
引用 [Lu Zou](https://www.zhihu.com/people/lu-zou-36) 在 《[花了 1000G,我终于弄清楚了 Serverless 是什么(上):什么是 Serverless 架构?](https://zhuanlan.zhihu.com/p/31122433)》上的评论:
> EC2 相当于你买了一辆车,而 Lambda 相当于你租了你一辆车。
长期租车的成本肯定比买车贵,但是你就少掉了一部分的维护成本。因此,这个问题实际上是一个值得深入计算的问题。
### 完全依赖于第三方服务
是的,当你决定使用某个云服务的时候,也就意味着你可能走了一条不归路。在这种情况下,只能将不重要的 API 放在 Serverless 上。
当你已经有大量的基础设施的时候,Serverless 对于你来说,并不是一个好东西。当我们采用 Serverless 架构的时候,我们就和特别的服务供应商绑定了。我们使用了 AWS 家的服务,那么我们再将服务迁到 Google Cloud 上就没有那么容易了。
我们需要修改一下系列的底层代码,能采取的应对方案,便是建立隔离层。这意味着,在设计应用的时候,就需要:
- 隔离 API 网关
- 隔离数据库层,考虑到市面上还没有成熟的 ORM 工具,让你即支持 Firebase,又支持 DynamoDB
- 等等
这些也将带给我们一些额外的成本,可能**带来的问题会比解决的问题多**。
### 冷启动时间
如上所说,Serverless 应用存在一个冷启动时间的问题。
据 New Relic 官方博客《[Understanding AWS Lambda Performance—How Much Do Cold Starts Really Matter?](https://blog.newrelic.com/2017/01/11/aws-lambda-cold-start-optimization/)》称,AWS Lambda 的冷启动时间。
![AWS 启动时间](/static/media/uploads/serverless/aws-lambda-monitoring-functions-chart.png)
又或者是我之前统计的请求响应时间:
![Serverless 请求时间](/static/media/uploads/serverless/times.png)
尽管这个冷启动时间大部分情况下,可以在 50ms 以内。而这是对于 Node.js 应用来说,对于拥有虚拟机的 Java 和 C# 可能就没有那么幸运了。
### 缺乏调试和开发工具
当我使用 Serverless Framework 的时候,遇到了这样的问题:缺乏调试和开发工具。后来,我发现了 serverless-offline、dynamodb-local 等一系列插件之后,问题有一些改善。
然而,对于日志系统来说,这仍然是一个艰巨的挑战。
每次你调试的时候,你需要一遍又一遍地上传代码。而每次上传的时候,你就好像是在部署服务器。然后 Fuck 了,我并不能总是快速地定位出问题在哪。于是,我修改了一下代码,添加了一行 ``console.log``,然后又一次地部署了下代码。问题解决了,挺好的,我删了一下 ``console.log``,然后又一次地部署了下代码。
后来,我学乖了,找了一个类似于 log4j 这样的可以分级别纪录日志的 Node.js 库 ``winston``。它可以支持 error、warn、info、verbose、debug、silly 六个不同级别的日志。
### 构建复杂
Serverless 很便宜,但是这并不意味着它很简单。
早先,在知道 AWS Lambda 之后,我本来想进行一些尝试。但是 CloudForamtion 让我觉得太难了,它的配置是如此的复杂,并且难以阅读及编写(JSON 格式)。
考虑到 CloudForamtion 的复杂度,我是在接触了 Serverless Framework 之后,才重新燃起了一些信心。
Serverless Framework 的配置更加简单,采用的是 YAML 格式。在部署的时候,Serverless Framework 会根据我们的配置生成 CloudForamtion 配置。
在那篇《[Kinesis Firehose 持久化数据到 S3](https://www.phodal.com/blog/serverless-development-guide-use-kinesis-firehose-stream-data-s3/)》想着的数据统计文章里,我们介绍了 Serverless 框架的配置。与一般的 Lambda 配置来说,这里的配置就稍微复杂一些。然而,这也并非是一个真正用于生产的配置。我的意思是,真实的应用场景远远比这复杂。
### 语言版本落后
在 Node.js 6 出来的时候,AWS Lambda 只支持 Node.js 4.3.2;在 Node.js 9.0 出来的时候,AWS Lambda 支持到 6.10.3。
如下是 AWS Lambda 支持以下运行时版本:
- Node.js – v4.3.2 和 6.10.3
- Java - Java 8
- Python – Python 3.6 和 2.7
- .NET 内核 – .NET 内核 1.0.1 (C#)
对于 Java 和 Python 来说,他们的版本上可能基本都是够用的,我不知道 C# 怎么样。但是 Node.js 的版本显然是有点老旧的,但是都 Node.js 9.2.0 了。不过,话说来说,这可能与版本帝 Chrome 带来的前端版本潮有一点关系。