AWS Lambda Python 链路可观测最佳实践

背景

随着企业核心业务全面向云原生和无服务器架构迁移,AWS Lambda 因其免运维、自动扩缩容和按调用计费的优势,已成为支撑高并发、事件驱动型业务的首选计算平台。然而,Serverless 的"黑盒化"特征也带来了新的可观测性挑战:

  • 分布式链路断裂:Lambda 函数往往作为事件触发链中的关键一环,与 API Gateway、S3、SQS、DynamoDB 等服务交叉调用,传统 APM 难以串联完整调用链。
  • 冷启动与性能瓶颈难定位:函数初始化耗时、依赖库加载、网络延迟等性能指标缺乏细粒度追踪,影响用户体验与成本控制。
  • 多环境、多账号下的观测一致性缺失:Dev、QA、Prod 环境函数数量众多,若没有统一的链路标准和标签规范,问题定位效率低,跨团队协作成本高。

为保障线上稳定性、优化函数性能、实现 Serverless 场景下的可观测闭环,亟需基于 Python 运行时构建一套标准化方案,提供从原理、代码示例到生产级部署的完整落地方案,助力企业在 Serverless 架构下实现"问题可追踪、性能可量化、成本可优化"的目标。

AWS 提供了两种链路协议支持用于 Lambda 函数的链路追踪:OpenTelemetry、X-Ray。当前最佳实践主要是采用 OpenTelemetry 协议来实现链路可观测。

观测云

观测云是一款专为 IT 工程师打造的全链路可观测产品,它集成了基础设施监控、应用程序性能监控和日志管理,为整个技术栈提供实时可观察性。支持通过一键集成 OpenTelemetry 标准 SDK/Collector,把分布式链路、指标、日志三信号统一采集并云端托管,在 OTel 的厂商中立格式之上提供即开即用的仪表、告警与 AI 异常检测,让用户免运维后端即可把云原生应用的可观测数据"拿来即用",实现从链路到业务场景的端到端可视化。

实践

AWS Lambda 使用 Python 语言编写函数,并调用应用服务,应用服务为 java 语言。同时需要将可观测数据上报至观测云。

准备 Lambda Layer

需要新增以下两个 Layer

  • Opentelemetry Layer:用于链路插桩
  • DataKit Layer: 用于接收 Opentelemetry 的可观测数据

Opentelemetry Layer

使用 OpenTelemetry 自动插桩方式可以零侵入 Python 代码实现链路追踪,这里 OpenTelemetry 可以作为 layer 附着到 Lambda 函数内部。

AWS 宁夏节点需要手动构建 OpenTelemetry layer,其他节点可直接使用对应的 ARN,这里主要介绍手动构建方式:

1、下载源码

bash 复制代码
git clone https://github.com/open-telemetry/opentelemetry-lambda.git

2、构建

构建前,主要安装相关 AWS 工具,可以参考仓库 README 文件,假设以及装好了相关工具,执行下面操作进行构建:

ruby 复制代码
liurui@liurui:~/code/opentelemetry-lambda$ cd python/src
liurui@liurui:~/code/opentelemetry-lambda/python/src$ ./run.sh -r cn-northwest-1

构建部分日志如下:

ruby 复制代码
running...
Invoked with: -r cn-northwest-1
sam building...
run.sh: Starting sam build.
Starting Build inside a container                                                                                                                               
Building layer 'OTelLayer'                                                                                                                                      
For container layer build, first compatible runtime is chosen as build target for container.                                                                    

Fetching public.ecr.aws/sam/build-python3.9:latest-x86_64 Docker container image......
Mounting /home/liurui/code/opentelemetry-lambda/python/src/otel as /tmp/samcli/source:ro,delegated, inside runtime container       


Successfully created/updated stack - otel-stack in cn-northwest-1


OTel Lambda layer ARN:
arn:aws-cn:lambda:cn-northwest-1:888888888:layer:otel-layer:2

构建成功后,自动上传在 AWS Layer 上 otel-layer,复制当前 ARN,后续操作会用到。

DataKit Layer

DataKit Layer 是观测云研发的 AWS Lambda Layer,用于采集、上报链路、指标、日志等数据。可以接收 OpenTelemetry 链路信息 。

登录 AWS Lambda 控制台,创建名为 datakit-x86_64 layer,可自行调整,选择于 Python 应用相符的架构,当前主要是 AMD 架构,根据架构,选择下面的压缩包进行上传,保存即可:

Lambda 函数

创建 Lambda 函数

创建 Lambda 函数,运行时选择 Python,架构选择 x86_64。

新增示例代码

lambda_function.py 新增以下内容:

python 复制代码
import json
import urllib.request
import urllib.error
import time

