防止无服务器崩溃的技巧
最近我参与了一些使用“无服务器”架构开发的服务的性能评估工作,这些服务都遇到了性能问题。与其讨论无服务器架构的种种优势,不如看看这篇文章,我会分享一些从实际案例分析中总结出的实用技巧,帮助你确保服务稳定运行并达到生产就绪状态。
提示 1:关注可观测性而非日志
作为工程师或负责监控服务的人员,轻松查找和修复问题的最佳方法是使用可观测性和无服务器监控工具,而不是仅仅关注日志。虽然 AWS 提供了一项名为AWS X-Ray分布式追踪的服务,但合作伙伴生态系统中还有更好的工具,例如Lumigo、Thundra、Instana等公司提供的工具。例如,Lumigo 相比其他工具具有一些关键优势X-Ray(感谢Yan Cui指出其中的一些优势):
- 自动仪表
- 支持流媒体
- 环境概览仪表板 - Lambda 函数调用、大多数错误、冷启动
- 问题页面显示了最近的故障,包括超时。
- 捕获每个 HTTP 请求的请求和响应
- 支持自动清理敏感数据
- 支持搜索特定交易
- 内置警报
尽管在逐步执行复杂的业务逻辑时,日志记录仍然有价值,但您很快就会发现,这些可观测性工具是您了解服务行为和当前状态的首选方法。
提示 2:指标警报
我以前参与编写的系统会使用ERROR日志级别记录故障。这些日志会被打包发送,然后由另一个组件抓取这些文件,并根据日志模式发出警报。遗憾的是,在云环境中仍然经常能看到这种做法。
我今天推荐的方法是使用指标。例如,当您的函数处理完毕后,Lambda 会将调用相关的指标发送到 CloudWatch Amazon Cloudwatch。您可以设置警报来响应这些指标的变化,Lambda 本身就提供了一系列调用、性能和并发指标。您还可以使用 CloudWatch 嵌入式指标格式创建自定义指标,并考虑您自身的特定上下文,这些指标也可以用同样的方式设置警报。
Yan Cui的这篇文章为配置常见 AWS 服务的警报提供了起点。
虽然可以将指标导入外部系统,但不应将其用于告警目的。这是因为指标导入的异步特性通常会导致延迟,到那时,您可能已经因为客户不满而得知错误信息了。
提示 3:关注异步
无服务器应用镜头部分Well Architected Framework指出:
您无法再使用同步事务来维持复杂的流程。您需要的服务交互越多,最终导致的调用链就越多,这可能会增加服务稳定性风险以及响应时间延长。
“分布式计算的八大谬误”中的前两个谬误是“网络是可靠的”和“延迟为零”。将同步 HTTP 调用串联起来会导致服务脆弱,容易崩溃。这促使 AWS 前杰出工程师 Tim Bray 指出:
“如果你的应用程序是云原生、大规模或分布式的,并且不包含消息传递组件,那很可能是一个错误。”
AWS 生态系统中提供了许多可用于解耦组件的选项。为了更好地理解事件、队列、主题和流之间的区别,建议观看Julian Wood的这篇技术讲座。
我个人非常高兴看到越来越多使用 EventBridge 提供的事件总线的事件驱动型应用程序得到应用。无需在组件间协调调用,您可以发布一个代表状态重大变化的事件,其他组件可以订阅这些事件并做出相应的响应。想要深入了解,可以先看看Sheen Brisals关于乐高如何采用 EventBridge 的Amazon EventBridge演讲和博客。
技巧四:掌握好时间安排
AWS Builders Library 上有一篇很棒的文章,讨论了“带抖动的超时、重试和退避”。
在设计服务时,您需要了解从前端到后端数据流中所有组件的超时设置和重试行为。如果 Lambda 函数是由默认超时时间为 29 秒且无法增加的 API 网关触发的,那么将 Lambda 函数的超时时间设置为 60 秒就毫无意义。
除了服务内部的超时设置外,SDK 中也存在超时设置。AWS SDK 的默认行为会根据所调用的服务和使用的特定驱动程序而有所不同,详情请参阅这篇知识中心文章。
在我查看的案例中,使用 AWS SDK for JavaScript 时都没有设置套接字超时。这意味着当遇到网络问题时,API 调用会挂起 120 秒。
技巧 5:了解你的设计模式
虽然我们强调应该关注异步通信,但有时你别无选择,只能进行同步调用。这可能是因为你依赖于外部接口。在这种情况下,如果外部 API 出现故障,最佳实践是立即关闭电路以响应调用客户端,同时在后台重试 API,直到电路恢复正常。这就是该Circuit Breaker设计模式的基础。Jeremy Daly为 AWS撰写了许多关于无服务器微服务模式的文章。
提示 6:优化您的服务
归根结底,你对所使用的编程语言和 AWS 服务了解得越多,就越有可能提供弹性、安全且高可用的服务。
从宏观层面来说,我将服务优化分解为三个主要方面:
a) 通用优化
在使用 AWS Lambda 函数时,随着时间的推移,已经涌现出一系列优化技巧。AWS 发布了一套关于如何使用 AWS Lambda 函数的最佳实践。
深入了解 AWS Lambda 生命周期及其相关配置至关重要。例如:
- 如果使用 Node.js,请确保启用 HTTP Keep-Alive。
webpack使用诸如或之类的工具减小封装尺寸,以缩短冷启动时间。esbuild- 使用Alex Casalboni
AWS Lambda Power Tuning开发的工具来确定正确的内存/电源配置和指令集架构 - 在适当情况下,使用预留并发数来限制函数的影响范围。我见过一些例子,在批量加载期间未设置此限制,导致整个账户的所有 AWS Lambda 并发执行次数都被消耗殆尽。
- 在函数处理程序之外初始化 SDK 客户端和数据库连接
b) 减少网络呼叫
每次通过网络发起呼叫都会引入额外的延迟和错误处理。这些呼叫应该尽可能减少,以下两个例子可以作为具体说明。
第一个调用是先向 DynamoDB 发送请求,检查记录是否存在,然后再发送请求添加一个项目。在这种情况下,使用条件表达式使得只需一次调用即可完成所有操作。
第二个问题涉及多次调用 DynamoDB 来连续检索数据。在这种情况下,问题出在糟糕的模式设计上。DynamoDB 中单表设计日益普及,正是出于减少所需调用次数的考虑。
如果您计划在生产环境中使用 DynamoDB,那么Alex DeBrie所著的《DynamoDB 之书》是必读之作。
c) 尽可能并行化
虽然我们希望减少网络调用次数,但有时别无选择。在这种情况下,您应该考虑并行运行。这样做可以减少函数执行时间和调用方的延迟。在异步 JavaScript 中,可以轻松地并行运行任务,并使用 `.` 等待所有任务完成Promise.all。
注意,有些优化措施最好始终执行,因为它们几乎不需要任何成本。而另一些优化措施则会占用工程师的时间来设置、运行、分析和重构。因此,重点关注调用频率最高的服务或函数,或者那些被可观测性工具标记为性能不佳的服务或函数是明智之举。务必谨慎对待过度优化,切勿忽视工程成本。
提示 7:无服务器 ≠ Lambda
最后,请记住,这AWS Lambda并非万全之策。
最初推出时AWS Lambda,配置选项有限,因此使用起来非常简单。现在,随着 Lambda 扩展、分层、最长 15 分钟超时时间和最高 10 GB 内存分配的增加,各种各样的用例都得到了拓展。然而,这通常会导致默认选择是编写新函数。如果您正在使用AWS LambdaLambda 编写 ETL 批处理作业,需要将文件分块处理并分配 15 分钟超时时间和 10GB 内存,那么很可能存在更好的“无服务器”解决方案,例如 Lambda AWS Glue。
与其编写一个需要管理和维护的函数,不如根本不编写函数,这样我们就朝着“优先考虑配置而非代码”的方向发展。
在上一届 AWS re:Invent 大会上,AWS 发布了目前处于预览阶段的AWS Glue Elastic Views。它无需编写自定义函数即可合并和复制数据。最近,AWS 又宣布Step Functions 已与超过 200 项 AWS 服务直接集成。同样,这也无需编写自定义代码。
文章来源:https://dev.to/aws-heroes/tips-to-prevent-a-serverless-wreck-15af
