Express.js 应用程序无服务器,使用 Lambda 或函数 - 好主意吗?

Posted

技术标签:

【中文标题】Express.js 应用程序无服务器,使用 Lambda 或函数 - 好主意吗?【英文标题】:Express.js app serverless, using Lambda or Functions - a good idea? 【发布时间】:2021-03-23 18:57:23 【问题描述】:

免责声明:我承认这更像是一个宽泛的最佳实践问题,而不是一个特定的编程问题,但是,我相信 SO 群体是它的最佳受众。我知道这个类似的问题 (Should I be using Express.js in a Serverless app?),但答案似乎没有回答我的问题。

出于典型原因,我想将 Express.js 从 AWS Lightsail/EC2 迁移到无服务器,而 Lambda 是我的首选武器。然而,一个完整的框架连同其上的一个应用程序可能仍然被视为一个函数,因此可能不适合在 AWS Lambda 或 Google/Azure Functions 上运行。虽然我确信it is doable,但这是个好主意吗?这种设置不会降低效率并使会话状态等处理复杂化,最终违背无服务器功能的目的吗?

【问题讨论】:

【参考方案1】:

问题的答案取决于您当前和未来的需求。我认为您应该始终提前计划并确保您将实施的当前基础架构可以升级以满足未来的需求。

你应该问自己这些问题:

将来我想要一些 websocket 连接吗? 我的请求路由中是否需要任何代理? 随着时间的推移,我的应用程序会有多大? 我希望将来使用哪种 AWS 服务

可扩展性

在 lambda 中使用 Express.js 并不是一个好主意,原因有很多:

    您将为执行 Lambda 支付更多费用,因为它需要更多时间来运行,并且可能需要更多内存 延迟较高 进行小的修改意味着在 1 个 lambda 上重新部署所有应用程序代码,因此只有 1 个故障点。 通常情况下,应用程序的代码库会随着您添加更多功能而增加。维护那个单体存储库会很麻烦,而且由于可能遇到的错误,您的部署将比您想要的要少。

成本效益

Lambda 上的 Express.js 更昂贵,因为您需要使用 API Gateway REST API 而不是使用 API Gateway HTTP API 将任何方法代理到您的 lambda 中

HTTP APIs are up to 71% cheaper compared to REST APIs

延迟

Lambda 不会在没有服务器的情况下神奇地执行您的代码,即使他们按原样推销它。当事件发生时,AWS 将启动一个 docker 容器,等待它完全加载所有依赖项,然后运行您的处理程序。

使用 AWS EC2 或 AWS ECS 上的普通 Node.js 服务器,这是一次性成本,因为您的服务器始终在运行,并且您的所有依赖项都已加载但未加载到您的 lambda。

正如 AWS 所说:

这种方法 [Express.js 并将所有请求代理到您的 lambda] 通常是不必要的,而且通常最好利用 API Gateway 中提供的本机路由功能。在很多情况下,Lambda 函数中不需要 Web 框架,这增加了部署包的大小。 API Gateway 还能够验证参数,从而减少使用自定义代码检查参数的需要。它还可以防止未经授权的访问,以及更适合在服务级别处理的一系列其他功能。

Best practices for organizing larger serverless applications

如何将 Express 框架转换为计划 Lambda

为了简化您的生活,我建议您使用 SAM CLI。上手非常简单。

Install SAM CLI

如果您的 Express 应用遵循 MVC 模式。您只需要将服务文件放在核心逻辑所在的位置。

我喜欢用于 lambda 的文件夹结构如下

假设它是一个小型日历应用

──src-ts
    ├───handlers
    │       getEvent.ts
    │
    ├───tests
    │   │   getEvent.tests.ts
    │   │
    │   └───utils
    │           utils.ts
    │
    └───utils
            utils.ts
            validation.ts

您的处理程序返回 3 个东西很重要

    标头 (JSON) 状态码(数字) 正文(字符串化)

您还需要一个template.yml 文件来描述您的 lambda 所需的基础架构

AWSTemplateFormatVersion: 2010-09-09
Description: Describe the lambda goal

Transform:
    - AWS::Serverless-2016-10-31


