当前位置:Java -> 使用 X-Ray 分析和调试基于 Quarkus 的 AWS Lambda 函数
无服务器架构已成为构建快速、可伸缩和高效应用的范式转变方法。虽然无服务器架构提供了无与伦比的灵活性,但在监控和故障排除方面也引入了新的挑战。
在本文中,我们将探讨Quarkus如何与AWS X-Ray集成,以及如何使用Jakarta CDI Interceptor来保持您的代码清晰,同时添加自定义仪器。
Quarkus是一个专为GraalVM和HotSpot定制的基于Java的框架,可以实现惊人的快速启动时间,并具有极低的内存占用率。它提供了几乎立即的规模扩展和高密度的内存利用率,这对于像Kubernetes这样的容器编排平台或AWS Lambda这样的无服务器运行时非常有用。
构建AWS Lambda函数可以像启动Quarkus项目、添加quarkus-amazon-lambda
依赖项,并定义您的AWS Lambda Handler函数那样简单。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-amazon-lambda</artifactId>
</dependency>
可以在官方Quarkus AWS Lambda指南中找到有关如何使用Quarkus开发AWS Lambda函数的详尽指南。
Quarkus提供了对X-Ray的开箱即用支持,但您需要向项目添加一个依赖项并配置一些设置,以使其与GraalVM/原生编译的Quarkus应用程序配合使用。
首先,让我们添加quarkus-amazon-lambda-xray
依赖项。
<!-- adds dependency on required x-ray classes and adds support for graalvm native -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-amazon-lambda-xray</artifactId>
</dependency>
不要忘记为您的Lambda函数启用跟踪,否则它将无法正常工作。一个实现的例子是在AWS CDK代码中将跟踪参数设置为active。
function = Function.Builder.create(this, "feed-parsing-function")
...
.memorySize(512)
.tracing(Tracing.ACTIVE)
.runtime(Runtime.PROVIDED_AL2023)
.logRetention(RetentionDays.ONE_WEEK)
.build();
在部署函数和函数调用之后,您应该能够在Cloudwatch界面中看到来自X-Ray的跟踪。默认情况下,它将显示函数的一些基本时间信息,如初始化和调用持续时间。
现在依赖项已经就位,并且我们的函数已启用跟踪,我们可以通过利用X-Ray SDK的TracingIntercepter
来丰富X-Ray中的跟踪。例如,对于SQS和DynamoDB客户端,您可以在application.properties文件内显式设置拦截器。
quarkus.dynamodb.async-client.type=aws-crt
quarkus.dynamodb.interceptors=com.amazonaws.xray.interceptors.TracingInterceptor
quarkus.sqs.async-client.type=aws-crt
quarkus.sqs.interceptors=com.amazonaws.xray.interceptors.TracingInterceptor
在放置这些属性、重新部署并执行函数后,TracingIntercepter
将包装每个对SQS和DynamoDB的API调用,并将实际的跟踪信息与跟踪一起存储。
这对于调试非常有用,因为它允许您验证代码并检查任何错误。请求AWS服务是计费模型的一部分,因此如果您的代码出现错误并且调用次数过多,可能会变得非常昂贵。
使用AWS SDK的TracingInterceptor
配置后,我们可以获取关于对AWS API的调用的信息,但如果我们想看到关于我们自己代码或AWS之外服务的远程调用的信息怎么办?
Java X-Ray SDK支持向跟踪添加自定义子段的概念。您可以通过以下代码片段中看到的几行代码将子段添加到跟踪中。
public void someMethod(String argument) {
// wrap in subsegment
Subsegment subsegment = AWSXRay.beginSubsegment("someMethod");
try {
// Your business logic
} catch (Exception e) {
subsegment.addException(e);
throw e;
} finally {
AWSXRay.endSubsegment();
}
}
尽管这样做很容易,但如果您有很多方法需要应用跟踪,它将变得非常混乱。这并不理想,最好不要将自己的代码与X-Ray仪器混合在一起。
Quarkus的编程模型基于Jakarta Contexts and Dependency Injection 4.0规范的Lite版本。除了依赖注入,该规范还描述了其他功能,比如:
@PostConstruct
和@PreDestroy
回调。正如上面提到的,CDI拦截器用于将横切关注点与业务逻辑分离。由于追踪是横切关注点,这听起来非常合适。让我们看看如何为我们的AWS X-Ray仪器创建拦截器。
我们首先要定义我们的拦截器绑定,我们将其称为XRayTracing
。拦截器绑定是中间注解,可用于将拦截器与目标bean关联。
package com.jeroenreijn.aws.quarkus.xray;
import jakarta.annotation.Priority;
import jakarta.interceptor.InterceptorBinding;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@InterceptorBinding
@Retention(RUNTIME)
@Priority(0)
public @interface XRayTracing {
}
下一步是定义实际的拦截器逻辑,这是将为我们的业务逻辑添加附加的X-Ray指令(创建子段并将其包装在我们的业务逻辑周围)的代码。
package com.jeroenreijn.aws.quarkus.xray;
import com.amazonaws.xray.AWSXRay;
import jakarta.interceptor.AroundInvoke;
import jakarta.interceptor.Interceptor;
import jakarta.interceptor.InvocationContext;
@Interceptor
@XRayTracing
public class XRayTracingInterceptor {
@AroundInvoke
public Object tracingMethod(InvocationContext ctx) throws Exception {
AWSXRay.beginSubsegment("## " + ctx.getMethod().getName());
try {
return ctx.proceed();
} catch (Exception e) {
AWSXRay.getCurrentSubsegment().addException(e);
throw e;
} finally {
AWSXRay.endSubsegment();
}
}
}
拦截器的一个重要部分是@AroundInvoke
注解,这意味着此拦截器代码将包装在我们自己的业务逻辑调用周围。
既然我们已经定义了我们的拦截器绑定和我们的拦截器,现在是时候开始使用它了。现在,我们想要为其创建子段的每个方法都可以用@XRayTracing
注解进行注释。
@XRayTracing
public SyndFeed getLatestFeed() {
InputStream feedContent = getFeedContent();
return getSyndFeed(feedContent);
}
@XRayTracing
public SyndFeed getSyndFeed(InputStream feedContent) {
try {
SyndFeedInput feedInput = new SyndFeedInput();
return feedInput.build(new XmlReader(feedContent));
} catch (FeedException | IOException e) {
throw new RuntimeException(e);
}
}
看起来好多了。我得说,相当简洁。
基于跟踪的子段层级结构,X-Ray将能够显示具有时间信息的嵌套树结构。
Quarkus与X-Ray之间的集成非常容易启用。开发者体验在定义针对每个客户端的拦截器时非常棒。借助CDI拦截器的帮助,您可以保持代码整洁,而不用过多担心业务逻辑中的X-Ray特定代码。
构建自己的拦截器的另一种选择可能是开始使用AWS PowerTools for Lambda (Java)。Java的PowerTools是提高开发人员生产力的绝佳方法,但它不仅仅用于X-Ray,所以我会将其留到另一篇文章中。
推荐阅读: 百度面经(1)
本文链接: 使用 X-Ray 分析和调试基于 Quarkus 的 AWS Lambda 函数