使用es 来存放 jaeger

OpenTracing 基础知识准备

The OpenTracing 数据模型

首先需要阐明的是 Span 和 trace 的概念。 用图论的观点来看的话,traces 可以被认为是 spans 的 DAG。也就是说,对N个 spans 形成的 DAG 是一个 Traces。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
单个 Trace 中 Span 之间的因果关系


[Span A] ←←←(the root span)
|
+------+------+
| |
[Span B] [Span C] ←←←(Span C is a `ChildOf` Span A)
| |
[Span D] +---+-------+
| |
[Span E] [Span F] >>> [Span G] >>> [Span H]



(Span G `FollowsFrom` Span F)

---------------------------------------------------------------------------

单个 Trace 中 Spans 之间的时间关系

––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–> time

[Span A···················································]
[Span B··············································]
[Span D··········································]
[Span C········································]
[Span E·······] [Span F··] [Span G··] [Span H··]
每个 Span 包含一些状态:
  • Operation 的 名字(An operation name)

  • 开始 ts (A start timestamp)

  • 结束 ts (A finish timestamp)

  • 0个或多个以 keys:values 为形式组成的 Span Tags。 key 必须是 string, values 则可以是 strings, bool,numeric types

  • 0个或多个 Span logs

一个 SpanContext
  • 通过 SpanContext 可以指向 0个 或者多个 因果相关的 Span。

  • 每个 SpanContext 包含以下状态:

  • 任何 OpenTraceing 实现相关的状态(比如 trace 和 span id)都需要被一个跨进程的 Span 所联系。

​- Baggage Items: 跨进程的 key value 对。

DAG

RDD的依赖关系分为两种:窄依赖(Narrow Dependencies)与宽依赖(Wide Dependencies,源码中称为Shuffle Dependencies)

- 窄依赖

    每个父RDD的一个Partition最多被子RDD的一个Partition所使用(1:1 或 n:1)。例如map、filter、union等操作都会产生窄依赖

    子RDD分区通常对应常数个父RDD分区(O(1),与数据规模无关)。

- 宽依赖

    一个父RDD的Partition会被多个子RDD的Partition所使用,例如groupByKey、reduceByKey、sortByKey等操作都会产生宽依赖;(1:m 或 n:m)

    子RDD分区通常对应所有的父RDD分区(O(n),与数据规模有关)

在Spark里每一个操作生成一个RDD,RDD之间连一条边,最后这些RDD和他们之间的边组成一个有向无环图,这个就是DAG。

Spark会根据宽依赖窄依赖来划分具体的Stage,而依赖有2个作用:

- 用来解决数据容错的高效性

- 其二用来划分stage。

OpenTracing API

在 OpenTracing 有着三个关键的并且相互关联的类型: Tracer, Span, SpanContext。下面,我们来介绍下每种类型的基本行为。 简单地说,每种行为都会在具体的语言中变为一个“方法”,

Tracer

Tracer接口用来创建Span,以及处理如何处理Inject(serialize) 和 Extract (deserialize),用于跨进程边界传递。

- 创建一个新的span

- 将SpanContext上下文Inject(注入)到carrier

- 将SpanContext上下文从carrier中Extract(提取)

    注意,对于Inject(注入)和Extract(提取),format是必须的。

    Inject(注入)和Extract(提取)依赖于可扩展的format参数。format参数规定了另一个参数"carrier"的类型,同时约束了"carrier"中SpanContext是如何编码的。

Span

#####设置(set) baggage item

Baggage item是对应于某个 Span 及其 SpanContext ,以及所有直接或间接引用自本地(local) Span 的 Span 的键值对。也就是说,baggage items是与其trace一起传播的。

Baggage item为全栈式的OpenTracing集成提供了强大的功能(比如在移动App上使用时,它可以一路追踪数据直至储存系统的深度),不过使用这些功能时要当心。

每个键值都会被拷贝到每一个本地(local)及远程的子Span,这可能导致巨大的网络和CPU开销。

SpanContext

相对于OpenTracing中其他的功能,SpanContext更多的是一个“概念”。也就是说,OpenTracing实现中,需要重点考虑,并提供一套自己的API。

OpenTracing的使用者仅仅需要,在创建span、向传输协议Inject(注入)和从传输协议中Extract(提取)时,使用SpanContext和references,

