jiontang 2017-07-21
Serverless 是当今软件架构领域最热的话题,本文作者使用 Serverless 架构重构了 Readability Parser API,使得 API 成本大幅度下降,尽管其架构是基于 AWS,但对于我们通用的架构仍然具有参考价值。
当我去年加入 Postlight 时,第一个任务是重写转码服务(Readability Parser API)。转码服务为稍后阅读应用程序以及其他服务提供 API 支持,它接受互联网上任何文章的链接,然后返回了该文章的结构化内容展示(它可以从网络上混乱的内容中提取结构化内容)[1]。
重写的原因有三个:
API 多年来变得老旧而脆弱,解析结果都存储在数据库中,这意味着整个数据库非常庞大。执行稍微复杂的查询都有问题,这意味着我们对 API 内部发生了什么一无所知。同时也存在原始文章如果更改,API 响应将不会包含更新的结果。
最初作者已经不在公司了,新工程师缺乏必要的领域知识。
最重要的是这个服务每月要花费公司大约 10,000 美元。
重写的几个目标:
生成功能相同的库,返回与原始代码相同的结果。
工程师可以轻松贡献代码。
减少每月产生的费用。
对于语言,我们选择了JavaScript。选择 JavaScript 意味着代码理论上可以在服务器或浏览器中运行。 公司的每个工程师都有 Web 编程经验,所以选择 JavaScript 也意味着几乎每人都可以给新项目提交代码。 旧的代码是用 Python 编写的,但是 Python 缺乏浏览器运行的优势。
为了大幅度降低成本,我们选择了运行在 AWS Lambda[2] 和 API Gateway[3] 上的无服务器架构,它使用 Serverless 框架[4]来构建和部署。
去年十月,我们发布了 Mercury Web Parser[5],结果令人震惊。我们的成本大幅度下降,Mercury Web Parser 每月的成本约为 400 美元,比老的服务的成本要低两个数量级。 (当然也是因为需求或架构略有不同,以前的费用也包括数据库费用,而现在的无服务器架构使用缓存,因此存在数据库开销。)
以下是我们如何实现的一些细节。
假设您以在无服务器环境中满足需求,采用无服务器架构将大大降低成本。简单地转到无服务器环境对降低托管成本有很大帮助。在我们完成改变之后,运行成本降低两个数量级。即使在切换到无服务器架构之后,仍然有降低成本的余地。
如果您对 Lambda 没有任何经验,则其定价将如下所示:
Lambda 免费套餐包含每月 1M 免费请求以及每月 400,000 GB 秒的计算时间。您为 Lambda 函数选择的内存大小决定着它们能以免费套餐运行多久。Lambda 免费套餐在 AWS 免费套餐 12 个月的期限到期后不会自动过期,而是无期限地提供给现有的和新的 AWS 客户。当您希望在 Lambda上优化成本时,最重要的是该函数分配的内存大小决定运行成本。该成本与执行函数所需的时间成比例增加或减少。
(注意:GB-seconds 是分配给函数的内存及执行时间的计量单位,例如,如果你调用一次 3 秒钟的函数,并且你已经为该函数分配了 1GB 内存, 就是执行了 3GB-seconds 的计算时间,如果将该分配减少到 512MB,执行时间保持 3 秒,则将计算时间缩短到 1.5GB-seconds。)
这意味着您可以通过加快执行函数所需的时间,降低内存分配或两者都用来降低 Lambda 成本。由于我们程序的执行速度已经很不错了,所以降低内存是显而易见的选择。
Lambda 的内存分配范围从 128MB 到 1536MB。降低 Lambda 成本的过程很简单。持续降低您的 Serverless 配置中的 memorySize 分配,部署,然后关注您的函数的执行延迟。如果我们的函数的延迟在几个小时后没有显示出显着的变化,那么我们会保留变化并降低成本。
请记住,每次将函数的内存分配减半时,您的 Lambda 成本大致减半。例如,根据官方的 Lambda 定价计算器,100 万次调用(不包括免费级别),平均运行 2 秒(不快,不是特别慢),分配 1GB 内存,将花费 33.54 美元。如果使用 512MB,将花费 $16.87。 256MB 花费 $8.54。
对于转码服务,我们目前运行的函数使用 256MB 配置。
API Gateway 中的缓存响应可以显著减少 Lambda 调用。 例如,用户通常会为相同的文章发起请求。 我们每个月只需要为 API Gateway(使用 0.5GB 内存,1 小时TTL)支付约 14 美元。 在上个月,API 请求中有 52%(2 千万)由缓存命中返回,这意味着只有不到一半(1870 万请求)需要调用我们的 Lambda 函数,这可以为我们节省 240 美元。
除了节省成本之外,无服务器架构也可能会大大降低维护/配置成本以及复杂性。 我们的 API 可以使用相同的配置,缓存和部署方法来为 1,000 个请求到 100,000,000 个请求提供服务。
此外,随着服务的扩展,成本并不一定会增加。 毕竟超过一半的 API 请求可以由我们的缓存提供服务。
在上述所有优化之后,我们目前运行 Mercury Web Parser API 的成本如下所示:
服务费用为137美元
缓存:$ 14
数据传输:$ 42(这是以0.09美元/ GB计算)
请求费用:3美元
计算成本:$ 174(平均2.37s /调用,内存分配256MB)
总成本:$ 370
我们已经使用 Lambda 做了很多事情,从解析网页到编写 Slack 机器人; 从批量转换数十万张照片到转码数十万部影片。
我们越多使用它,就越认为无服务器架构解决了很多问题。到目前为止,Mercury Web Parser 及其所使用的工具一直是我们决定使用无服务器架构的最佳验证。
在 Postlight,我们使用了 Mercury Web Parser 来支持:
Mercury AMP 转换器[6],任何使用 Google AMP 的网站,只需要加入一行代码。
Mercury Reader[7] 是超过 100 万用户使用的 Chrome 扩展程序,通过点击按钮可以消除文章中的广告和干扰,只留下任何网站上的文字和图像。
Bloomberg Lens[8],Chrome 扩展程序和 iOS 共享表应用程序,其中提供有关网络上任何文章的相关新闻,公司数据和个人信息。
我们还支持数千名每天使用 Mercury 的开发人员从网络上的任何文章中提取结构化内容。 每月完成 3900 万个请求,只需 370 美元。
对于每一百万的请求,花费还不到 10 美元,并且可以轻松地扩容。