本文介绍函数计算集成链路追踪功能的背景、使用场景、核心功能、采样规则配置和开启方式。
背景介绍
阿里云可观测链路 OpenTelemetry版基于OpenTracing标准,兼容开源社区,为分布式应用的开发者提供了完整的分布式调用链查询和诊断,分布式拓扑动态发现,应用性能实时汇总等功能。
函数计算与链路追踪集成,支持使用Jaeger上传链路信息,使您能够跟踪函数的执行,帮助您快速分析和诊断Serverless架构下的性能瓶颈,提高Serverless场景的开发诊断效率。
使用场景
当函数计算与链路追踪集成后,您可以记录请求在函数计算的耗时时间、查看函数的冷启动时间、记录函数内部时间的消耗等。链路追踪功能可以帮助您排查以下问题:
函数执行总超时,需要定位函数的性能瓶颈。
函数执行时间很短,但是端对端时延很长时,需要定位相关原因。
分布式系统中,请求横跨多个云服务,需要分析和诊断函数的性能瓶颈。
核心功能
函数计算的链路追踪功能可以串联整个调用链,包含以下核心功能:
自动记录函数计算内部关键步骤耗时时间。更多信息,请参见自动记录函数计算内部关键步骤耗时。
串联上游服务:如果请求Header中带有链路上下文信息,则函数计算会根据上下文创建子链路。更多信息,请参见串联上游服务。
串联下游服务:函数计算会将链路上下文传入到函数Context参数中,帮助您追踪函数内部调用链路。更多信息,请参见串联下游服务。
查看应用拓扑。
查看错误接口执行情况,定位错误原因。
自动记录函数计算内部关键步骤耗时
服务开启链路追踪功能后,您默认可以看到以下调用链。
Span名称说明如下:
InvokeFunction:当前请求在函数计算的总停留时间。
ColdStart:函数系统层冷启动的时间,冷启动不是每次调用都出现,只在重新申请执行环境时会进行冷启动。
PrepareCode:函数下载代码或下载自定义镜像的时间,如果PrepareCode时间过长,您可以适当精简代码包来缩短准备代码的时间。
RuntimeInitialization:执行环境启动的时间,包含启动实例的时间、实例健康检查时间。在自定义运行时和自定义镜像中,如果RuntimeInitialization执行时间过长,需要检查一下对应的HTTP Server和镜像的启动行为。
Initializer:初始化函数的执行时间,初始化函数当且仅当容器冷启动的时候才会被执行。
Invocation:函数的执行时间,您可以在函数中获取到Invocation的上下文,详细记录函数调用中的耗时。
应用名称:函数计算生成的应用命名方式为FC:ServiceName/FunctionName
当请求没有遇到冷启动时,链路中没有冷启动时间和Initializer的时间。调用链如下所示。
串联上游服务
服务开启链路追踪后,如果请求Header中带有链路上下文信息SpanContext,则函数计算会根据上下文创建子链路。
函数计算识别的链路上下文请求头如下:
x-fc-tracing-opentracing-span-context
:用于传递链路上下文信息SpanContext信息。x-fc-tracing-opentracing-span-context-baggage-
:用于传递跨上下文的Baggage信息。如果有多个Baggage则需要上传多个Header,例如
x-fc-tracing-opentracing-span-context-baggage-key1: val1
,x-fc-tracing-opentracing-span-context-baggage-key2: val2
。
在调用函数时添加链路上下文信息Header即可注入上下文信息。
以Node.js为例:
'use strict';
const FCClient = require('@alicloud/fc2');
/*
阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
本示例以将AccessKey和AccessSecretKey保存在环境变量实现身份验证为例。
运行本示例前,请先在本地环境中设置环境变量ALIBABA_CLOUD_ACCESS_KEY_ID和ALIBABA_CLOUD_ACCESS_KEY_SECRET。
在FC Runtime运行环境下,配置执行权限后,ALIBABA_CLOUD_ACCESS_KEY_ID和ALIBABA_CLOUD_ACCESS_KEY_SECRET环境变量会自动被设置。
*/
var client = new FCClient('<account id>', {
accessKeyID: process.env['ALIBABA_CLOUD_ACCESS_KEY_ID'],
accessKeySecret: process.env['ALIBABA_CLOUD_ACCESS_KEY_SECRET'],
region: 'cn-shanghai',
});
var serviceName = '<service name>';
var funcName = '<function name>';
async function test() {
try {
// 注入Span Context Header信息。
var headers = {
'x-fc-tracing-opentracing-span-context': '124ed43254b54966:124ed43254b5****:0:1',
'x-fc-tracing-opentracing-span-context-baggage-key': 'val'
};
var resp = await client.invokeFunction(serviceName, functionName, 'event', headers = headers);
} catch (err) {
console.error(err);
}
}
串联下游服务
函数计算会将链路上下文传入到函数中,帮助追踪函数内部的调用链路。
对于内置Runtime,可以通过
context.tracing
获取链路上下文信息。对于Custom Runtime或Custom Container,可以通过请求Header获取函数计算链路上下文信息。
x-fc-tracing-opentracing-span-context
:函数计算InvokeFunction的链路上下文,函数内基于此上下文创建追踪段。x-fc-tracing-opentracing-span-baggages
:经过Base64编码的跨上下文Baggage。x-fc-tracing-jaeger-endpoint
:Jaeger的Server端地址,您直接将函数中的追踪段上传至此地址。
context.tracing
结构示例如下:
{
"openTracingSpanContext": "5f22f355044a957a:5708f3a95a4ed10:5f22f355044a****:1",
"openTracingSpanBaggages": {
"key1": "val1",
"key2": "val2"
},
"jaegerEndpoint": "http://tracing-analysis-dc-zb-internal.aliyuncs.com/adapt_fcfc@fcfc@fcfc/api/traces"
}
函数中获取SpanContext示例如下:
Node.js:
exports.handler = (event, context, callback) => { var params = { openTracingSpanContext: context.tracing.openTracingSpanContext, openTracingSpanBaggages:context.tracing.openTracingSpanBaggages, // jaegerEndpoint is confidential, do not print it out easily // jaegerEndpoint:context.tracing.jaegerEndpoint } console.log('tracing params',params) callback(null,'success'); }
PHP:
function handler($event, $ctx) { $logger = $GLOBALS['fcLogger']; $openTracingSpanContext = $ctx['tracing']['openTracingSpanContext']; $openTracingSpanBaggages = $ctx['tracing']['openTracingSpanBaggages']; // jaegerEndpoint is confidential, do not print it out easily $jaegerEndpoint = $ctx['tracing']['jaegerEndpoint']; $logger->info($openTracingSpanContext); $logger->info($openTracingSpanBaggages['key1']); return 'success'; }
Java:
package example; import com.aliyun.fc.runtime.Context; import com.aliyun.fc.runtime.StreamRequestHandler; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class HelloFC implements StreamRequestHandler { public void handleRequest( InputStream inputStream, OutputStream outputStream, Context context) throws IOException { String spanContext = context.getTracing().getOpenTracingSpanContext(); String jaegerEndpoint = context.getTracing().getJaegerEndpoint(); String spanBaggage = context.getTracing().getOpenTracingSpanBaggages().get("key1"); outputStream.write(new String("success").getBytes()); } }
Custom Runtime或Custom Container获取Header即可,以Golang语言为例:
spanContext := req.Header.Get('x-fc-tracing-opentracing-span-context') spanBaggages := req.Header.Get('x-fc-tracing-opentracing-span-baggages') jaegerEndpoint := req.Header.Get('x-fc-tracing-jaeger-endpoint')
自定义采样规则
如果您需要自定义采样规则,您可以登录可观测链路 OpenTelemetry版控制台设置远程采样规则。更多信息,请参见使用Jaeger进行远程采样策略配置。配置完成后,函数计算会使用您设置的远程采样规则采样。
函数计算在链路追踪中对应的服务名称为fc-tracing,默认使用的采样规则为RatelimitingSampler,以每秒1个请求的速率采样。
函数计算使用的默认采样规则如下:
{
"default_strategy": {
"type": "ratelimiting",
"param": 1,
}
}
开启方式
关于链路追踪功能的开启方式,请参见配置链路追踪。