OpenTracing要求,SpanContext是不可变的,目的是防止由于Span的结束和相互关系,造成的复杂生命周期问题。

#不使用Cassandra来存放 jaeger 主要是因为我们已经部署了ELK 所以尝试使用elasticsearch来存放

#####Jaeger 组件

Agent

Agent是一个网络守护进程,监听通过UDP发送过来的Span,它会将其批量发送给collector。按照设计,Agent要被部署到所有主机上,作为基础设施。Agent将collector和客户端之间的路由与发现机制抽象了出来。

Collector

Collector从Jaeger Agent接收Trace,并通过一个处理管道对其进行处理。目前的管道会校验Trace、建立索引、执行转换并最终进行存储。存储是一个可插入的组件,现在支持Cassandra和elasticsearch。

Query

Query服务会从存储中检索Trace并通过UI界面进行展现,该UI界面通过React技术实现,其页面UI如下图所示,展现了一条Trace的详细信息。

存储

jaeger采集到的数据必须存储到某个存储引擎,目前支持Cassandra和elasticsearch

#####部署步骤

会通过docker-compose 统一部署 所以先列出完整yaml文件 再一一说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
version: '2.1'
services:

elasticsearch:
image: elasticsearch:5.6.4
environment:
- "ES_JAVA_OPTS=-Xms1024m -Xmx1024m"

collector:
image: jaegertracing/jaeger-collector
environment:
- SPAN_STORAGE_TYPE=elasticsearch
- ES_SERVER_URLS=http://elasticsearch:9200
- ES_USERNAME=elastic
- LOG_LEVEL=debug
depends_on:
- elasticsearch

agent:
image: jaegertracing/jaeger-agent
environment:
- COLLECTOR_HOST_PORT=collector:14267
- LOG_LEVEL=debug
ports:
- "5775:5775/udp"
- "5778:5778"
- "6831:6831/udp"
- "6832:6832/udp"
depends_on:
- collector
query:
image: jaegertracing/jaeger-query
environment:
- SPAN_STORAGE_TYPE=elasticsearch
- ES_SERVER_URLS=http://elasticsearch:9200
- ES_USERNAME=elastic
- LOG_LEVEL=debug
ports:
- 16686:16686
depends_on:
- elasticsearch

hotrod:
image: jaegertracing/example-hotrod:1.6
command: all --jaeger-agent.host-port=agent:6831
ports:
- 8080:8080
depends_on:
- agent

Docker 安装ES
Docker 安装collector
如ES部署再同一个机器上 可以使用--link关联

多服务器则可以用过 ES_SERVER_URLS = http://你的es ip:9200 来关联
Docker 安装query
如同conllector

部署完成query之后,根据你暴露的端口号(-p 16686:16686/tcp),浏览器输入以下地址(将localhost换成你部署query的地址):

注意,ES_USERNAME、ES_PASSWORD这两个环境变量,当你的elasticsearch未设置账号密码时,你可以不填,也可以填上默认值,elasticsearch的默认ES_USERNAME=elastic,ES_PASSWORD=changeme
Docker 安装agent
根据uber jaeger官网的架构,agent一般是和jaeger-client部署在一起,agent作为一个基础架构,每一台应用(接入jaeger-client的应用)所在的机器都需要部署一个agent;

根据数据采集原理,jaeger-client采集到数据之后,是通过UDP端口发送到agent的,jaeger-client和agent部署在一起的好处是UDP传输数据都在应用所在的机器,可避免UDP的跨网络传输,多一层安全保障。

当然,架构可能是多变的,你的agent可能不和jaeger-client所在的应用在一台机器,这个时候,jaeger-client就必须显示的指定其连接的agent的IP及port,具体做法后文jaeger-client对应模块会讲到。

前文提到,jaeger-client采集到数据之后,是通过UDP端口发送到agent的,agent接收到数据之后,使用Uber的Tchannel协议,将数据发送到collector,所以,agent是必须和collector相连的;

--collector.host-port=collector ip1:14267,collector ip2:14267,collector ip3:14267,用逗号分开,连接三个collector,这样的话,这三个collector只要一个存活,agent就可以吧数据传输完成,以避免单点故障
hotrod
用以测试