opentelemetry+python+jaeger链路追踪相关使用备注

什么是链路追踪:

在 分布式微服务架构中, 一个请求从用户发起到接收,后端服务可能要经过多个微服务间调用,及多个功能组件(mysql,redis...)和网络请求(http,udp),在这个过程中,任何地方都可能出现错误,导致此次请求失败; 这时就需要 能够掌握请求中每个阶段节点所做的事情,保证出现问题时,能准确迅速定位; 这种记录 请求每个关键节点信息并能以调用链路顺序的方式展现出来 就是链路追踪;

Instrumentation: 英文文档中 此单词含义是 "仪器仪表";在计算机领域中 为 "能够监测和度量某个系统的性能,分析系统错误,并能将追踪的数据进行记录"; 其实就是 检测数据或埋点数据; 理解此单词含义才能更加明白的阅读相关文档;

为什么需要链路追踪:

  • 能通过记录 找到具体出现问题的微服务及错误栈信息;
  • 能清晰梳理出 微服务间调用的流程;对于服务治理很有帮助;
  • 能迅速判断出接口各种异常位置(如bug/耗时过长)

链路追踪行业规范:

最开始时,各家公司厂商有自己的一套链路追踪的数据结构及展示形式,缺点在于 开发者如果想更换链路追踪系统,则代码中链路追踪部分也要修改,造成迁移难度巨大;

后来意识到这个问题,CNCF(Cloud Native Computing Foundation:云原生计算基金会) 出了 一个OpenTracing(基于API的标准,所有遥测或埋点数据必须通过此API标准发送数据到观测后端服务);

google出了一个OpenCensus(提供了一些语言的库,开发者可以使用这些库将数据发送到OpenCensus支持的观测后端服务,如jaeger,zipkin等等);

2019年时, google的OpenCensus和CNCF的OpenTracing 合并为 Opentelemetry(简称 OTel),归为CNCF孵化维护;

Opentelemetry功能:

  • 提供多种语言的库用于手动和自动 生成/发送 监测(或埋点)数据到 不同观测后端的功能;
  • 标准开放的语义定义,确保与后端服务无关的数据收集;

Python中OTel+jaeger实现自动链路追踪功能:

jaeger:uber公司开源的,用go语言实现的一个存储观测数据及提供web端查询的分布式系统; 此工具只支持trace数据格式; 

实现步骤:

docker run -d --name jaeger \
  -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
  -e COLLECTOR_OTLP_ENABLED=true \
  -p 6831:6831/udp \
  -p 6832:6832/udp \
  -p 5778:5778 \
  -p 16686:16686 \
  -p 4317:4317 \
  -p 4318:4318 \
  -p 14250:14250 \
  -p 14268:14268 \
  -p 14269:14269 \
  -p 9411:9411 \
  jaegertracing/all-in-one:1.37
  • 在flask项目中安装如下包:
pip install opentelemetry-distro
pip install opentelemetry-propagator-jaeger
pip install opentelemetry-exporter-jaeger
  • 在项目虚拟环境中执行如下命令 来 安装自动收集各种监测数据用到的各种包;如mysql,redis,mongo,requests,grpc等等...;此命令会根据此项目目前代码安装可能用到的包;
opentelemetry-bootstrap -a install
  • python代码部分(代码无法直接运行,需要修改flask的create_app相关代码;)
import json
import os
from random import randint
import traceback
import click
from flask import request
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry.instrumentation.grpc import GrpcInstrumentorClient
from opentelemetry.instrumentation.pymongo import PymongoInstrumentor
from opentelemetry.instrumentation.redis import RedisInstrumentor
from opentelemetry.instrumentation.requests import RequestsInstrumentor
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
from opentelemetry.propagators.jaeger import JaegerPropagator
from opentelemetry.trace import Span

from app import create_app
from app.utils import json_success

os.environ["LC_ALL"] = "en_US.utf-8"
os.environ["LANG"] = "en_US.utf-8"

from opentelemetry import trace
from opentelemetry.exporter.jaeger.thrift import JaegerExporter
from opentelemetry.sdk.resources import SERVICE_NAME, Resource, SERVICE_NAMESPACE
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor

from opentelemetry.propagate import set_global_textmap

# 设置 全局的从请求头中获取trace信息的方式为 Jaeger的uber-trace-id;其他的方式如 b3 等等;
# 设置此选项,使微服务间能够根据 http请求头的uber-trace-id 将 跨多个微服务的请求归为同一个trace中,方便查看
set_global_textmap(JaegerPropagator())
# 设置trace的服务名及命令空间
resource = Resource(attributes={
    SERVICE_NAME: "project_name",
    SERVICE_NAMESPACE: "test_env",
})
# 设置trace数据导出服务 为jaeger; 通过jaeger服务的6831(UDP协议)端口上传;
jaeger_exporter = JaegerExporter(
    agent_host_name="localhost",
    agent_port=6831,
)
# 设置trace
provider = TracerProvider(resource=resource)
# 将trace中每个span数据发送给jaeger的方式,SimpleSpanProcessor(直接传输),其他如:BatchSpanProcessor(批量传输),ConcurrentMultiSpanProcessor(多线程并发传输)...
processor = SimpleSpanProcessor(jaeger_exporter)
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)

