分布式追踪系统Jaeger

前言

随着公司的发展,业务不断增加,模块不断拆分,系统间业务调用变得越复杂,对定位线上故障带来很大困难。整个调用链不透明,犹如系统被蒙上一块黑纱,当线上遇到故障时,整个技术部就陷入痛苦的漩涡。这时候分布式追踪系统应运而生,如揭开了黑纱,让阳光照进黑暗。

一、Jaeger介绍

Jaeger是Uber开发的一套分布式追踪系统,已在Uber大规模使用。并在2017-9-13 加入CNCF 开源组织。使用Jaeger可以非常直观的展示整个分布式系统的调用链,由此可以很好发现和解决问题:
在这里插入图片描述
Jaeger 架构
在这里插入图片描述
如上图所示,Jaeger 主要由以下几部分组成。

  1. Jaeger-Client - 为不同语言实现了符合 OpenTracing 标准的 SDK。应用程序通过 API 写入数据,client library 把 trace 信息按照应用程序指定的采样策略传递给 jaeger-agent(Jaeger-Client相当于是埋点采集数据,然后发送给Jaeger-Agent)。
  2. Jaeger-Agent - 它是一个监听在 UDP 端口上接收 span 数据的网络守护进程,它会将数据批量发送给 collector。它被设计成一个基础组件,部署到所有的宿主机上。Agent 将 client library 和 collector 解耦,为 client library 屏蔽了路由和发现 collector 的细节。
  3. Jaeger-Collector - 接收 jaeger-agent 发送来的数据,然后将数据写入后端存储。Collector 被设计成无状态的组件,因此您可以同时运行任意数量的 jaeger-collector。
  4. Data Store - 后端存储被设计成一个可插拔的组件,支持将数据写入 cassandra、elastic search。
  5. Jaeger-Query - 接收查询请求,然后从后端存储系统中检索 trace 并通过 UI 进行展示。Query 是无状态的,您可以启动多个实例,把它们部署在 nginx 这样的负载均衡器后面。

Jaeger 作用
分布式环境下信息传播
分布式事物监控
展示跨进程调用链
服务依赖分析
性能/延迟优化
问题根源分析

Jaeger特性
使用udp传输数据,相对于HTTP,优点在于,不用担心Jaeger服务宕机或者网络传输有问题而影响正常的业务。缺点就是丢包,影响了整条调用链。

总结:就是在一个分布式系统的每个要追踪的机器上面安装agent,然后在代码里面埋点,将要采集的的信息发送给当前机器上面的agent。然后所有agent将各个机器上面采集到的相关埋点信息统一发送给collector,collector再把这些数据存储到相关物理数据库中,以供前端查询和展示。

二、Jaeger安装

2.1 Jaeger-agent安装

下载地址:https://github.com/jaegertracing/jaeger/releases

wget https://github.com/jaegertracing/jaeger/releases/download/v1.16.0/jaeger-1.16.0-linux-amd64.tar.gz
tar zxf jaeger-1.16.0-linux-amd64.tar.gz
cd jaeger-1.16.0-linux-amd64

jaeger的二进制发行包包含五个二进制文件:

  1. jaeger-agent
  2. jaeger-collector
  3. jaeger-query
  4. jaeger-standalone
  5. jaeger-ingester

如果下载太慢的话,可以去我这里下载:https://download.csdn.net/download/gaitiangai/12351738

2.2 选择存储

trace数据总要存在一个地方。jaeger支持ES和Canssandra两种后端DB。国内用ES的多一点,我们就以ES为例,来介绍其安装方式。ES请先自行安装。也可参见我的另一篇文章:https://blog.csdn.net/gaitiangai/article/details/105701721

2.3 启动

由于命令都有很多参数,所以我们可以创建几个脚本,来支持jaeger的启动。
vim start-collector.sh
export SPAN_STORAGE_TYPE=elasticsearch
nohup ./jaeger-collector --es.server-urls http://172.17.20.141:9200/ --log-level=debug>> collector.log 2>&1 &

start-agent.sh
export SPAN_STORAGE_TYPE=elasticsearch
nohup ./jaeger-agent --collector.host-port=172.17.20.140:14267 --discovery.min-peers=1 --log-level=debug >> agent.log 2>&1 &

start-query.sh
export SPAN_STORAGE_TYPE=elasticsearch
nohup ./jaeger-query --span-storage.type=elasticsearch --es.server-urls=http://172.17.20.141:9200/ >> query.log 2>&1 &
访问:http://172.17.20.140:16686/search

