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 。

复制代码
datakit service -R

打开 datakit.confhttp_api 开启 0.0.0.0:9529

准备一个 Lambda 函数

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

javascript 复制代码
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 的社区:github.com/open-teleme...

克隆仓库

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

./packages/layer/package.json

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

安装依赖

复制代码
npm  install

构建项目

arduino 复制代码
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

测试函数

回到函数点击测试

观测云效果

链路上报效果如下:

相关推荐
我先去打把游戏先1 天前
TCP、TLS、HTTP、HTTPS、MQTT、MQTTS几种网络协议的对比与解释
嵌入式硬件·mcu·物联网·网络协议·tcp/ip·http·aws
China_Yanhy2 天前
AWS EC2 挂载新网卡不通?从网卡启动到策略路由的完整排查指南
网络·云计算·aws
在云上(oncloudai)3 天前
Amazon EFS 全面解析
aws·亚马逊云科技
卖芒果的潇洒农民3 天前
AWS EC2
云计算·aws
在云上(oncloudai)7 天前
AWS 成本异常检测(AWS Cost Anomaly Detection)全解析
aws·亚马逊云科技
bluetata7 天前
Spring AI 使用 AWS Amazon Nova 模型
人工智能·spring·aws
翼龙云_cloud8 天前
亚马逊云渠道商:如何解决AWS EC2搭建的网站无法访问?
运维·云计算·aws
EMQX9 天前
大规模使用 AWS IoT Core 的成本困境:EMQX 如何削减 80% 开支
物联网·mqtt·云计算·aws
weixin_307779139 天前
通过AWS Transfer Family集成Active Directory实现安全SFTP文件访问
安全·云计算·aws