使用 AWS Lambda 和 Java 的无服务器 FaaS

位置:首页>文章>详情   分类: Java教程 > 编程技术   阅读(450)   2023-09-08 09:14:48

什么是无服务器架构?

无服务器架构在由第 3 方完全管理的临时容器中运行自定义代码。自定义代码通常是完整应用程序的一小部分。它也被称为函数。这为无服务器架构提供了另一个名称,即功能即服务 (FaaS)。容器是短暂的,因为它可能只持续一次调用。容器可以重复使用,但这不是您可以依赖的东西。作为开发人员,您将代码上传到 FaaS 平台,然后该服务会处理基础架构的所有容量、扩展、修补和管理,以运行您的代码。

使用无服务器架构构建的应用程序遵循事件驱动的方法。例如,应用程序中发生了一个活动,例如单击。

这与经典架构非常不同,在经典架构中,应用程序代码通常部署在 Tomcat 或 WildFly 等应用程序服务器中。扩展您的应用程序意味着启动应用程序服务器的额外实例或使用打包的应用程序服务器启动额外的容器。负载平衡器需要使用新的 IP 地址进行更新。操作系统需要打补丁、升级和维护。

Serverless Architectures 解释了经典编程模型和这种新的无服务器架构之间的区别。

FaaS 平台将您的应用程序划分为多个功能。每个功能都部署在 FaaS 中。该服务启动额外的计算实例以满足您的应用程序的可扩展性需求。 FaaS 平台提供执行环境并负责启动和拆除容器以运行您的功能。

阅读 Serverless Architectures 了解有关这些图像的更多详细信息。

FaaS 的一大优势是您只需为计算时间付费,即您的代码运行的时间。当您的代码未运行时,不收取任何费用。

查看 Functions 与 VM 和 Container 的不同之处的另一种方法:

请注意,Linux 容器而不是 Docker 容器被用作 AWS Lambda 的实现。

FaaS 与 PaaS 有何不同?

正如在 Serverless Architectures 中引用的那样,以下推文提供了一个快速答案:

如果您的 PaaS 可以在 20 毫秒内有效地启动运行半秒的实例,那么就称它为无服务器。 https://t.co/S3YzvqFYLR

— adrian cockcroft (@adrianco) 2016 年 5 月 28 日

换句话说,大多数 PaaS 应用程序并不适合针对每个请求启动和关闭整个应用程序,而 FaaS 平台正是这样做的。

使用 FaaS 抽象后端解释不同 *aaS 产品的区别。博客中的图片如下:

Serverless Architectures 还详细介绍了 FaaS 是什么和不是什么。

AWS LambdaGoogle Cloud FunctionsAzure Functions 是运行无服务器应用程序的一些选项。

此博客将展示如何编写您的第一个 AWS Lambda 函数。

什么是 AWS Lambda?

AWS Lambda 是 Amazon Web Services 的 FaaS 服务。它在高可用性计算基础架构上运行您的代码,并执行计算资源的所有管理,包括服务器和操作系统维护、容量配置和自动扩展、代码监控和日志记录。

AWS Lambda 在您的代码运行期间以 100 毫秒为增量向您收费。在 AWS 中存储 Lambda 函数没有任何相关费用。每月前 100 万个请求是免费的,之后的价格是象征性的。阅读有关 Lambda 定价 的更多详细信息。它还通过向 AWS CloudWatch 提供实时指标和日志来提供性能可见性。您需要做的就是编写代码!

这是一个快速介绍:

另请查看 AWS ReInvent 2016 中 AWS Lambda 的新增功能:

另请查看 AWS ReInvent 2016 中的无服务器架构模式和最佳实践:

您在 AWS Lambda 上运行的代码称为 Lambda 函数。您可以将代码作为 zip 文件上传或使用 AWS Lambda 管理控制台 进行设计。内置了对 AWS SDK 的支持,这简化了调用其他 AWS 服务的能力。

简而言之,Lambda 是可扩展的、无服务器的、在云中计算的。

