您当前的位置:首页 > 互联网百科 > 云计算

“神奇”的 AWS 无服务器开发体验

时间:2022-04-27 12:05:00  来源:  作者:InfoQ
“神奇”的 AWS 无服务器开发体验

 

当开发者想要开发无服务器和云原生应用时,一个常见的问题是:这方面的开发体验到底怎么样呢?这个问题很很重要,因为良好的开发体验和快捷的反馈通道会让开发者更开心、更有生产力,从而能够快速交付特性。

 

由于我们在建立 PlAIn 时有意缩小规模,所以我们必须有出色的开发体验。我们需要确保公司聘请的少数几位工程师能够在保持高质量的同时快速交付产品特性,产生最大的影响力。

 

2021 年我们有了时间去思考这个问题的解决方案,因为 Plain 是从头开始建立的。在我们选择常用的技术栈时,一方面要考虑到公司每天都会做变更,另一方面我们希望基础平台能够支持未来 5-10 年的业务成长与成就。这意味着平台应该能以较低的成本大规模运行我们的服务,而不需要专门划分出一个部门来管理自主研发的基础设施。

 

作出这些决策背后的理由肯定需要单独写文章来谈了,不过我们最终决定完全投入无服务器和云原生、全栈 TypeScript,并使用 AWS 作为我们的云供应商,因为它足够成熟也非常流行。我们认为,使用 AWS 的专有服务是一种可以接受的供应商锁定权衡,因为相比更换云供应商的自由度来说,从这一决策中获得的价值是更高的。我确实看到过一些公司花了大量精力去尝试做跨云(cloud-agnostic,云不可知),但实际上并没有从中得到任何现实收益。

无服务器开发的独特之处

 

无服务器应用程序的开发和测试工作有一些独特的要素。与传统开发相比的一大区别在于,你最终会使用大量云服务,并会尽量把责任卸载给无服务器解决方案。

 

就 AWS Lambda 而言,这意味着你最后往往会使用 API Gateway、DynamoDB、SQS、SNS、S3、EventBridge、ElastiCache 等来构建你的应用。使用这么多服务需要开发、测试和部署大量配置、权限和基础设施。如果你只关心你的 lambda 代码的测试工作,那么就会略过很大一部分特性。如果你不验证你的基础设施,可能会遇到以下情况:

 

  • 缺少一个 SQS 或 Lambda 函数的 S3 trigger
  • 缺少一个将事件路由到正确目标的 EventBridge 规则
  • 使用一个新的 AWS 服务时缺少 Lambda IAM 角色更新
  • API Gateway 中的 CORS 或授权器配置不正确

 

你要回答的一个最重要的问题是:你想要什么时候发现这些错误

 

  1. 在编写和运行你的测试时?
  2. 在进行特性开发和开发人员手动尝试他们的特性时?
  3. 在你通过一些 E2E 集成测试套件运行的持续集成中?
  4. 在一个共享的部署环境中,如开发或暂存?
  5. 或者在最坏的情况下:在生产环境中?

 

我们的选择是越早越好:在编写和运行测试时。这意味着,“你应该 mock 云的依赖项还是拥抱云“这个争论其实并不是一个问题。如果让我们的 Lambda 使用 AWS mock 或一些 localhost 仿真,在部署时还是很难做到无条件正常运行。Gareth McCumskey 的“为什么无服务器的本地部署是一种反模式”这篇博文为“模拟还是上云“的争论给出了很好的答案,我强烈推荐大家阅读。

 

云端开发带来的最大影响是需要互联网接入来编写代码。虽然这对某些公司或人们来说可能是一个不可接受的权衡,但对我们这家远程优先的公司来说,我们本来就需要互联网接入来与同事沟通,因此很少会出现无法接入网络的情况。

 

本着我们希望进行云端开发,而们开始评估各种工具和技术,以找出适合我们的方法。

神奇的堆栈

 

那么,我们神奇的 AWS 无服务器开发体验是什么样子的呢?从高层来看,以下内容构成了开发体验的关键部分:

 

  • 每位开发人员都有自己的个人 AWS 账户
  • 用 AWS CDK 来开发我们的基础设施,用无服务器栈(SST)来获得非常快速的反馈通道
  • 编写明显多于单元测试的集成测试
  • 全栈 TypeScript

 

采用这些技术和实践产生了相当出色的开发体验。

个人 AWS 账户

 

