技术分享 | jaeger链路日志实现

源宝导读:随着企业应用越来越复杂,内部的调用链条越来越长,性能问题也变得越来越难以定位和排查,为了应对此问题,我们在移动平台中引入了“jaeger调用链追踪工具”,帮助我们高效定位云端服务的性能问题。本文将分享我们相关的技术实践。

一、背景

    大家好,很幸运代表团队和大家分享一下,天际-移动平台团队在实现分布式链路日志追踪过程的心路历程。移动应用的后台服务,其内部调用链路往往很复杂,一旦发现性能问题,很难快速精准的定位,严重影响研发小伙伴们的幸福感。具体问题表现在这几个方面:

  • 容器内日志简单,某些前后端数据不一致导致的的问题无法定位。

  • PaaS小程序微服务化,服务之间调用虽然有严格规定,但是出现问题时还是无法快速定位问题的出处。

  • 测试人员登记bug需要粘贴详细的请求、响应,开发通过创造数据,模拟这个请求来慢慢排查问题所在。

二、技术选型

移动平台中关于PaaS小程序后端的现有架构:

    从上图中可知,我们当前同时支持了PHP、Go、Nodejs三种编程语言构建的应用,如果要做日志的链路追踪,起码需要兼容多编程语言。

    通过分析,我们总结出“日志追踪工具”应满足的条件:

  • 支持多语言。保证PHP、Go、Nodejs都可以接入日志,才能形成完整链路。

  • 一定是无侵入式的。这样在多个服务中埋点比较方便,日志服务升级维护成本也不会高。

  • 对于特定标签的日志可以通过微信、邮箱甚至短信的方式通知到开发或者运维同学。

  • 能够对API接口的性能统计分析。

  • 由于我们使用的阿里云日志,日志服务最好可以将阿里云日志作为数据存储。

三、jaeger工具介绍

3.1、简介

    Jaeger是由Uber开源的分布式追踪系统,一套完整的Jager追踪系统包括Jaeger-client、Jaeger-agent、Jaeger-collector、Database和Jaeger-query UI等基本组件。

3.2、Jaeger的优势

  • 采用Open Tracing标准,支持跨语言。

  • 分布式上下文传播。

  • 分布式是链路追踪。

  • 服务依赖性分析。

  • 性能延迟监控。

3.3、jaeger的技术原理

架构图:

  • jaeger-client:jaeger 的客户端,实现了opentracing协议。

  • jaeger-agent:jaeger-client 的一个代理程序,client将收集到的调用链数据发给agent,然后由agent发给collector。

  • jaeger-collector:负责接收jaeger client或者jaeger agent上报上来的调用链数据,然后做一些校验,比如时间范围是否合法等,最终会经过内部的处理存储到后端存储。后端存储是一个可插拔的组件,Jaeger on Aliyun Log Service 增加了对阿里云日志服务的支持。

  • jaeger-query:专门负责调用链查询的一个服务,有自己独立的UI。

  • spark-job:基于spark的运算任务,可以计算服务的依赖关系,调用次数等。

    说明:其中jaeger-collector和jaeger-query是必须的,其余的都是可选的,我们采用agent上报的方式,让客户端上报日志到agent,以减少部分性能消耗。jaeger-collector支持Aliyun Log Service,也是很好的满足我们要求。

    aliyun-log-jaeger-collector配置表:

3.4、日志

单条链路:

    可以清晰的看到一个请求的发起时间,所经过的服务数量、所调用服务的依赖关系、消耗的时长等信息。

3.5、技术名词解释

  • service:微服务的名称或者标识。

  • operation:一个span的名称,简单易读。

  • span:系统中具有开始时间和执行时长的逻辑运行单元 。具体可以理解为一次方法调用, 一个程序块的调用或者一次RPC/数据库访问。

  • tags:“键值对”形式的tags,一个span可以有多tags,tags是对span的简单注解,不会被子级span继承。tags value 的标准含义看参考https://opentracing.io/ specification/conventions

  • logs:一个span可以有多logs,每一个logs都可以自定名称以及任意大小的存储结构。

  • spanContext:跨进程边界,传递到下级span的状态,每个span都有访问spanContext的方法。当在创建span时,向传输协议Inject(注入)从上级span传输协议中Extract(提取)的spanContext既可。

  • Inject and Extract:spanContext可以通过Injected操作向Carrier增加,或者通过ExtractedCarrier中获取,跨进程通讯数据。通过这种方式,SpanContexts可以跨越进程边界,并提供足够的信息来建立跨进程的span间关系(因此可以实现跨进程连续追踪)。

四、落地应用

