本文介紹Node.js運行環境的鏈路追蹤相關內容。
背景資訊
阿里雲鏈路追蹤服務(Tracing Analysis)基於OpenTracing標準,相容開源社區,為分布式應用的開發人員提供了完整的分布式調用鏈查詢和診斷、分布式拓撲動態發現、應用效能即時匯總等功能。
Function Compute與鏈路追蹤整合後,支援使用Jaeger SDK和OpenTelemetry上傳鏈路資訊,使您能夠跟蹤函數的執行,協助您快速分析和診斷Serverless架構下的效能瓶頸,提高Serverless情境的開發診斷效率。
功能簡介
您可以在Function Compute控制台配置鏈路追蹤。具體操作,請參見配置鏈路追蹤。
為服務開啟鏈路追蹤後,Function Compute會自動記錄請求在系統側的耗時,包含冷啟動耗時、Initializer函數的耗時和函數的執行時間等。關於下圖中系統Span的說明,請參見Span名稱說明。
如您還需查看函數內業務側的耗時,例如,在函數內訪問RDS或NAS等服務的耗時,可以通過建立自訂Span來實現。
範例程式碼
Function Compute的鏈路分析基於OpenTracing協議的Jaeger實現,Node.js運行時提供以下兩種方式自訂Span。
使用OpenTelemetry(推薦)
在Node.js語言的代碼中,您可以通過OpenTelemetry SDK手動埋點將資料上報到鏈路追蹤服務端。完整的範例程式碼,請參見nodejs-tracing-openTelemetry。
範例程式碼解析如下。
- 在工程目錄中配置依賴檔案package.json。
"dependencies": { "@opentelemetry/api": "^1.0.2", "@opentelemetry/exporter-jaeger": "0.25.0", "@opentelemetry/exporter-zipkin": "0.25.0", "@opentelemetry/instrumentation": "0.25.0", "@opentelemetry/instrumentation-http": "0.25.0", "@opentelemetry/resources": "0.25.0", "@opentelemetry/semantic-conventions": "0.25.0", "@opentelemetry/sdk-trace-node": "0.25.0", "@opentelemetry/sdk-trace-base": "0.25.0" }
- 上報資料到鏈路追蹤服務端。
module.exports.handler = function(event, context, callback) { tracer = require('./tracer')('fc-tracer',context.tracing.jaegerEndpoint); var spanContext = contextFromString( context.tracing.openTracingSpanContext); startMySpan(spanContext); callback(null,'success'); }
- 建立一個
tracer
對象,用於建立Span。module.exports = (serviceName,endpoint) => { const provider = new NodeTracerProvider({ resource: new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: serviceName, }), }); let exporter = new JaegerExporter({endpoint:endpoint}); provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); provider.register(); registerInstrumentations({ instrumentations: [ new HttpInstrumentation(), ], }); return opentelemetry.trace.getTracer('http-example'); };
- 擷取Function Compute上下文的Tracing資訊,轉換為SpanContext。
function contextFromString(value){ const arr = value.split(`:`); const spanContext={ traceId:`0000000000000000`+arr[0], spanId:arr[1], traceFlags:api.TraceFlags.SAMPLED, isRemote:true } return spanContext; }
- 建立
tracer
並通過轉換的Context建立子Span。每一個Span代表調用鏈中被命名並計時的連續性執行片段,您也可以基於該Span繼續建立子Span。function startMySpan(spanContext){ var FcSpan=api.trace.wrapSpanContext(spanContext); var ctx = api.trace.setSpan(api.ROOT_CONTEXT,FcSpan); tracer.startActiveSpan("fc-operation",undefined,ctx,parentSpan => { parentSpan.setAttribute("version","fc-v1"); sleep(150); child(); parentSpan.end() }) } function child(){ tracer.startActiveSpan("fc-operation-child",span =>{ sleep(100); span.addEvent("timeout"); span.end(); }) }
使用Jaeger SDK
您可以通過Jaeger SDK埋點,將資料上報到鏈路追蹤服務端。完整的範例程式碼,請參見nodejs-tracing。
範例程式碼解析如下。
- 在工程目錄中配置依賴檔案package.json。
"dependencies": { "jaeger-client": "^3.19.0" }
- 上報資料到鏈路追蹤服務端。
module.exports.handler = function(event, context, callback) { tracer=newTracer(context); var invokeSpanContext = spanContext.fromString(context.tracing.openTracingSpanContext); startMySpan(invokeSpanContext); callback(null,'success') }
- 根據上下文的Tracing資訊,建立一個
tracer
對象。function newTracer(context){ var config = { serviceName: 'fc-tracer', reporter: { // Provide the traces endpoint; this forces the client to connect directly to the Collector and send spans over HTTP collectorEndpoint: context.tracing.jaegerEndpoint, flushIntervalMs: 10, }, sampler: { type: "const", param: 1 }, }; var options = { tags: { 'version': 'fc-v1', }, }; var tracer = initTracer(config, options); return tracer }
- 轉換SpanContext對象並建立自訂Span,您也可以基於該Span繼續建立子Span。
function startMySpan(spanContext){ var parentSpan = tracer.startSpan("fc-operation", { childOf: spanContext }); sleep(150); child(parentSpan.context()) parentSpan.finish(); } function child(spanContext){ var childSpan = tracer.startSpan("fc-operation-child", { childOf: spanContext }); childSpan.log({event:"timeout"}); sleep(100); childSpan.finish(); }