# 上游接口
UPSTREAM_URL = "http://java服务接口:8090/user"

def lambda_handler(event, context):
    """
    带日志的接口转发示例
    """
    # 1. 取 Lambda RequestId,方便全链路追踪
    request_id = context.aws_request_id
    print(json.dumps({
        "level": "INFO",
        "requestId": request_id,
        "message": "Lambda invoke start",
        "event": event
    }))

    try:
        # 2. 解析入参
        params = event.get("queryStringParameters") or {}
        todo_id = params.get("id", "1")
        print(json.dumps({
            "level": "INFO",
            "requestId": request_id,
            "message": "Parsed todo_id",
            "todo_id": todo_id
        }))

        # 3. 调用上游
        upstream = UPSTREAM_URL
        print(json.dumps({
            "level": "INFO",
            "requestId": request_id,
            "message": "Upstream request start",
            "url": upstream
        }))
        start = time.time()

        req = urllib.request.Request(upstream, method="GET")
        with urllib.request.urlopen(req, timeout=5) as resp:
            upstream_body = resp.read().decode("utf-8")
            upstream_json = json.loads(upstream_body)

        latency = round((time.time() - start) * 1000, 2)
        print(json.dumps({
            "level": "INFO",
            "requestId": request_id,
            "message": "Upstream request finish",
            "statusCode": resp.status,
            "latency_ms": latency
        }))

        # 4. 返回
        response_body = {
            "message": "Hello from Lambda!",
            "upstream": upstream_json
        }
        print(json.dumps({
            "level": "INFO",
            "requestId": request_id,
            "message": "Lambda invoke success",
            "response": response_body
        }))
        return {
            "statusCode": 200,
            "headers": {"Content-Type": "application/json"},
            "body": json.dumps(response_body)
        }

    # 5. 异常分支日志
    except urllib.error.HTTPError as e:
        print(json.dumps({
            "level": "ERROR",
            "requestId": request_id,
            "message": "Upstream HTTPError",
            "statusCode": e.code,
            "reason": e.reason
        }))
        return {
            "statusCode": e.code,
            "body": json.dumps({"error": f"Upstream HTTPError: {e.reason}"})
        }

    except urllib.error.URLError as e:
        print(json.dumps({
            "level": "ERROR",
            "requestId": request_id,
            "message": "Upstream URLError",
            "reason": str(e.reason)
        }))
        return {
            "statusCode": 502,
            "body": json.dumps({"error": f"Upstream URLError: {e.reason}"})
        }

    except Exception as e:
        print(json.dumps({
            "level": "ERROR",
            "requestId": request_id,
            "message": "Unknown exception",
            "error": str(e)
        }))
        return {
            "statusCode": 500,
            "body": json.dumps({"error": str(e)})
        }

添加完成后,点击 Deploy 进行部署。

添加 Layer

点击 Layger 进行添加,选择 指定一个 ARN 进行添加,ARN 为上面准备工作产生的 Layer ARN 地址。

确保已经添加了以下两个 Layer。

添加环境变量

在对应的函数配置里面进行添加。

ini 复制代码
# otel lambda handler
AWS_LAMBDA_EXEC_WRAPPER = /opt/python/otel-handler
# 观测云网关地址
ENV_DATAWAY = http://open****?token=xxxxxxx
# otel 上报地址,无需调整
OTEL_EXPORTER_OTLP_ENDPOINT = http://localhost:9529/otel

测试

点击测试按钮进行测试。

观测云链路效果

相关推荐
zhojiew19 小时前
在AWS裸金属实例上安装Cubesandbox并集成PydanticAI进行数据分析的实践
数据分析·云计算·aws
yyuuuzz19 小时前
aws亚马逊云上运维常见问题梳理
运维·服务器·网络·云计算·aws
亚林瓜子2 天前
AWS S3日志桶常用过期文件生命周期策略
云计算·生命周期·aws·s3·过期·glacier
yyuuuzz2 天前
企业出海场景下的技术适配小经验
运维·服务器·网络·云计算·aws
yyuuuzz4 天前
国外云服务使用的常见技术问题梳理
运维·服务器·网络·数据库·aws
光于前裕于后5 天前
AWS Redshift 集成Zero-ETL和数据共享 Data sharing
云计算·etl·aws
zhojiew7 天前
在AWS中国区实现EKS跨VPC跨区域实现节点加入集群的实践
云计算·aws
认真的薛薛7 天前
Terraform: AWS VPC+可SSH登录EC2
ssh·aws·terraform
认真的薛薛7 天前
Terraform:AWS VPC
云原生·aws·terraform
yyuuuzz7 天前
境外云服务器使用常见问题梳理
运维·服务器·网络·aws