前言

AWS Lambda 是一项计算服务,使用时无需预配置或管理服务器即可运行代码。AWS Lambda 只在需要时执行代码并自动缩放。借助 AWS Lambda,几乎可以为任何类型的应用程序或后端服务运行代码,而且无需执行任何管理。

Lambda Layer 是一个包含补充代码或数据的 .zip 文件存档,通常包含库依赖项、自定义运行时系统或配置文件。Lambda 扩展则是可以增强 Lambda 函数的功能,例如集成监控、安全性和监管工具等。

在本文中,我们将引导您了解如何将观测云服务集成到 AWS Lambda,通过配置 Lambda 层、设置环境变量,实现 Lambda 函数的指标、日志和链路采集。

通过观测云 DataKit Extension 接入 AWS Lambda 最佳实践_aws

前提条件

  • 确保您拥有 AWS 账户,并且具备管理 Lambda 函数的权限。
  • 已注册 观测云账号

第1步:创建Lambda层

1、打开 AWS Lambda 控制台并导航至「Layers」页面。

通过观测云 DataKit Extension 接入 AWS Lambda 最佳实践_aws_02

2、点击「Create layer」,创建一个新的层。

通过观测云 DataKit Extension 接入 AWS Lambda 最佳实践_lambda_03

3、在「Layer configuration」中,填写层的名称。

通过观测云 DataKit Extension 接入 AWS Lambda 最佳实践_aws_04

4、选择「Upload a .zip file」并上传以下链接对应的文件:

通过观测云 DataKit Extension 接入 AWS Lambda 最佳实践_aws_05

第2步:复制 ARN 并添加层到 Lambda 函数

  • 创建成功后,复制层的 ARN 值。

通过观测云 DataKit Extension 接入 AWS Lambda 最佳实践_aws_06

  • 在 Lambda 函数配置中添加此 ARN 到 Layers 部分。

通过观测云 DataKit Extension 接入 AWS Lambda 最佳实践_lambda_07

第3步:配置环境变量

设置以下环境变量以确保数据正确传输到观测云:

Datakit 监听的地址名

  • DD_AGENT_HOST: 0.0.0.0

Datakit 监听的端口号

  • DD_TRACE_AGENT_PORT: 9529

DataWay 真实地址

  • ENV_DATAWAY: https://xxxx.guance.com?token=<your-token>

通过观测云 DataKit Extension 接入 AWS Lambda 最佳实践_lambda_08

第4步:日志、链路和指标采集

日志采集

  • 支持采集控制台日志。

通过观测云 DataKit Extension 接入 AWS Lambda 最佳实践_aws_09

通过观测云 DataKit Extension 接入 AWS Lambda 最佳实践_lambda_10

  • Node.js 18.x 和 Go 日志采集示例。

通过观测云 DataKit Extension 接入 AWS Lambda 最佳实践_lambda_11

链路采集

  • 使用 OpenTelemetry 或 DDTrace 进行链路采集
  • 对于 Go 语言,需要在业务代码中添加相应的追踪代码。Go 代码示例较为复杂,需要修改业务代码,示例如下:
package main

import (
        "context"
        "fmt"
        "github.com/aws/aws-lambda-go/lambda"
        "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext"
        "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
        "os"
        "time"
)

type MyEvent struct {
        Name string `json:"name"`
}

func HandleRequest(ctx context.Context, event *MyEvent) (*string, error) {
        return run(ctx, event)
}

func run(ctx context.Context, event *MyEvent) (*string, error) {
        tracer.Start(
                tracer.WithEnv("prod"),
                tracer.WithService("test-file-read"),
                tracer.WithServiceVersion("1.2.3"),
                tracer.WithGlobalTag("project", "add-ddtrace-in-golang-project"),
                tracer.WithLambdaMode(false),
        )

        // end of app exit, make sure tracer stopped
        defer tracer.Stop()

        tick := time.NewTicker(time.Second)
        defer tick.Stop()
        ctx, cancel := context.WithTimeout(ctx, time.Minute*2)
        defer cancel()
        // your-app-main-entry...
        for {
                runApp()
                runAppWithError()

                select {
                case <-tick.C:
                case <-ctx.Done():
                        message := fmt.Sprintf("Hello %s!", event)
                        return &message, nil
                }
        }
}

func main() {
        //run(context.Background(), &MyEvent{Name: "Hello World!"})
        lambda.Start(HandleRequest)
}

func runApp() {
        var err error
        // Start a root span.
        span := tracer.StartSpan("get.data")
        defer span.Finish(tracer.WithError(err))

        // Create a child of it, computing the time needed to read a file.
        child := tracer.StartSpan("read.file", tracer.ChildOf(span.Context()))
        child.SetTag(ext.ResourceName, os.Args[0])

        // Perform an operation.
        var bts []byte
        bts, err = os.ReadFile(os.Args[0])
        span.SetTag("file_len", len(bts))
        child.Finish(tracer.WithError(err))
}

func runAppWithError() {
        var err error
        // Start a root span.
        span := tracer.StartSpan("get.data")

        // Create a child of it, computing the time needed to read a file.
        child := tracer.StartSpan("read.file", tracer.ChildOf(span.Context()))
        child.SetTag(ext.ResourceName, "somefile-not-found.go")

        defer func() {
                child.Finish(tracer.WithError(err))
                span.Finish(tracer.WithError(err))
        }()

        // Perform an error operation.
        if _, err = os.ReadFile("somefile-not-found.go"); err != nil {
                // error handle
        }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 链路效果展示

通过观测云 DataKit Extension 接入 AWS Lambda 最佳实践_lambda_12

通过观测云 DataKit Extension 接入 AWS Lambda 最佳实践_lambda_13

指标采集

以下是 AWS Lambda 指标的详细列表

通过观测云 DataKit Extension 接入 AWS Lambda 最佳实践_aws_14

awslambda-metric

标签描述
aws_account_idAWS 账户ID。
aws_lambda_function_memory_sizeConfigured memory size for the Lambda function.
aws_lambda_function_nameLambda function name.
aws_lambda_function_versionLambda function version.
aws_lambda_initialization_typeInitialization type of the Lambda function.
aws_regionAWS region where the function is executed.
指标描述类型单位
billed_duration_msBilled duration in milliseconds.intms
duration_msTotal duration in milliseconds.intms
errorsErrors count.intcount
init_duration_msInitialization duration in milliseconds.intms
invocationsInvocation count.intcount
max_memory_used_mbMaximum memory used in MB.intMb
memory_size_mbMemory size configured for the Lambda function in MB.intMb
out_of_memoryOut of memory errors count.intcount
post_runtime_durationDuration of the post-runtime phase in milliseconds.intms
produced_bytesBytes produced.intB
response_duration_msResponse duration in milliseconds.intms
response_latencyResponse latency in milliseconds.intms
runtime_duration_msDuration of the runtime in milliseconds.intms
timeoutsTimeouts count.intcount

安全和隐私说明

  • 确保在配置 ENV_DATAWAY 时使用安全的连接(例如 HTTPS)。
  • 不要在日志或错误消息中暴露敏感信息。

注意事项

  • 在部署之前,确保测试所有配置。
  • 监控Lambda函数的性能,确保指标收集符合预期。
  • 定期检查Lambda层和相关配置是否有更新。

参考资料