AWS Lambda 提供了几种执行环境:

  • Node.js – v0.10.36、v4.3.2(推荐)
  • Java – Java 8
  • Python – Python 2.7
  • .NET 核心 – .NET 核心 1.0.1 (C#)

本博客将展示:

  • 构建一个将 JSON 文档存储到 Couchbase
  • 的 Java 应用程序
  • 使用 Maven 为 Java 应用程序创建部署包
  • 创建 Lambda 函数
  • 更新 Lambda 函数

此博客中的完整代码可在 github.com/arun-gupta/serverless/tree/master/aws/hellocouchbase 获得。

AWS Lambda 的 Java 应用程序

首先,让我们看一下将用于此 Lambda 函数的 Java 应用程序。 Java 中 Lambda 函数的编程模型提供了有关如何使用 Java 编写 Lambda 函数代码的更多详细信息。

我们的 Lambda 函数将实现预定义接口 com.amazonaws.services.lambda.runtime.RequestHandler。代码如下:

public class HelloCouchbase implements RequestHandler<Request, String> {
 
    CouchbaseCluster cluster;
    Bucket bucket;
    LambdaLogger logger;
 
    @Override
    public String handleRequest(Request request, Context context) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        String timestamp = dateFormat.format(Calendar.getInstance().getTime());
 
        logger = context.getLogger();
        logger.log("Request received: %s" + timestamp);
        ButtonDocument buttonDocument = new ButtonDocument();
        buttonDocument.setId(context.getAwsRequestId());
        buttonDocument.setRequestId(context.getAwsRequestId());
        buttonDocument.setTimestamp(String.valueOf(timestamp));
        
        getBucket().upsert(buttonDocument.toJson());
 
        return buttonDocument.toString();
    }

handleRequest 方法是实现功能代码的地方。 Context 提供有关 Lambda 执行环境的有用信息。来自上下文的一些信息存储在一个 JSON 文档中。最后,Couchbase Java SDK API upsert 用于将 JSON 文档写入已识别的 Couchbase 实例。 Amazon EC2 上的 Couchbase 提供了在 AWS EC2 上安装 Couchbase 的完整说明。

Couchbase 服务器的信息获取方式如下:

public CouchbaseCluster getCluster() {
    if (null == cluster) {
        logger.log("env: " + System.getenv("COUCHBASE_HOST"));
        cluster = CouchbaseCluster.create(System.getenv("COUCHBASE_HOST"));
    }
    return cluster;
}

这再次使用 Couchbase Java API CouchbaseCluster 作为 Couchbase 集群的主要入口点。 COUCHBASE_HOST环境变量在创建 Lambda 函数时传递。在我们的例子中,这将指向在 AWS EC2 上运行的单节点 Couchbase 集群。 最近在 AWS Lambda 中引入了环境变量

最后,您需要访问服务器中的存储桶:

public Bucket getBucket() {
    while (null == bucket) {
        logger.log("Trying to connect to the database");
        bucket = getCluster().openBucket("serverless", 2L, TimeUnit.MINUTES);
 
        try {
            Thread.sleep(3000);
        } catch (Exception e) {
            logger.log("Thread sleep Exception: " + e.toString());
            throw new RuntimeException(e);
        }
    }
 
    return bucket;
}

存储桶名称为 serverless,所有 JSON 文档都存储在其中。

一个简单的Hello World 应用程序 也可用于创建此功能。

创建 AWS Lambda 部署包

AWS Lambda 函数需要一个部署包。此包是一个 .zip.jar 文件,其中包含该函数的所有依赖项。我们的应用程序是使用 Maven 打包的,因此我们将使用 Maven 插件来创建部署包。

该应用程序包含带有以下插件片段的 pom.xml

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>2.3</version>
    <configuration>
        <createDependencyReducedPom>false</createDependencyReducedPom>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
        </execution>
    </executions>
</plugin>

有关 Maven 配置的更多详细信息,请参阅在没有任何 IDE 的情况下使用 Maven 创建 .jar 部署包maven-shade-plugin 允许创建一个包含所有依赖项的 uber-jar。 shade 目标与 package 阶段相关联。所以 mvn package 命令将生成一个部署 jar。

使用 mvn package 命令打包应用程序。这将显示输出:

[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hellocouchbase ---
[INFO] Building jar: /Users/arungupta/workspaces/serverless/aws/hellocouchbase/hellocouchbase/target/hellocouchbase-1.0-SNAPSHOT.jar
[INFO] 
[INFO] --- maven-shade-plugin:2.3:shade (default) @ hellocouchbase ---
[INFO] Including com.amazonaws:aws-lambda-java-core:jar:1.1.0 in the shaded jar.
[INFO] Including com.couchbase.client:java-client:jar:2.3.6 in the shaded jar.
[INFO] Including com.couchbase.client:core-io:jar:1.3.6 in the shaded jar.
[INFO] Including io.reactivex:rxjava:jar:1.1.8 in the shaded jar.
[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing /Users/arungupta/workspaces/serverless/aws/hellocouchbase/hellocouchbase/target/hellocouchbase-1.0-SNAPSHOT.jar with /Users/arungupta/workspaces/serverless/aws/hellocouchbase/hellocouchbase/target/hellocouchbase-1.0-SNAPSHOT-shaded.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

target/hello-couchbase-1.0-SNAPSHOT.jar 是将部署到 AWS Lambda 的阴影 jar。

有关创建部署包的更多详细信息,请参阅创建部署包

创建 AWS Lambda 函数

使用 AWS CLI 创建 AWS Lambda 函数。这种情况下的 CLI 命令如下所示:

aws lambda create-function \
--function-name HelloWorld \
--role arn:aws:iam::<account-id>:role/service-role/myLambdaRole \
--zip-file fileb:///Users/arungupta/workspaces/serverless/aws/hellocouchbase/hellocouchbase/target/hellocouchbase-1.0-SNAPSHOT.jar \
--handler org.sample.serverless.aws.couchbase.HelloCouchbaseLambda \
--description "Hello Couchbase Lambda" \
--runtime java8  \
--region us-west-2 \
--timeout 30 \
--memory-size 1024 \
--publish

在此 CLI 中:

  • create-function 创建一个 Lambda 函数
  • --function-name 提供函数名称。函数名称区分大小写。
  • --role 指定 Lambda 在执行您的函数以访问任何其他 AWS 资源时承担的 IAM 角色 的 Amazon 资源名称 (ARN)。如果您使用 AWS 控制台执行了 Lambda 函数,则会为您创建此角色。
  • --zip-file 指向在上一步中创建的部署包。 fileb 是 AWS CLI 特定的协议,用于指示上传的内容是二进制的。
  • --handler 是被调用以开始执行函数的 Java 类
  • --publish 请求 AWS Lambda 创建 Lambda 函数并将版本发布为原子操作。否则可能会创建多个版本并可能在稍后发布。

Lambda 控制台显示:

测试 AWS Lambda 函数

使用 AWS CLI 测试 AWS Lambda 函数。

aws lambda invoke \
--function-name HelloCouchbaseLambda \
--region us-west-2 \
--payload '' \
hellocouchbase.out

它将输出显示为:

{
    "StatusCode": 200
}

命令的输出存储在 hellocouchbase.out 中,如下所示:

"{\"id\":\"e6bbe71a-ca4f-11e6-95a7-95f2ed410493\",\"installationId\":null,\"requestId\":\"e6bbe71a-ca4f-11e6-95a7-95f2ed410493\",\"identityId\":null,\"timestamp\":\"2016-12-25 03:12:01.157\"}"

调用此函数会在 Couchbase 中存储一个 JSON 文档。可以使用 Couchbase Web Console 查看存储在 Couchbase 中的文档。密码是 Administrator,密码是 EC2 实例 ID。

此 Couchbase 实例中的所有数据桶如下所示:

请注意,serverless 存储桶是手动创建的。

单击 Documents 显示存储在存储桶中的不同文档的详细信息:

单击每个文档会显示有关 JSON 文档的更多详细信息:

Lambda 函数也可以使用控制台进行测试:

更新 AWS Lambda 函数

如果应用程序逻辑发生变化,则需要为 Lambda 函数上传新的部署包。在这种情况下,mvn package 将创建一个部署包,aws lambda CLI 命令用于更新功能代码:

aws lambda update-function-code \
--function-name HelloCouchbaseLambda \
--zip-file fileb:///Users/arungupta/workspaces/serverless/aws/hellocouchbase/hellocouchbase/target/hellocouchbase-1.0-SNAPSHOT.jar \
--region us-west-2 \
--publish

显示结果:

{
    "CodeSha256": "w510ejw/OoVsQt2JiLG2bPZPAaFvQCRrYYYlQWctCQE=", 
    "FunctionName": "HelloCouchbaseLambda", 
    "CodeSize": 6978108, 
    "MemorySize": 1024, 
    "FunctionArn": "arn:aws:lambda:us-west-2:<account-id>:function:HelloCouchbaseLambda:8", 
    "Environment": {
        "Variables": {
            "COUCHBASE_HOST": "ec2-35-165-249-235.us-west-2.compute.amazonaws.com"
        }
    }, 
    "Version": "8", 
    "Role": "arn:aws:iam::<account-id>:role/service-role/myLambdaRole", 
    "Timeout": 30, 
    "LastModified": "2016-12-25T04:17:38.717+0000", 
    "Handler": "org.sample.serverless.aws.couchbase.HelloCouchbaseLambda", 
    "Runtime": "java8", 
    "Description": "Java Hello Couchbase"
}

然后可以再次调用该函数。

在写这篇博客的过程中,这也经常被用来调试功能。这是因为 Lambda 函数没有任何关联的状态或框。因此,您无法登录到一个盒子来检查该功能是否未正确部署。一旦功能正常运行,您当然可以使用 CloudWatch 日志语句。

AWS Lambda 参考资料

  • 无服务器架构
  • AWS Lambda:工作原理
  • Couchbase 服务器文档
  • Couchbase 论坛
  • 通过 @couchbasedev 关注我们
标签2: Java教程
地址:https://www.cundage.com/article/jcg-serverless-faas-aws-lambda-java.html

相关阅读

Java HashSet 教程展示了如何使用 Java HashSet 集合。 Java哈希集 HashSet 是一个不包含重复元素的集合。此类为基本操作(添加、删除、包含和大小)提供恒定时间性...
SpringApplicationBuilder 教程展示了如何使用 SpringApplicationBuilder 创建一个简单的 Spring Boot 应用程序。 春天 是用于创建企业应...
通道是继 buffers 之后 java.nio 的第二个主要新增内容,我们在之前的教程中已经详细了解了这一点。通道提供与 I/O 服务的直接连接。 通道是一种在字节缓冲区和通道另一端的实体(通...
课程大纲 Elasticsearch 是一个基于 Lucene 的搜索引擎。它提供了一个分布式的、支持多租户的全文搜索引擎,带有 HTTP Web 界面和无模式的 JSON 文档。 Elasti...
解析器是强大的工具,使用 ANTLR 可以编写可用于多种不同语言的各种解析器。 在这个完整的教程中,我们将: 解释基础:什么是解析器,它可以用来做什么 查看如何设置 ANTLR 以便在 Java...
Java 是用于开发各种桌面应用程序、Web 应用程序和移动应用程序的最流行的编程语言之一。以下文章将帮助您快速熟悉 Java 语言,并迈向 API 和云开发等更复杂的概念。 1. Java语言...
Java中的继承是指子类继承或获取父类的所有非私有属性和行为的能力。继承是面向对象编程的四大支柱之一,用于提高层次结构中类之间的代码可重用性。 在本教程中,我们将了解 Java 支持的继承类型,...
Java Message Service 是一种支持正式通信的 API,称为 网络上计算机之间的消息传递。 JMS 为支持 Java 程序的标准消息协议和消息服务提供了一个通用接口。 JMS 提...
之前,我介绍了spring 3 + hibernate 集成 示例和struts 2 hello world 示例。在本教程中,我将讨论在将 spring 框架与 struts 与 hibern...
Java 项目中的一项常见任务是将日期格式化或解析为字符串,反之亦然。解析日期意味着你有一个代表日期的字符串,例如“2017-08-3”,你想把它转换成一个代表 Java 中日期的对象,例如Ja...