谈论无服务器架构远远超出了像AWS lambdas这样的功能即服务(FAAS)。
Lambdas如此有吸引力的两个原因是它们的自动缩放(输入和输出)能力和按使用付费的定价模式。为了利用这些功能并实现无服务器架构的全部优势,我们需要我们的其他基础设施组件具有相同的灵活性。
在Theodo,我们喜欢无服务器,并在越来越多的项目中使用这项技术。一些服务和模式开始广泛使用。因此,我们决定分享我们的Web应用程序架构最佳实践。如果您是新接触无服务器,并且正在寻找回答这些问题的高级指南,那么您来对了!
直接而残忍的剧透(不要害怕,我们将深入每一个方面):
在上图中,块表示在大多数无服务器体系结构中都可以找到的典型且边界清晰的域或技术特性。它们不一定代表微服务,也不一定代表CloudForformation行话中的堆栈(我们将在下面讨论这一点)。
我们的目标是拥有一个健壮的、完全托管的系统,并提供舒适的开发体验。为了实现这一目标,我们将采取以下措施:
云的竞争是激烈的:AWS、GCP、Azure、IBM Cloud、阿里巴巴云,它们都有一些令人惊叹的产品,并且正在以前所未有的速度发展。Ben Ellerby比较了本文中排名前3位的提供商:我们青睐AWS解决方案。它们在无服务器方面是最先进的。借助AWS解决方案,我们尽可能接近完全无服务器架构。为了说明这一点,在本文的下一部分中,我们将详细介绍构成我们的体系结构块的每个AWS服务。
JavaScript是世界上最流行的编程语言之一,因此它有一个相当大的社区(参见那些GitHub统计数据)!根据Datadog的观察,无服务器世界与此没有太大不同,目前所有部署的lambdas中有39%运行JavaScript,尽管Python领先47%。TypeScript使语言更上一层楼,增加了一层很好的额外保护。最后,lambdas中的JavaScript适用于绝大多数用例!
它执行大部分基础架构as Code(IAC)繁重任务(在CloudFortification之上)。定义一个响应HTTP事件的Lambda,无服务器框架将自动部署相关的API Gateway资源和相应的路由以及新的Lambda。当我们达到框架极限,并且想要更复杂的服务配置时,我们只需添加一些CloudForment即可。
自豪的广告:我们非常相信Theodo的无服务器框架,因此我们决定成为官方合作伙伴!
Lambda是一个函数。它只有一项工作,而且做得很好。我们的前端需要检索项目列表吗?为它做一个Lambda。我们需要在用户注册后发送确认电子邮件吗?再为它做一杯兰布达。当然,一些特定的代码(如数据实体)可以在专用的实用程序文件夹中分解和共享,但请密切关注此代码,因为任何更改都会影响所有相关的lambdas,而且lambdas可以独立测试和部署,因此我们可能会遗漏一些东西(此处为拯救而键入的脚本)。
为了不让团队互相践踏,不想有一个巨大的Package.json和serverless.yml(CloudFortification有200个资源限制),疯狂的长时间的CloudFortification部署时间,为了在我们的代码库中发现自己更好,并在我们的lambda之间强制执行明确的责任:我们定义边界,在Micro-Services中拆分我们的项目。本·埃勒比(Ben Ellerby)在这里写到了一种名为EventBridge Storming的研讨会,它帮助定义了这些界限。
在我们的单存储库中:一个微服务=一个CloudForformation栈=一个serverless.yml+Package.json。另外,微服务控制其自己的未与其他微服务共享的数据实体。
我们在前面建议使用完整的JavaScript,但是您可能希望使用另一种语言,或者您可能希望逐步迁移到JavaScript中的无服务器:在无服务器中微服务的极端优势在于,您可以非常容易地在体系结构中混合各种技术,同时仍然维护具有微服务之间不可知接口的简单而连贯的体系结构。
这些微服务需要完全独立,如果一个服务出现故障,或者如果我们在另一个服务上做出突破性的改变,那么对系统其余部分的影响应该尽可能有限。为了帮助实现这一点,lambda仅通过EventBridge(一种无服务器事件总线)相互通信。在本文中,Ben Ellerby(又是他)详细介绍了为什么EventBridge如此有用。
现在我们已经设置了上下文,让我们回顾一下上面令人望而生畏的图表中显示的每个体系结构块,详细说明在AWS中最容易找到的无服务器服务是什么。
我们闪亮的无服务器后端必须以某种方式满足前端的需求。为了简化与AWS相关的前端开发,我们利用了Amplify。
Amplify有几样东西:一个CLI工具、一个IAC工具、一个SDK和一组UI组件。我们利用前端JS SDK来更快地集成通过其他IAC工具(如无服务器框架)部署的资源(例如,用于身份验证的Cognito)。
今天的大多数网站都是单页应用程序(SPA),它们是功能齐全的动态应用程序,打包在用户浏览器首次访问URL时下载的一组静态文件中。在AWS环境中,我们将这些文件托管在通过CloudFront(内容交付网络(CDN))公开的S3(文件存储)上。
话虽如此,趋势显然是倾向于像Next.js这样的服务器(较少)端呈现(SSR)网站。为了在无服务器中建立SSR网站,我们利用了CloudFront中的lambda@Edge。这允许我们使用lambdas进行服务器端渲染,尽可能靠近我们的最终用户。请阅读这篇文章以深入探讨该主题。
对于我们的网站,我们想要比原始的自动生成的S3URL更好的东西,为此,我们使用证书管理器生成证书并将其绑定到CloudFront,并使用Route 53管理我们的域。
现在,我们的网站必须与后端联系才能检索和推送数据。为此,我们使用API Gateway来处理HTTP连接和路由,为每个路由同步触发一个Lambda。我们的lambdas包含与DynamoDB通信的业务逻辑,以便存储和使用数据。
如上所述,我们是事件驱动的,这意味着我们可以快速回复用户,并且在后台继续异步处理请求。例如,DynamoDB公开的流可以异步触发Lambda对任何数据更改做出反应。大多数无服务器服务都有类似的功能。
DynamoDB本身就是一个巨大的主题,在本文中,Rob Cronin保证了与臭名昭著的NoSQL数据库相关的一些经典问题。
我们的体系结构是事件驱动的,所以我们的很多lambda是异步的,由EventBridge事件、S3事件、DynamoDB Streams等触发。例如,我们可以有一个异步Lambda,负责在成功注册时发送欢迎电子邮件。
故障处理在分布式异步系统中至关重要。因此,对于异步lambdas,我们使用它们的死信队列(Dead Letter Queue,DLQ),并首先将最终失败消息传递给简单通知服务(SNS),然后再将其传递给简单队列服务(SQS)。我们现在必须这样做,因为还不可能将SQS直接附加到Lambda DLQ。
使用异步操作,前端不再能在等待XHR响应时只显示加载器。我们需要来自后端的待定状态和数据推送。为此,我们利用API Gateway的WebSocket API,它为我们保持WebSocket连接处于活动状态,并且只触发消息上的lambdas。我写了一篇文章,深入分析了为什么我们选择WebSocket而不是其他解决方案,以及如何实现它。
S3不是处理来自Lambda的文件上传流,而是让Lambda生成签名的(安全的)上传URL,我们的前端将使用该URL将文件直接上传到S3。与大多数AWS服务一样,最好的部分是另一个异步Lambda可以侦听S3文件更改事件来处理任何后续操作。
Cognito拥有我们需要的一切:身份验证、用户管理、访问控制和外部身份提供者集成。虽然大家都知道它使用起来有点复杂,但它可以为我们做很多事情。像往常一样,它有一个专用的SDK来让lambdas与它交互,并且可以分派事件来触发lambdas。
在我们的示例中,我们演示了将本地Cognito授权器绑定到API Gateway路由的可能性。我们还公开了一个用于刷新身份验证令牌的Lambda和另一个用于检索用户列表的Lambda。
不过需要警告的是,Cognito还不是用于管理整个用户实体的GoTo数据库,有一些限制,比如您可以拥有的属性数量。如果您需要一定的灵活性,您会更喜欢将自定义属性存储在DynamoDB中。
在某些情况下,我们的逻辑和数据流可能会变得相当复杂。AWS没有直接在lambdas中手动操作此流程,因此很难跟踪和组织正在发生的事情,而是提供了一项专为我们提供的服务:Step Functions。
我们通过CloudFortification声明我们的状态机:每个后续步骤和状态、每个预期或意外的结果,并将一些本机操作(如等待或选择)或Lambda(在几个集成中)附加到这些步骤。然后,我们可以通过AWS界面看到我们的机器实时、可视地(带有日志)运行。在每个步骤中,我们都可以定义重试和失败处理。Ben Ellerby在本文中进一步详细介绍了该服务。
举一个更具体的示例,假设我们要发送带有SaaS的电子邮件活动,并确保此活动已发送:-步骤1-Lambda:要求SaaS发送电子邮件活动并检索活动ID-步骤2-任务令牌Lambda:从步骤函数获取回调令牌,将其链接到活动ID,然后等待来自SaaS的回调-步骤3(在流程之外)-Lambda:由活动状态的钩子从SaaS调用。使用关联的回调令牌恢复具有活动状态的流程-步骤4-选择:根据状态,如果活动尚未成功,请返回步骤2-步骤5(最终)-Lambda:在活动发送时更新我们的用户。
Identity&;Access Management(IAM)可帮助我们精细管理任何AWS访问,无论他们是开发人员、CI/CD管道还是相互调用的AWS服务。它一开始让人望而生畏,但它的优势是相当先进和精致,要求我们好好考虑特定的“消费者”应该被允许做的每一个微观行为。这意味着我们的基础设施的每一层都默认受到保护。本·埃勒比(Ben Ellerby)在Nashville的Serverless Days上谈到了这个话题。
对于非常敏感的数据,如SaaS API密钥,我们将其安全地存储在Systems Manager的Parameter Store中。并从我们的Serverless和CloudForms文件中请求它们,甚至在我们的代码中使用相关的SDK请求它们。值得一提的是,Secrets Manager也做类似的工作。密钥管理服务(KMS)可帮助我们管理加密密钥。
Cloudwatch是事实上的监控服务。所有AWS服务都有基本的自动指标和日志发送到CloudWatch,为我们提供一些基本信息。我们可以走得更远:发送自定义指标和日志、创建仪表板、触发阈值警报、进行复杂查询以挖掘数据并将其显示在自定义图形中。
我们仍在寻找其他选择。以X-Ray为例,它的目标是通过我们的整个分布式系统端到端地跟踪请求,然后以非常直观和动态的方式表示它。只是目前这个跟踪丢失了,因为像EventBridge(它是我们架构的中心)这样的一些服务还不受支持。另一项服务ServiceLens建立在X-Ray和CloudWatch之上,看起来棒极了。也有一些很有前途的外部(对AWS)解决方案,如Thundra、Epsagon或Lumigo,但我们还没有机会完全试用它们。
Theodo自豪地将它的工具添加到生态系统中:如果您想要改进您的本地开发和可观察性,您绝对应该尝试Serverless-Dev-Tools。
无服务器是一种成功的承诺,我们想帮助您冒险一试
无服务器世界发展很快,非常快。进入它感觉就像是发现了一个全新的宇宙,充满了可能性,在那里一切都有待建造,这是令人兴奋的!
在Theodo,我们每周都会发现新的服务、工具和模式。这就是为什么我打算让这篇文章尽可能保持新鲜和最新,以便跟上步伐并分享我们当前的最佳实践。所以,请不要犹豫在推特上关注我,接下来还会有更多的投稿。
现在您了解了无服务器体系结构的基础知识,我们打算演示与更经典的体系结构相比,它是多么的便宜!因此,我们开始为此建造一个成本计算器。输入2到3个输入,您将看到它应该花费多少钱。如果有兴趣,请在推特上联系我。当然,在接下来的几周里,我会在推特上谈论这件事。
我希望这篇文章能给你一些答案!我非常乐意回答您可能有的任何问题,并听取您的反馈来改进上面的建议。