2.4 端口整理

1)Agent

  • 5775 UDP协议,接收兼容zipkin的协议数据
  • 6831 UDP协议,接收兼容jaeger的兼容协议
  • 6832 UDP协议,接收jaeger的二进制协议
  • 5778 HTTP协议,数据量大不建议使用
  • 14271 HTTP协议,管理服务的端口,包括健康检查

它们之间的传输协议都是基于thrift封装的。我们默认使用5775作为传输端口。

2)Collector

  • 14267 tcp agent发送jaeger.thrift格式数据
  • 14250 tcp agent发送proto格式数据(背后gRPC)
  • 14268 http 直接接受客户端数据
  • 14269 http 健康检查

3)Query

  • 16686 http jaeger的前端,放给用户的接口
  • 16687 http 健康检查

至此,我们的jaeger就安装完毕。

2.5 命令帮助

./jaeger-agent help

2.6.客户端

go:https://github.com/jaegertracing/jaeger-client-go
php:https://github.com/jukylin/jaeger-php
java:https://github.com/jaegertracing/jaeger-client-java
python:https://github.com/jaegertracing/jaeger-client-python
node:https://github.com/jaegertracing/jaeger-client-node

官方提供了 go,java,node,python客户端,其他客户端还在开放中,php客户端为个人开发

2.7 数据采集策略

Jaeger 官方提供了多种采集策略,使用者可以按需选择使用

  • ConstSampler,全量采集
  • ProbabilisticSampler ,概率采集,默认万份之一
  • RateLimitingSampler ,限速采集,每秒只能采集一定量的数据
  • RemotelyControlledSampler ,一种动态采集策略,根据当前系统的访问量调节采集策略

三、使用-PHP

3.1 常规安装

3.1.1 php7安装

yum install -y gcc gcc-c++  make zlib zlib-devel pcre pcre-devel  libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel glibc glibc-devel glib2 glib2-devel bzip2 bzip2-devel ncurses ncurses-devel curl curl-devel e2fsprogs e2fsprogs-devel krb5 krb5-devel openssl openssl-devel openldap openldap-devel nss_ldap openldap-clients openldap-servers
wget https://www.php.net/distributions/php-7.1.31.tar.gz
tar -zxvf php-7.1.31.tar.gz
cd php-7.1.31
ln -s /usr/lib64/libssl.so /usr/lib
./configure --prefix=/data/webserver/php7 --with-config-file-path=/data/webserver/php7 --enable-mbstring --enable-ftp --with-gd --with-jpeg-dir=/usr --with-png-dir=/usr --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd --without-pear --enable-sockets --with-freetype-dir=/usr --with-zlib --with-libxml-dir=/usr --with-xmlrpc --enable-zip --enable-fpm --enable-xml --enable-sockets --with-gd --with-zlib --with-iconv --enable-zip --with-freetype-dir=/usr/lib/ --enable-soap --enable-pcntl --enable-cli --with-curl --with-openssl
make
make install
cp /data/webserver/php7/etc/php-fpm.d/www.conf.default /data/webserver/php7/etc/php-fpm.d/www.conf
cp php.ini-production /data/webserver/php7/etc/php.ini
cp ./sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm7
chmod +x /etc/init.d/php-fpm7

如果报错:

-fvisibility=hidden -DZEND_SIGNALS   -c /root/jaeger/php/php-7.1.31/ext/gd/gd.c -o ext/gd/gd.lo 
In file included from /root/jaeger/php/php-7.1.31/ext/gd/gd.c:77:
/usr/include/ft2build.h:56:38: error: freetype/config/ftheader.h: No such file or directory
/root/jaeger/php/php-7.1.31/ext/gd/gd.c:78:12: error: #include expects "FILENAME" or <FILENAME>
make: *** [ext/gd/gd.lo] Error 1

解决

ln -s /usr/include/freetype2/freetype/ /usr/include/freetype

3.1.2 安装composer

composer官方文档详见https://docs.phpcomposer.com/01-basic-usage.html

wget  https://getcomposer.org/installer   #下载文件
/data/webserver/php7/bin/php installer  #把下载下来的文件使用你的PHP7执行一下

要检查 Composer 是否正常工作,只需要通过 php 来执行 PHAR:

/data/webserver/php7/bin/php composer.phar