完全转向无服务器后,每位开发人员就必须有自己的个人沙盒 AWS 账户。如前所述,构建大多数特性时,仅仅编写代码是不够的,还有大量的基础设施需要开发、修改和测试。拥有个人的 AWS 账户让每位开发人员都可以进行实验和开发工作,而不会影响其他工程师或像开发或暂存这样的共享环境。再结合我们强大的基础设施即代码,每个人都可以拥有一份生产环境的个人克隆版本。

 

你可能会想:这不是很贵吗?我们是不是要向 AWS 支付数百美元?不,无服务器解决方案不是这样的!真正的无服务器解决方案都是按使用量付费的,所以如果你的 AWS 账户没有任何活动(例如在工程师不工作的晚上和周末),那么你就不会支付一分钱。这方面有一些例外,如 S3 存储、DynamoDB 存储、RDS 存储、Route53 托管区等费用,但它们一般没几个钱。

 

例如,Plain 公司 1 月份为我们的 7 个开发者账户支付的账单总计 150 美元,而我们每个人都有自己的生产环境克隆,因此开发速度大幅提升,相比之下这点费用真不算什么。通常情况下,每位开发人员涉及的最大成本是我们的关系数据库:Amazon Aurora Serverless v1 PostgreSQL。在开发过程中,当它收到请求时会自动扩展,并在无活动 30 分钟后降至零。

“神奇”的 AWS 无服务器开发体验

 

每个开发者账户的 AWS 用量总账单。

“神奇”的 AWS 无服务器开发体验

 

我的 AWS 账户的使用量明细

(注意:CloudWatch 的高额费用是由于在 1 月份评估了可观察性工具和平台)

AWS CDK 和 SST

 

由于我们的所有特性都相当依赖云资源,因此将我们的基础设施定义为代码和版本控制是一个硬性要求。我们最初研究了 Terraform、Pulumi、Serverless Framework、AWS SAM 等工具,但它们要么要求我们学习新的编程或模板语言,要么开发者对整个特性生命周期的体验达不到我们的期望。

 

2021 年 3 月,我们偶然发现了Serverless Stack(SST),当时它还是 0.9.11 版本。他们的实时 lambda 重载特性和建立在 AWS CDK 上的特点一下子就吸引了我们。SST 和 AWS CDK 原生支持 TypeScript,所以它很好地满足了我们对 TypeScript 全栈的渴望。

 

实时lambda开发允许我们编写 Lambda 代码,并使用实时的 AWS 服务运行我们的集成测试,反馈循环只需 2-3 秒。SST 将你的 lambda 替换成一个垫片,通过 Websockets 将所有 Lambda 调用代理到你的本地开发者机器上,它可以调用其他 AWS 服务并返回响应。本地运行时使用 AWS Lambda 执行角色的权限,并对真正的服务调用 AWS API,所以当变更部署到生产环境时我们会很有信心它能正常运行。总的来说,这意味着与 mocking 或仿真相比,我们能极快地发现基础设施问题。

“神奇”的 AWS 无服务器开发体验

 

实时 lambda 开发架构概述。(来源:docs.serverless-stack.com)

 

这种设置的好处是我们可以轻松做到真正的全栈开发。我们可以将 React 前端应用指向个人 AWS 账户部署的 API Gateway URL,并同时改变前端和后端,两个代码库都可以实时重载。鉴于一切部署都在使用与生产环境相同的 AWS 服务,我们的前端应用程序不需要调整就能完全正常工作。

 

虽然选择在一个(当时)相对未知的工具上建立我们的后端堆栈是有一点风险的,但我们知道我们有 AWS CDK 这个逃生舱口。如果我们遇到 SST 不支持或我们不喜欢的东西,还可以使用非常成熟的 AWS CDK 构造。这使我们在 SST 的奇妙开发体验与 AWS CDK 的成熟度、特性丰富度和第一方支持之间取得了最佳平衡。

 

Serverless Stack 也有一些非常棒的特性,比如说:

 

  • 在 Lambda 代码中加入断点,在本地 IDE 中调试。这得益于-increase-timeout 标志,该标志将所有 Lambda 超时时间增加到 15 分钟。如果你对此感兴趣可以查看这里的文档或视频。
  • 检测基础设施变更并提示你部署它们,即尽可能地接近实时重载。部署仍然需要一些时间,因为在底层它是 Cloudformation。
  • 一个基于 Web 的控制台(SST控制台),可以可视化你的堆栈、Lambda、S3 桶,还有回放单个 Lambda 事件的能力。
  • 自动导出已删除的Cloudformation堆栈输出:我们以前曾多次遇到这种情况,有时我们注意到的时候已经太晚了,所以很麻烦。
  • 一个不断增长的构造库

 

