Lambda NodeJS 运行时链路接入观测云

背景

为有效监控无服务器架构的业务性能,我们需要将AWS Lambda函数的全链路数据接入观测云进行统一可观测性分析。由于Lambda环境的特殊性,最佳实践是构建一个集成了OpenTelemetry的官方Layer。该Layer能自动捕获函数调用链与性能指标,并通过标准OTLP协议上报。为确保数据传输的高效性与前瞻性,我们特别将社区常见的JSON格式调整为Protobuf编码,以适配观测云后端的技术演进,为函数性能优化与故障诊断提供坚实的数据基础。

前提

运行时:NodeJS 22

安装Datakit并配置采集器

进入观测云控制台-「集成」-「Datakit」-「Linux」复制命令安装Datakit

进入 /usr/local/datakit/conf.d/samples ,将 opentelemetry.conf.sample 复制到上级目录 /conf.d 中,并修改文件后缀为 conf

bash 复制代码
cp opentelemetry.conf.sample ../opentelemetry.conf

编辑 opentelemetry 配置文件,修改如下部分,添加 enable = true ,然后保存

执行以下命令重启 Datakit

bash 复制代码
datakit service -R

准备一个lambda函数

以下 demo 脚本调用了一个 Java 服务 52.83.66.70:8090/user:

bash 复制代码
const http = require('http');

exports.handler = async (event, context) => {
    console.log('=== 开始调用Java服务验证TraceID ===');
    try {
        console.log('准备调用Java服务: 52.83.66.70:8090/user');
        // 调用您的Java服务
        const javaServiceResult = await callJavaService();
        console.log('Java服务调用成功');
        return {
            statusCode: 200,
            body: JSON.stringify({
                success: true,
                message: 'Java服务调用完成',
                javaServiceResponse: javaServiceResult,
                requestId: context.awsRequestId,
                timestamp: new Date().toISOString()
            })
        };
    } catch (error) {
        console.error('调用Java服务失败:', error);
        return {
            statusCode: 500,
            body: JSON.stringify({
                success: false,
                message: 'Java服务调用失败',
                error: error.message
            })
        };
    }
};

function callJavaService() {
    return new Promise((resolve, reject) => {
        console.log('开始发起HTTP请求到Java服务...');
        const options = {
            hostname: '52.83.66.70',
            port: 8090,
            path: '/user',
            method: 'GET',
            timeout: 5000,  // 5秒超时
            headers: {
                'User-Agent': 'Lambda-OTEL-Test/1.0',
                'Accept': 'application/json'
            }
        };
        const req = http.request(options, (res) => {
            console.log(Java服务响应状态码: ${res.statusCode});
            console.log('响应头:', JSON.stringify(res.headers));
            let data = '';
            res.on('data', (chunk) => {
                data += chunk;
            });
            res.on('end', () => {
                console.log('Java服务响应数据长度:', data.length);
                console.log('原始响应:', data);
                try {
                    // 尝试解析JSON响应
                    const parsedData = data ? JSON.parse(data) : {};
                    resolve({
                        statusCode: res.statusCode,
                        data: parsedData,
                        headers: res.headers,
                        rawResponse: data
                    });
                } catch (e) {
                    // 如果JSON解析失败,返回原始数据
                    console.log('响应不是JSON格式,返回原始数据');
                    resolve({
                        statusCode: res.statusCode,
                        data: data,
                        headers: res.headers,
                        isJson: false
                    });
                }
            });
        });
        req.on('error', (error) => {
            console.error('请求Java服务错误:', error.message);
            reject(error);
        });
        req.on('timeout', () => {
            console.error('请求Java服务超时');
            req.destroy();
            reject(new Error('请求Java服务超时'));
        });
        // 发送请求
        req.end();
        console.log('HTTP请求已发送到Java服务');
    });
}

测试事件:

构建layer

构建官方的layer做导出器,通过 Layer 集成,无侵入式地自动捕获 Lambda 函数执行的链路数据可以自动采集lambda函数的链路数据,将采集的数据转换为 OpenTelemetry(OTel)标准格式,确保与观测后端平台的兼容性。

注意:Node.js 社区提供的默认 OpenTelemetry 导出器通常使用 HTTP/JSON 方式发送数据,需要将默认的导出协议从 HTTP/JSON 改为 HTTP/PROTOBUF,Datakit后续可能考虑废弃HTTP/JSON方式。Protobuf 编码具有更高的序列化/反序列化效率,能显著降低传输数据大小和网络开销,尤其适用于 Lambda 的短时执行环境。

具体可以参考 Opentelemetry 的社区:https://github.com/open-telemetry/opentelemetry-lambda/tree/main/nodejs

克隆仓库

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

修改协议

进入项目目录,将相关文件的 @opentelemetry/exporter-trace-otlp-http 改成@opentelemetry/exporter-trace-otlp-proto,一共需要修改3个文件。

bash 复制代码
cd opentelemetry-lambda/nodejs

./packages/layer/src/wrapper.ts

./nodejs/packages/layer/package.json

./nodejs/packages/layer/test/wrapper.spec.ts

安装依赖

bash 复制代码
npm  install

构建项目

bash 复制代码
npm run build

在./nodejs/packages/layer/build/会有一个layer.zip文件

添加Layer

创建 Layer

在 AWS 控制台 Lambda进入「layer」,新建一个layer,选择上传.zip文件方式上传刚才生成的layer.zip文件,架构选择x86、运行时选择nodejs。创建好后复制ARN

添加 Layer

在 Demo 函数中添加 Layer,选择指定一个 ARN ,将刚才的 ARN 复制进去,点击「添加」

配置环境变量

配置lambda环境变量,选择「配置」-「环境变量」

添加如下变量:

Key VALUE
AWS_LAMBDA_EXEC_WRAPPER /opt/otel-handler
OTEL_EXPORTER_OTLP_ENDPOINT http://<datakit主机地址>:9529/otel
OTEL_EXPORTER_OTLP_TRACES_PROTOCOL http/protobuf
OTEL_NODE_ENABLED_INSTRUMENTATIONS aws-lambda,aws-sdk,http,https,pg,mysql,redis
OTEL_SERVICE_NAME 服务名称
OTEL_TRACES_SAMPLER always_on

测试函数

回到函数点击测试

观测云效果

链路上报效果如下:



相关推荐
yyuuuzz1 天前
谷歌云使用的几个常见注意事项
运维·服务器·网络·安全·web安全·云计算·aws
zhojiew1 天前
在AWS中国区的EMR集群中实现基于向量语义搜索的HBase运维诊断系统
运维·hbase·aws
yyuuuzz1 天前
独立开发者线上服务运维的几点实践经验
运维·服务器·网络·云计算·aws
zhojiew1 天前
使用DBT(data build tool)集成AWS Athena完成数据处理的实践
云计算·aws
yyuuuzz3 天前
aws的核心概念与常见使用场景
运维·服务器·网络·云计算·aws
devilnumber3 天前
如何在java的Lambda中安全地修改外部变量?
java·安全·lambda
zhojiew3 天前
在AWS云上使用EC2 嵌套虚拟化实例部署Cube Sandbox的实践和问题
云计算·aws
CDN3603 天前
360CDN日志分析避坑指南:如何通过upstream_response_time精准定位源站瓶颈
网络·php·运维开发
DianSan_ERP4 天前
抖店订单接口中消费者信息加密解密机制与安全履约全解析
前端·网络·数据库·后端·安全·团队开发·运维开发
yyuuuzz4 天前
国际云服务器的技术特点与使用经验
运维·服务器·网络·数据库·云计算·aws