Lessons Learned — A Year Of Going “Fully Serverless” In Production Lessons Learned — A Year Of Going “Fully Serverless” In Production

2025-06-07

经验教训——在生产环境中迈向“完全无服务器”的一年

经验教训——在生产环境中迈向“完全无服务器”的一年

经验教训——在生产环境中迈向“完全无服务器”的一年

摄影:Aaron Burden

Torii ,我们决定尽可能地无运维 (no-ops)路线,这意味着我们将把所有精力集中在产品上,而不是运维上。虽然我们喜欢 DevOps,但这不是我们公司的主要关注点。

无服务器,因为我们喜欢晚上睡觉。

我们可以将应用程序分为三个部分:

  1. 静态网站。这些是用 React 编写并在构建时静态生成的前端网站。

  2. 后台作业。这些作业是由文件上传、webhook 或任何其他异步事件等事件调度或触发的。

  3. **API 服务器。**与我们的数据库交互并满足所有客户端请求的 REST API 服务器。

经验教训

#1. 静态网站

静态网站速度快、易于扩展且易于分发。我们使用 React 构建前端,并将代码打包为简单的 HTML/JS/资源包,方便分发。

我们使用Netlify在 CDN 上托管这些静态资产,并从世界任何地方获得快速的加载时间

这里无需配置 Nginx/Apache 服务器👍

#2. 无服务器上的 API 服务器

其基本思想是,API 服务器本身就是一个函数:输入是 HTTP 请求,输出是 HTTP 响应。它非常适合 FaaS函数即服务),因为每个 HTTP 请求都有自己的服务器实例来处理。

这种设置可以实现自动扩展、高可用性,并显著降低成本。由于移动部件更少,它也使事情变得更简单:没有服务器、没有负载均衡器、没有自动扩展组。所有这些都被抽象出来,我们只关心一个功能。

我们将整个 Node.js 应用打包为单个 AWS Lambda 函数。API 网关将所有流量路由到该函数,Node.js 应用会将其视为常规 HTTP 请求。

我们选择 apex/up 来设置、更新和部署我们的函数栈。它真的就像在终端里写代码一样简单。它高度可配置,因此您可以根据自己的需求自定义部署,但如果没有特殊要求,默认设置也可以。

无需配置、配置或应用安全补丁的服务器👏

#3. 无服务器打包

部署 Lambda 函数(包括其所有依赖项)时,其大小限制为 52MB。如果您最近编写过一个不错的 Node.js 项目,就会知道我们可以轻松突破此限制。注意:有一种从 S3 部署的方法可以绕过此限制,但我们尚未尝试过。

为了缓解这种情况,我们仅包含必需的依赖项,并通过排除未使用的文件(例如 README、包历史记录、测试、文档和示例)来缩减其大小。我们发布了一个名为lambdapack的包来实现这一点。它将使用 webpack 打包您的代码,以提供最新的 Node.js 和 JavaScript 功能,同时尽可能地减少 node_modules 的大小。lambdapack 与 apex/up 完全集成,因此可以优化构建过程并高效打包。

在 GitHub 上阅读有关lambdapack 的更多信息。

#4. 部署

这种方法效果惊人,每次部署都会创建一个新版本的 Lambda 函数。AWS 允许每个 Lambda 保留多个版本,并使用指向这些版本的别名。常用的别名包括:测试、暂存和生产。因此,新部署意味着上传新版本的 Lambda 函数,并将生产别名指向该版本。幸运的是,up 命令会自动通过 up deploy production 命令完成此操作。回滚只是将指针指向所需版本。

#5. 本地测试/开发

由于我们使用的是常规的 Node.js 服务器,因此在本地运行就相当于照常运行服务器。然而,这并不能完全模拟 AWS 基础设施,因为 AWS 基础设施与 AWS 存在诸多重要差异,例如:强制使用相同的 Node.js 版本、API 网关超时、Lambda 超时、与其他 AWS 资源通信等等。遗憾的是,最好的测试方式是在 AWS 基础设施本身上进行。