Resources:
    # API Gateway
    LambdaAPI:
        Type: AWS::Serverless::Api
        Properties:
            StageName: StageName
            Cors:
                AllowMethods: "'POST, GET, OPTIONS'"
                AllowHeaders: "'*'"
                AllowOrigin: "'*'"


    # IAM Role
    LambdaRole:
        Type: AWS::IAM::Role
        Properties:
            AssumeRolePolicyDocument:
                Version: 2012-10-17
                Statement:
                    - Action:
                          - 'sts:AssumeRole'
                      Effect: Allow
                      Principal:
                          Service:
                              - lambda.amazonaws.com
            ManagedPolicyArns:
                - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
                - arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess
                - arn:aws:iam::aws:policy/AmazonAPIGatewayInvokeFullAccess

    GetEvent:
        Type: AWS::Serverless::Function
        Properties:
            Runtime: nodejs12.x
            Timeout: 180
            FunctionName: youLambdaName
            Handler: src/handlers/getEvent.handler
            Role: !GetAtt LambdaRole.Arn
            Events:
                Get:
                    Type: Api
                    Properties:
                        RestApiId: !Ref LambdaAPI
                        Path: /events/eventid
                        Method: GET

注意 我使用了打字稿,但在编译时它创建了一个 src 文件夹

一些资源可以更深入地帮助您:

https://aws.amazon.com/blogs/compute/going-serverless-migrating-an-express-application-to-amazon-api-gateway-and-aws-lambda/ https://dev.to/brightdevs/how-to-convert-an-express-app-to-aws-lambda--44gc https://medium.com/hackernoon/how-to-deploy-a-node-js-application-to-aws-lambda-using-serverless-ae7e7ebe0996 https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html

总结

在没有 Express 的情况下使用 lambdas 的好处是:

更好的可扩展性 成本优化 低延迟 可用性更高,因为每个业务逻辑都有多个 lambda,而不是一个运行所有逻辑

在没有 Express 的情况下使用 lambdas 的缺点是:

您需要修改现有代码 在开发逻辑时,您需要考虑 lambda 的初始化时间 当您想向 API 基础设施添加更多功能时,您需要学习 SAM yaml 模板并阅读 AWS 文档。

利用 AWS 基础设施,不要试图与之抗衡。所有 AWS 服务都以无缝且低延迟的方式协同工作。如果您想使用“无服务器”,您应该从基础架构中移除 Express。

【讨论】:

【参考方案2】:

如果按照您所说的功能运行有点繁重,您可能会考虑为您的应用创建一个 docker 映像并使用被认为是无服务器选项的 Fargate ECS 运行它。

【讨论】:

【参考方案3】:

将您的服务器划分为托管在 lambda 脚本上的小型微服务将大有帮助。

我已将我的服务器分解为几个微服务,以构建一个可扩展的系统。以下是您通常可以创建的提到的 lambda 函数,以使其具有成本效益和可扩展性

    用户数据管理 身份验证 用户特定的 Web 界面/API 核心逻辑 第三方集成

等等……

可扩展性:如果没有手动配置或不使用任何可以调整 EC2 或任何其他服务器上的可扩展性的第三方软件,您将无法获得自动可扩展性

成本效益:由于 lambda 函数具有高可用性和每次 API 调用的计费,您实际上可以从预算中获得更多收益。

安全性:将每个 Web 应用程序分解为不同的 lambda 函数将使您在为不同类型的用户提供访问权限以及为每个 Web 应用程序和负载均衡器配置 API 网关时提供更大的灵活性,这将是一个很好的安全层,除了身份验证系统。

您是否从头开始创建应用并不重要。服务器中包含的所有功能都将被分成小块代码,并且在构建它们时可以灵活地测试和运行每个应用程序。

有了 Express,我还没有看到这种灵活性和快速发展。

【讨论】:

以上是关于Express.js 应用程序无服务器,使用 Lambda 或函数 - 好主意吗?的主要内容,如果未能解决你的问题,请参考以下文章

在前端使用 fetch 从 express.js 服务器获取响应

如何使用 Express.js、GraphQL、客户端和服务器文件夹为 React 应用程序配置 Webpack?

存储 JWT 服务器端 express.js

在 Express.js 中刷新 JWT

使用历史模式通过 Express.js 服务 VueJS 构建

如何使用 express.js 在 Ajax 调用中实现 CSRF 保护(寻找完整示例)?