每当我们遇到问题、有疑问或特性请求时,SST 的Slack社区都能提供很大帮助。Frank、Jay、Dax和社区总是很乐意帮助我们。我强烈建议大家尝试一下 SST,因为很难找到如此好用的东西了。

测试

 

一开始我们就有一个野心,就是对我们的测试套件能有充分的信心。如果我们的 CI 是绿色的,那么应该就可以安全地将该变更部署到生产环境中——这正是我们在合并到主分支时所做的事情。为了实现这一目标,我们决定将测试工作集中在一个强大的集成测试套件上,而不是对单个 lambda 函数或小代码块分别进行单元测试。这似乎是不好的实践,或者是违背了传统的测试金字塔原则。但当我们遇到像无服务器这样的阶梯式创新时,有必要对现有的实践提出质疑,看看这些实践是否仍那么有意义。

 

要明确的是:我们确实会在有意义的地方写单元测试。如果我们有一些业务逻辑或计算,那么就会写一个详尽的单元测试套件。一个例子是我们的核心客户状态机对所有可能的状态和状态转换都有单元测试。但是像 SQL 查询、AWS API 调用或我们的 GraphQL 请求这样的单元测试是绝对不可能写的,因为它不会带来什么实际的保证。你最终要测试的是大量的实现细节,而维护高质量的 mock 或仿真需要投入很大资源,并不值得。

 

拿数字说话,我们目前的测试套件比例是 30%单元测试和 70%集成测试用例。

“神奇”的 AWS 无服务器开发体验

 

我们的集成测试是以一种合理的方式设计和编写的,它们速度够快,主要测试行为而非实现。这意味着我们尽量避免断言内部实现细节,例如 DynamoDB 或 RDS 中存储的数据。相反,我们专注于验证外部(从 Lambda 的角度)可见的行为,如 API 响应或正在发布的事件。对于我们的事件,我们的原则是只测试一个已经发布的事件,而不是断言所有下游消费者。我们为每个消费者编写单独的集成测试。这也要求我们在代码中保持合理的领域边界,以确保每个领域都可以独立测试。

“神奇”的 AWS 无服务器开发体验

 

集成测试的边界

 

这种编写测试的方式也有一个好处,就是能够针对共享环境运行。我们目前有一个完整的集成测试套件,在部署后合并到主环境时针对我们的开发环境运行,并按计划检测 flaky 测试。没有什么能阻止我们在生产环境中也运行这些完全一样的测试。理论上,我们可以删除 100%的代码,用 Delphi 重写所有的 Lambda,只要我们的集成测试套件通过就可以把它发布到生产环境。(注意:我们还没有尝试过这件事,也不打算在短时间内这样做)。

 

一个典型的 GraphQL API 查询或突变的集成测试大致上会做以下工作:

 

  1. 从认证的用户池中请求一个用户(我们遇到了一些配额和身份提供者的限制)
  2. 创建一个新的工作区,以便有一个干净的状态
  3. 设置测试的状态,如创建一个客户、发送一个聊天信息等
  4. 进行 GraphQL 查询
  5. 断言 GraphQL 响应
  6. 在突变的情况下:断言任何应该被发布的事件

 

describe('create issue mutation', () => {
  it('should create an issue', async () => {
    // Given: workspace + customer + issue type
    const testWorkspace = await testData.newWorkspace();
    const ctx = await testData.testAggregateContext({ testWorkspace });
    const issueType = await issueAggregate.createIssueType(ctx, {
      publicName: 'Run of the mill issues',
    });
    const customer = await customerAggregate.createCustomer(ctx, factories.newCustomer());
    // When we make GraphQL Mutation
    const res = await testWorkspace.owner.graphqlClient.request(CREATE_ISSUE_GQL_MUTATION, {
      input: { issueTypeId: issueType.id, customerId: customer.id },
    });
    // Then:
    // 1. Expect a successful response:
    expect(res).toStrictEqual({
      createIssue: {
        issue: {
          id: jestExpecters.isId('i'),
          issueType: { id: issueType.id },
          customer: { id: customer.id },
          status: IssueStatus.Open,
          issueKey: 'I-1',
        },
        error: null,
      },
    });
    // 2. Expect an event to be published:
    await testEvents.expectEvents(testWorkspace, [
      jestExpecters.standardEventStructure({
        actor: testWorkspace.owner,
        payload: {
          eventType: 'domain.issue.issue_created',
          version: 1,
          issue: res.createIssue.issue,
        },
      }),
    ]);
  });
});