4.1、  核心设计思路:

  • 采用jaeger-client上报数据到jaeger-agent,再由jaeger-agent集中处理传输到jaeger-collector,之后jaeger-collector会将合法的数据存储到阿里日志。

  • 之后在我们需要时,可以通过jaeger-query + jaeger-ui来查询日志。

  • 我们采用jaeger的默认方式,将spanContext中跨进程数据(当前只有uber-trace-id)注入到header中,当下游服务在请求header中提取到对应的跨进程数据就会形成一个依赖和链路关系,如果没有就生成一个新的供下游服务发现和关联。

4.2、traceId传递方式

//  上游服务将traceId注入到header中
    $header = TraceJaeger::inject($header);
// 下游服务解析获取traceId,完成一个请求的传递
$target = [];
foreach (request()->headers->all() as $key => $value) {
    $target[$key] = Arr::first($value);
}
$spanContext = $this->tracer->extract(TEXT_MAP, $target);

4.3、应用结果

串行

traceId:1660cc5871c2df9e1660cc5871c34a59

并行

traceId:1660d1de34f6c7691660d1de34f5a93b

    以上都是我们实际的调用场景,应用创建的改造前(串行),改造后(并行)。可以很清晰的看到服务之间的调用和所花费的时间。

    我们打开可以看到app-service这个服务被调用的详细信息。包括请求方式、请求数据、响应数据等。

4.4、兼容Go语言

1、go服务gin中间件使用开源框架,代码仓库:https://github.com/yuchanns/bullets

go get -u github.com/yuchanns/bullets

2、中间件使用:

package main
import (
   "context"
   "github.com/gin-gonic/gin"
   "github.com/yuchanns/bullets/common"
   "github.com/yuchanns/bullets/common/middlewares"
   "os"
)
func main() {
   g := gin.Default()
   //服务名
   serviceName := "openapi-service"
   //上报agent地址
   agentAddr := os.Getenv("OPENTRACING_AGENT")
   //操作前缀
   operationPrefix := []byte("api-request-")
   opentracerCloseFunc, opentracerMiddleware, err := middlewares.BuildOpe
   nTracerInterceptor(serviceName, agentAddr, operationPrefix)
   if err != nil {
      common.Logger.Error(context.Background(), err)
   } else {
      defer opentracerCloseFunc()
      g.Use(opentracerMiddleware)
   }
}

3、自定义打tag:

import (
   "github.com/gin-gonic/gin"
   "github.com/opentracing/opentracing-go"
   "github.com/opentracing/opentracing-go/log"
   "github.com/pkg/errors"
)
func CustomTag(ctx *gin.Context) {
   if cspan, ok := ctx.Get("tracing-context"); ok {
      if span, ok := cspan.(opentracing.Span); ok {
         span.SetTag("error", true)
         span.LogFields(log.Error(errors.New("err")))
         span.LogFields(log.String("exampleKey", "stringValue"))
      }
   }
}

4.5、兼容PHP语言

1、安装composer包

composer require tracelog/jaeger

2、根目录执行

php artisan vendor:publish

3、选择发布配置⽂件

Tracelog\jaeger\config\jaeger.php文件拷贝到工程项目的config⽬录

4、修改配置⽂件

return[
    'enabled' => env('JAEGER_ENABLED', true), //是否开启
    'service_name' => env('JAEGER_SERVICE_NAME', env('APP_NAME', 'Laravel')), //服务名称
    'agent' => [ 'host' => env('OPENTRACING_AGENT','0.0.0.0:6831'), //日志服务代理 地址
    ],
    'watchers' => [
        Tracelog\jaeger\watchers\RequestWatcher::class, //请求日志监听
        Tracelog\jaeger\watchers\FrameworkWatcher::class //项目日志推送
    ]
]

使⽤ jukylin/jaeger-php 直接记录。

参考:https://github.com/jukylin/jaeger-php/blob/master/example/HTTP.php

4.6、集成到Laravel Log

    使⽤框架中Log⻔⾯时,也可以将日志记录到代理。针对当前框架情况修改(添加)/app/Common/StreamHandler ---> Handle

if (config('jaeger.enabled')){
    $span = TraceJaeger::client()->startSpan($record['message'],['child_of' => TraceJaeger::getRootSpan()]);
    $span->setTag('log.level', $record['level_name']);
    $span->log($record['context']);
    $span->finish();
    TraceJaeger::client()->flush();
}

说明:对Nodejs的兼容,我们目前正在实现中。

五、总结

    自从链路日志工具上线后,我们排查问题的效率有了很大提升。我们可以直接通过日志定位出有问题的后端服务,通过请求和响应数据快速判断问题原因,极大的提高了工作效率和排查问题的幸福感!

------ END ------

作者简介

智同学: 研发工程师,目前负责天际-移动平台的研发工作。

也许您还想看

记AWSS3在iOS端的一次改造事件

明源云创CI/CD技术演进

微前端架构在容器平台的应用

AI云店小程序演变之路

天眼探针基于rrweb实现前端异常视频录制与回放功能

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
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 ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值