# 自动生成span数据的各种涉及到IO的插件部分; 如 requests,grpc,mongo,redis,sqlalchemy等等;
# 所有python可用自动埋点的插件在 https://github.com/Rgcsh/opentelemetry-python-contrib/tree/main/instrumentation 目录下
# 注意 多数插件必须在 flask app生成之前定义;否则无法自动生成span(埋点失败)
RequestsInstrumentor().instrument()
GrpcInstrumentorClient().instrument()
SQLAlchemyInstrumentor().instrument(enable_commenter=True, commenter_options={})
PymongoInstrumentor().instrument()
RedisInstrumentor().instrument()

app = create_app()


def request_hook(span: Span, _):
    """
    flask请求进入时 在before_request中的hook函数;可以将一些请求数据(如请求参数等等) 放到span中
    :param span:
    :param _:
    :return:
    """

    def request_params():
        """ 获取当前请求的参数
        """
        request_params = dict()

        # 获取请求参数
        request_params.update(request.args.to_dict())

        # 获取form表单中的参数
        request_params.update(request.form.to_dict())

        # 获取json参数
        json_params = None
        try:
            json_params = getattr(request, "json", None)
        except Exception:
            pass

        if isinstance(json_params, dict):
            request_params.update(json_params)
        if len(str(request_params)) > 1000:
            return "部分截取入参:" + str(request_params)[-1000:]
        return request_params

    # 在span中添加一些额外的数据,值不能 为dict类型(否则无法显示在jaeger UI上);
    span.set_attributes(
        {"request.params": json.dumps(request_params()) or '',
         "request.uid": request.headers.get("Access-User") or ''})


# 对flask框架进行埋点,基本就是 生成一个请求相关的span数据
# 此插件必须在flask app生成之后调用
FlaskInstrumentor().instrument_app(app, request_hook=request_hook)

# 获取一个全局的trace,在手动埋点时使用
tracer = trace.get_tracer(__name__)


@app.route("/roll", methods=["POST"])
def roll_dice():
    """
    一个测试路由
    :return:
    """
    # 手动设置span数据
    with tracer.start_as_current_span("do_roll") as rollspan:
        res = randint(1, 6)

        rollspan.set_attribute("roll.value", res)
        # 遇到错误时,可以通过此方式上传 错误栈span;
        rollspan.set_attributes({"error": "true", "stacktrace": traceback.format_exc()})
    return json_success()


@click.command()
@click.option("--port", "-p", help="Server run port", default=8080)
@click.option("--host", "-h", help="Server run host", default="0.0.0.0")
def start(host, port):
    """ 开启实例

    :param host: 监听的主机
    :param port: 监听的端口
    """
    app.run(host=host, port=int(port))


if __name__ == "__main__":
    start()

监测效果:

代码示例说明:

微服务间通过请求头中的uber-trace-id的值作为trace_id的值来关联,保证他们属于同一个trace;

每个自动化生成检测数据 插件有其自身的 参数可以定义,实现额外的自定义功能;

总结:

opentelemetry(OTel)提供了常用语言(java,go,python等等)的库供开发者使用,用于自动或手动 生成检测数据并传输到众多后端检测服务中 的功能; 

OTel python sdk推荐使用>=python3.7版本,但是在python3.6中也能使用,只是时间精度只能达到毫秒级别,无法达到纳秒级别;

作为开发者需要做的就是使用OTel及出现问题时,会使用web ui工具排查问题即可;

相关链接:

Getting Started — Jaeger documentation

OpenTelemetry - CNCF · GitHub

GitHub - open-telemetry/opentelemetry-python: OpenTelemetry Python API and SDK

GitHub - open-telemetry/opentelemetry-python-contrib: OpenTelemetry instrumentation for Python modules

Getting Started | OpenTelemetry

OpenTelemetry-Python API Reference — OpenTelemetry Python documentation

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Jaeger链路追踪是一种用于监控和追踪分布式系统中请求的工具。它可以帮助开发人员跟踪请求在系统中的传递路径,并提供详细的性能指标和错误信息。Jaeger的安装可以参考官方地址\[1\]和相关教程\[2\]。Jaeger由多个组件组成,包括Agent、Collector、Query Service等\[2\]。 在使用Go语言进行Jaeger链路追踪时,可以通过Jaeger客户端发送单个或多个span来追踪请求\[3\]。同时,还可以使用grpc发送span消息\[3\]。在Gin框架中,可以通过添加拦截器实现Jaeger的注入\[3\]。此外,还可以修改grpc_opentracing源码来实现Gin和gRPC的追踪\[3\]。 总结来说,Jaeger链路追踪是一种用于监控和追踪分布式系统中请求的工具,可以帮助开发人员跟踪请求的传递路径和性能指标。在Go语言中,可以使用Jaeger客户端发送span来实现链路追踪,并通过拦截器和修改源码来实现Gin和gRPC的追踪。 #### 引用[.reference_title] - *1* [【链路追踪Jaeger基于go的「Gin」「gRPC」进行链路追踪](https://blog.csdn.net/the_shy_faker/article/details/129044832)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [35、jaeger链路追踪](https://blog.csdn.net/qq23001186/article/details/126339369)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值