复制代码

 

一个典型的 EventBridge 事件监听器集成测试会:

 

  1. 设置任何所需的状态(这在很大程度上取决于具体的 Lambda)。
  2. 在总线上发布一个 EventBridge 事件
  3. 等待并期待副作用的出现,这可能是:

另一个 EventBridge 事件被发布

数据存储中的状态被更新(如 DynamoDB、RDS、S3)

 

如果你曾写过任何集成测试,一定会在脑子里大喊:运行这些东西一定很慢!它们肯定比单元测试慢,但也不是慢得让人无法忍受。由于我们使用的所有服务都是无服务器的,而且我们确保集成测试有 0 个共享状态,所以我们有能力并行运行所有的测试。我们还没有达到这样的优化程度,但举例来说,我们的 CI 并行度为 40,在 2 分钟内就能在 110 个测试套件中运行 656 个测试用例,对我们应用的每个角落进行详尽的集成测试。

“神奇”的 AWS 无服务器开发体验

 

来自我们 CI 的集成测试套件结果

 

集成测试的不稳定性是我们积极解决的另一个问题,为此我们在工作周内按计划运行测试。一旦遇到测试失败,我们就会跳出来,追踪问题的根源。这也需要我们重新思考,并把某些东西(如 GraphQL 订阅)的测试调整成一种稳健和可靠的方式。

 

我们才刚刚开始研究我们的集成测试设置,这个话题绝对值得另起一篇文章。也就是说,鉴于我们的 API 是产品的一个关键部分,对每一个 GraphQL 查询和突变的整合进行测试是至关重要的。我们认为,就算测试套件稍慢一些,但对特性或变更能正确运行有更高的信心就足够值得了。

全栈 TypeScript

 

虽然使用全栈 TypeScript 并不是在 AWS 上拥有良好开发体验的严格必要条件,但它确实让我们的团队获得了更高的效率。无需学习新的语言就能在前端、后端和基础设施代码之间来回切换,这对团队的每位成员来说都是非常宝贵的体验。

 

在开发后端代码时你仍然需要学习 AWS 服务,但这在使用任何东西时都是很自然的需求。你同样需要了解 css/html 来开发前端 Web 应用。有了 TypeScript 中的 SST 和 CDK,在你弄清楚自己想使用哪些 AWS 服务后,TypeScript 类型和编辑器的自动完成特性会引导你定义正确的基础设施。

 

我们的大部分后端代码库都在一个单一的单体仓库中,并使用了一些库,如pnpm、zod、true-myth、swc,来让我们的代码更容易编写——未来的文章中会有更多介绍。

实践

 

那么,这在实践中是什么样子的呢?让我们来看看一个变更该怎么做:

“神奇”的 AWS 无服务器开发体验

 

(视频见原文)

 

在这个例子中,我们通过我们的核心 GraphQL API 在 Plain 中创建了一个工作空间。这验证了 E2E 的 API 调用是有效的:

 

  • 用户从我们的身份提供者那里获取了一个有效的 JWT
  • AWS API Gateway 处理了 GraphQL 请求并验证了 JWT 的有效性。
  • GraphQL Lambda 在我们的 Aurora Serverless PostgreSQL 数据库中创建了一个新的工作区,并向 EventBridge 发布了一个事件
  • 这验证了 Lambda 具有正确的 IAM 权限,可以从 PostgreSQL 中读/写并发布到 EventBridge
  • 一个成功的响应被返回到客户端

总结

 

有了这些技术和实践,我们就可以专注于发布特性了:

 

  • 由于每个人都有自己的 AWS 账户,所以不会影响到其他工程师
  • 有了 SST 和实时 lambda 开发,我们可以使用实时的 AWS 服务实现快速的反馈循环,知道它在部署时可以正常工作
  • 利用 CDK 轻松开发无服务器基础设施
  • 因为有我们的集成测试,所以我们对正确性有很高的信心
  • 在前端、后端和基础设施之间切换时,不必学习不同的编程或模板语言

 

我们还能做的更好吗?改进的余地肯定还有,但我认为这已经是相当神奇的体验了!如果你有任何问题,或者知道如何让我们的堆栈变得更好,请在 Twitter 上 @builtwithplain 或我 @akoskrivachy,与我们联系。

 

如果你对我们的神奇技术栈感兴趣,请在 Plain 的工作页面上查看我们目前的职位空缺。

 

原文链接:
https://journal.plain.com/posts/2022-02-08-a-magical-aws-serverless-developer-experience/