3.1.3 安装jaeger-php

在composer的下载目录下新建 composer.json 文件如下:

vim composer.json
{
  "minimum-stability": "dev",
  "require": {
    "jukylin/jaeger-php" : "^2.0",
    "opentracing/opentracing":"1.0.0-beta5"
  }
}

执行安装:

/data/webserver/php7/bin/php composer.phar install    

执行完毕会在当前目录下载一个vendor文件夹,这里面包含的就是我们想要的Jaeger-PHP相关文件:

ls vendor/           #查看安装的包,如下
autoload.php  composer  jukylin  opentracing  packaged

一句话总结,安装PHP7 和 composer 都是为了可以下载最终的这个vendor文件夹。

于是,我们的简易安装方法也就来了。

3.1 简易安装

去我的资源里面下载我下载好的相关文件,解压,放到你的项目路径路径下就可以使用了。

3.2 测试

创建 test.php 文件如下:

<?php
/*
 * Copyright (c) 2019, The Jaeger Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

echo "afadafadfafaf11111111<br>";

echo '/home/wwwroot/default/vendor'. '/autoload.php<br>';
require_once '/home/wwwroot/default/vendor'. '/autoload.php';

echo "afadafadfafaf222222222222<br>";
use Jaeger\Config;
use GuzzleHttp\Client;
use OpenTracing\Formats;
use OpenTracing\Reference;
unset($_SERVER['argv']);

//init server span start
$config = Config::getInstance();
$config->gen128bit();

$config::$propagator = Jaeger\Constants\PROPAGATOR_ZIPKIN;

echo "afadafadfafaf<br>";
$tracer = $config->initTracer('First_Tracer', '0.0.0.0:6831');

$injectTarget = [];
$spanContext = $tracer->extract(Formats\TEXT_MAP, $_SERVER);
$serverSpan = $tracer->startSpan('FirstSpan', ['child_of' => $spanContext]);
$serverSpan->addBaggageItem("version", "1.8.9");
print_r($serverSpan->getContext());
$tracer->inject($serverSpan->getContext(), Formats\TEXT_MAP, $_SERVER);

//init server span end
$clientTracer = $config->initTracer('Second_Tracer');

//client span1 start
$injectTarget1 = [];
$spanContext = $clientTracer->extract(Formats\TEXT_MAP, $_SERVER);
echo "=======<br>";
var_dump($spanContext);
$clientSpan1 = $clientTracer->startSpan('Second_Apan', ['child_of' => $spanContext]);
$clientTracer->inject($clientSpan1->spanContext, Formats\TEXT_MAP, $injectTarget1);
echo "=======<br>";
var_dump($injectTarget1);

$method = 'GET';
$url = 'https://github.com/';
//$client = new Client();
//$res = $client->request($method, $url,['headers' => $injectTarget1]);

$clientSpan1->setTag('http.status_code', 200);
$clientSpan1->setTag('http.method', 'GET');
$clientSpan1->setTag('http.url', $url);

$clientSpan1->log(['message' => "HTTP1 ". $method .' '. $url .' end !']);
$clientSpan1->finish();
//client span1 end

//client span2 start
$injectTarget2 = [];
$spanContext = $clientTracer->extract(Formats\TEXT_MAP, $_SERVER);
$clientSpan2 = $clientTracer->startSpan('HTTP2',
    ['references' => [
        Reference::create(Reference::FOLLOWS_FROM, $clientSpan1->spanContext),
        Reference::create(Reference::CHILD_OF, $spanContext)
    ]]);

$clientTracer->inject($clientSpan2->spanContext, Formats\TEXT_MAP, $injectTarget2);

$method = 'GET';
$url = 'https://github.com/search?q=jaeger-php';
//$client = new Client();
//$res = $client->request($method, $url, ['headers' => $injectTarget2]);

$clientSpan2->setTag('http.status_code', 200);
$clientSpan2->setTag('http.method', 'GET');
$clientSpan2->setTag('http.url', $url);

$clientSpan2->log(['message' => "HTTP2 ". $method .' '. $url .' end !']);
$clientSpan2->finish();
//client span2 end

//server span end
$serverSpan->finish();
//trace flush
$config->flush();

echo "success<br>";

?>

执行一下这个代码,看看结果:

/afa//fa/fa/f/afa/php test.php

去访问:http://你的机器IP:16686/search 看看页面上面有没有相关埋点数据即可。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值