本文介紹Python運行環境的鏈路追蹤相關內容。

背景信息

阿里云鏈路追蹤服務(Tracing Analysis)基于OpenTracing標準,兼容開源社區,為分布式應用的開發者提供了完整地分布式調用鏈查詢和診斷、分布式拓撲動態發現、應用性能實時匯總等功能。

函數計算與鏈路追蹤集成后,支持使用Jaeger SDKOpenTelemetry上傳鏈路信息,使您能夠跟蹤函數的執行,幫助您快速分析和診斷Serverless架構下的性能瓶頸,提高Serverless場景的開發診斷效率。

功能簡介

您可以在函數計算控制臺配置鏈路追蹤。具體操作,請參見配置鏈路追蹤

為服務開啟鏈路追蹤后,函數計算會自動記錄請求在系統側的耗時,包含冷啟動耗時、Initializer函數的耗時和函數的執行時間等。關于下圖中系統Span的說明,請參見Span名稱說明鏈路追蹤

如您還需查看函數內業務側的耗時,例如,在函數內訪問RDS,NAS等服務的耗時,可以通過創建自定義Span來實現。

示例代碼

函數計算的鏈路分析基于OpenTracing協議的Jaeger實現,Python運行時提供使用OpenTelemetry的方式自定義Span。

在Python語言的代碼中,您可以通過OpenTelemetry SDK手動埋點將數據上報到鏈路追蹤服務端。完整的示例代碼,請參見python-tracing-openTelemetry

示例代碼解析如下。
  • 在工程目錄中配置依賴文件requirements.txt
    opentelemetry-api==1.12.0
    opentelemetry-sdk==1.12.0
    opentelemetry-exporter-jaeger==1.12.0
  • 上報數據到鏈路追蹤服務端。
    trace.set_tracer_provider(
        TracerProvider(
            resource=Resource.create({SERVICE_NAME: "my-helloworld-service"})
        )
    )
    tracer = trace.get_tracer(__name__)
    def handler(event, context):
        init_tracer(context.tracing.jaeger_endpoint)
        span_context = get_fc_span(context.tracing.span_context)
        start_my_span(trace.set_span_in_context(NonRecordingSpan(span_context)))
        return 'hello world'
  • 初始化一個tracer對象,提供對Tracers的訪問。
    def init_tracer(endpoint):
        jaeger_exporter = JaegerExporter(
            collector_endpoint=endpoint
        )
    
        span_processor = SimpleSpanProcessor(jaeger_exporter)
    
        trace.get_tracer_provider().add_span_processor(span_processor)
  • 獲取上下文的Tracing信息,轉換為SpanContext對象。
    def get_fc_span(jaeger_span_context):
        jaeger_span_context_arr = jaeger_span_context.split(":")
        tid = int(jaeger_span_context_arr[0], 16)
        sid = int(jaeger_span_context_arr[1], 16)
    
        span_context = trace.SpanContext(
            trace_id=tid,
            span_id=sid,
            is_remote=True,
            trace_flags=trace.TraceFlags(0x01),
        )
        return span_context
  • 創建tracer并通過轉換的Context創建子Span。每一個Span代表調用鏈中被命名并計時的連續性執行片段,您也可以基于該Span繼續創建子Span。
    def start_my_span(context):
        with tracer.start_as_current_span(name="fc-operation", context=context):
            time.sleep(0.15)
            with tracer.start_as_current_span("child"):
                time.sleep(0.1)