#6. 后台任务

对于文件处理或与第三方 API 同步等后台作业,我们保留了一组专用的 Lambda 函数,这些函数不属于 API 服务器。这些作业由 CloudWatch 调度运行,或作为对系统中事件的响应。

目前我们使用一个“兄弟”项目来处理这些后台作业 Lambdas — 使用开源apex/apex

这些函数仅在需要时运行,无需保持服务器正常运行来处理这些作业。无服务器方法的又一优势 🚀

#7. 日志记录

AWS 服务自带 CloudWatch 日志服务,其 UI、用户体验和用户体验都非常糟糕。虽然上层命令行提供了日志功能来查看日志,但还有很多需要改进的地方:警报、聚合日志等等。

我们的第一个解决方案是直接从 API 服务器记录到第三方日志服务(我们使用papertrail),但这可以使 Lambda 函数始终保持运行。

更好的方法是将 Lambda 日志流式传输到专用的 Lambda 中,由其负责将其发送到第三方日志服务。我们使用了cloudwatch-to-papertrail的更新版本。我还建议流式传输 API 网关日志,以便获取完整的信息。

#8. 环境变量和秘密

不要将您的机密提交给源代码控制。既然我们已经解决了这个问题,我们应该将它们加密存储在某个地方。AWS 针对此问题提供了一个解决方案,称为AWS 参数存储。您可以添加参数,选择是否加密它们,然后选择谁可以读取这些机密。我们将允许 Lambda 函数在开始运行时立即读取这些机密。由于 Lambda 函数是重复使用的,因此这只会在第一次调用 Lambda(第一个 API 调用)时发生。要进行设置,我们添加具有 /{env}/env_variable 层次结构的参数,例如 /production/MYSQL_PASSWORD。现在我们可以读取所有 /production 参数并将它们用作环境变量或仅将它们存储在内存中。

#9. 性能和冷启动

如果 Lambda 长时间未调用,它将冻结,下一次调用将需要启动新的服务器实例。这可能需要一些时间,具体取决于应用程序的复杂程度,有时在 600 毫秒到 2000 毫秒之间。目前除了 (1) 预热 Lambda(使用监控服务定期调用它,或使用 CloudWatch 再次执行预定的 Lambda 调用)和 (2) 提高 Node.js 应用程序的加载速度之外,没有其他真正的解决方案。希望 AWS 未来能够找到缩短冷启动时间的方法。

如果你的 API 服务器必须遵守 SLA,那么此时无服务器可能不太适合

#10. 禁止并行请求

在构建 Node.js 服务器时,我们习惯于借助事件循环和异步函数来处理多个请求。然而,在 AWS Lambda 中运行时,每个 Lambda 容器只会处理一个请求。

这意味着并行性是通过 API 网关生成多个 Lambdas 来实现的,而不是通过一个 Node.js 应用程序服务多个请求。

测试您的应用程序和用例以查看该模型是否适合。

结论

无服务器是运维领域的一次进步吗?对于DevOps,我们希望了解运维的工作原理;而对于无服务器,我们可以将运维责任委托给其他人(在本例中为 AWS),从而受益,我们可以称之为“无运维”。虽然我们失去了灵活性,但我们获得了很多功能、更轻松的心态以及将精力集中在代码和产品上的能力。

无服务器必将在未来几年占据主导地位,包括更具体的无服务器产品,如无服务器数据库、无服务器流媒体服务等。

对于我们开发者来说,这几乎是圣杯。构建它,发布它,它就能正常工作。

最初发布于https://hackernoon.com/lessons-learned-a-year-of-going-fully-serverless-in-production-3d7e0d72213f

文章来源:https://dev.to/ketacode/lessons-learneda-year-of-going-filled-serverless-in-product-3mh8
PREV
从 Mock Service Worker 请求处理程序生成一个 HTTP 服务器。
NEXT
Big O,代码效率分析