Tags:无服务器开发   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
“神奇”的 AWS 无服务器开发体验
当开发者想要开发无服务器和云原生应用时,一个常见的问题是:这方面的开发体验到底怎么样呢?这个问题很很重要,因为良好的开发体验和快捷的反馈通道会让开发者更开心、更有生产...【详细内容】
2022-04-27  Search: 无服务器开发  点击:(250)  评论:(0)  加入收藏
▌简易百科推荐
生成式AI:云计算的关键之战
“美国有一家铁路公司,过去两年我们一直在交谈。终于,他们这次打电话给我们,希望迅速推进上云迁移。”近日,亚马逊云科技全球客户技术支持与服务副总裁Uwem Ukpong向记者谈及企...【详细内容】
2024-04-08    21世纪经济报道  Tags:云计算   点击:(15)  评论:(0)  加入收藏
云计算:数据存储与处理的革命性技术
当我们谈论“云计算”时,我们实际上在讨论的是一种基于互联网的新型计算模式。云计算允许用户通过网络访问并使用存储在数据中心(也称为“云”)的共享计算资源。这些资源可以包...【详细内容】
2024-03-04  徐文轩    Tags:云计算   点击:(19)  评论:(0)  加入收藏
云服务2023:阿里云急转弯,腾讯云被集成,百度云加速赶
文|奇偶派回望2023年伊始,伴随着特殊时期的结束和国家数字化转型相关政策的落地,叠加以ChatGPT为代表AI新增量的出现,市场对中国云服务行业的表现普遍给予了较高的期待值,希望其...【详细内容】
2024-01-09    奇偶派  Tags:云服务   点击:(41)  评论:(0)  加入收藏
云计算这一年:冰与火之歌奏响
©⾃象限原创作者丨程心在电影《奥本海默》中,当奥本海默第一次见证了原子弹的爆炸成功,巨大而刺眼的白光穿越了200英里的距离和层层防护,那一刻世界仿佛被抽离,人们见证了...【详细内容】
2023-12-26    自象限  Tags:云计算   点击:(41)  评论:(0)  加入收藏
为什么 Traefik 是云原生首选网关?
根据 Traefik Labs 团队对于 Traefik 在云原生生态中的定位:云原生反向代理和负载均衡器及网关解决方案。一、从生态拥抱视角看:Traefik 的发展前景从云原生生态视角来看,Traef...【详细内容】
2023-11-29  架构驿站  微信公众号  Tags:网关   点击:(67)  评论:(0)  加入收藏
2024年的云趋势:云计算的前景如何?
适应复杂的生态系统、提供实时功能、优先考虑安全性和确保可持续性的需求正在引领云计算之船。多样化的工作负载允许探索通用的公共云基础设施范例之外的选项。由于需要降低...【详细内容】
2023-11-23    千家网  Tags:云计算   点击:(69)  评论:(0)  加入收藏
基于云的应用设计和部署:综合指南
什么是基于云的应用?基于云的应用是设计在云计算环境中运行的软件应用程序。在这里,应用及其相关数据不在本地计算机上存储和执行,而是在云中托管和操作。基于云的应用运行在...【详细内容】
2023-11-23  千家网  微信公众号  Tags:   点击:(65)  评论:(0)  加入收藏
云平台存储应急演练常见问题分析
相比于传统架构成熟的应急处置体系,业界关于云平台存储开展应急演练和管理方面则稍显欠缺。本文将梳理云平台存储应急演练与传统IT架构的区别,列举云平台存储常见的故障场景,并...【详细内容】
2023-11-21    IT168  Tags:云平台   点击:(69)  评论:(0)  加入收藏
阿里云 11.12 故障原因曝光
针对阿里云 11.12 的重大服务故障, 该公司发给客户的一份「官方故障报告」昨天在网上被广泛流传。事件回顾:阿里云严重故障,全线产品受影响(已恢复)影响范围1、OSS、OTS、SLS、MN...【详细内容】
2023-11-16    OSC开源社区  Tags:阿里云   点击:(113)  评论:(0)  加入收藏
云计算的五个网络要求
网络和云团队应该在其云策略中考虑带宽和延迟优化、安全性、网络冗余、服务质量和网络自动化等因素。云计算和SaaS架构的出现颠覆了整个IT行业,并扩展到了网络领域。能够从世...【详细内容】
2023-11-14    千家网  Tags:云计算   点击:(72)  评论:(0)  加入收藏
相关文章
    无相关信息
站内最新
站内热门
站内头条