Zipkin
Zipkin 是一种分布式跟踪系统。它有助于收集解决微服务架构中的延迟问题所需的时序数据。它管理这些数据的收集和查找。
Zipkin的设计基于Google Dapper论文。
应用程序用于向Zipkin报告时序数据。
Zipkin UI还提供了一个依赖关系图,显示了每个应用程序通过的跟踪请求数。如果要解决延迟问题或错误,可以根据应用程序,跟踪长度,注释或时间戳对所有跟踪进行筛选或排序。选择跟踪后,您可以看到每个跨度所需的总跟踪时间百分比,从而可以识别问题应用程序。
快速开始
在本节中,我们将逐步构建并启动Zipkin实例,以便在本地检查Zipkin。
有三个选项:使用Java,Docker或从源代码运行。
如果您熟悉Docker,这是首选的方法。如果您不熟悉Docker,请尝试通过Java或源代码运行。
无论您如何启动Zipkin,请浏览 http://your_host:9411 以查找跟踪!
Docker
Docker Zipkin项目能够构建docker镜像,提供脚本和docker-compose.yml,用于启动预构建的图像。
- 拉取镜像
docker pull openzipkin/zipkin
最快的开始是直接运行最新的图像:
docker run -d -p 9411:9411 openzipkin/zipkin
java
jdk8+ 以上安装,直接运行:
curl -sSL https://zipkin.io/quickstart.sh | bash -s
java -jar zipkin.jar
使用源码编译运行
# get the latest source
git clone https://github.com/openzipkin/zipkin
cd zipkin
# Build the server and also make its dependencies
./mvnw -DskipTests --also-make -pl zipkin-server clean install
# Run the server
java -jar ./zipkin-server/target/zipkin-server-*exec.jar
Architecture
概览
跟踪器存在于您的应用程序中,并记录有关发生的操作的时间和元数据。他们经常使用库,因此它们的使用对用户是透明的。
例如,检测的Web服务器记录何时收到请求以及何时发送响应。收集的跟踪数据称为Span。
编写仪器是为了安全生产并且开销很小。出于这个原因,它们只在带内传播ID,告诉接收器正在进行跟踪。 Zipkin带外报告已完成的跨度,类似于应用程序异步报告度量标准的方式。
例如,在跟踪操作并且需要发出传出的http请求时,会添加一些标头来传播ID。标头不用于发送操作名称等详细信息。
将数据发送到Zipkin的检测应用程序中的组件称为Reporter。记者通过几种传输之一将跟踪数据发送到Zipkin收集器,这些收集器将跟踪数据保存到存储中。稍后,API会查询存储以向UI提供数据。
这是描述此流程的图表:
要查看您的平台是否已存在检测库,请参阅现有仪器列表。
Example Flow
如概述中所述,标识符是带内发送的,详细信息是带外发送给Zipkin的。
在这两种情况下,跟踪检测都负责创建有效的跟踪并正确呈现它们。
例如,跟踪器确保它在带内(下游)和带外(与Zipkin异步)发送的数据之间的奇偶校验。
这是一个示例序列的http跟踪,其中用户代码调用资源/ foo。
这导致单个跨度,在用户代码收到http响应后异步发送到Zipkin。
┌─────────────┐ ┌───────────────────────┐ ┌─────────────┐ ┌──────────────────┐
│ User Code │ │ Trace Instrumentation │ │ Http Client │ │ Zipkin Collector │
└─────────────┘ └───────────────────────┘ └─────────────┘ └──────────────────┘
│ │ │ │
┌─────────┐
│ ──┤GET /foo ├─▶ │ ────┐ │ │
└─────────┘ │ record tags
│ │ ◀───┘ │ │
────┐
│ │ │ add trace headers │ │
◀───┘
│ │ ────┐ │ │
│ record timestamp
│ │ ◀───┘ │ │
┌─────────────────┐
│ │ ──┤GET /foo ├─▶ │ │
│X-B3-TraceId: aa │ ────┐
│ │ │X-B3-SpanId: 6b │ │ │ │
└─────────────────┘ │ invoke
│ │ │ │ request │
│
│ │ │ │ │
┌────────┐ ◀───┘
│ │ ◀─────┤200 OK ├─────── │ │
────┐ └────────┘
│ │ │ record duration │ │
┌────────┐ ◀───┘
│ ◀──┤200 OK ├── │ │ │
└────────┘ ┌────────────────────────────────┐
│ │ ──┤ asynchronously report span ├────▶ │
│ │
│{ │
│ "traceId": "aa", │
│ "id": "6b", │
│ "name": "get", │
│ "timestamp": 1483945573944000,│
│ "duration": 386000, │
│ "annotations": [ │
│--snip-- │
└────────────────────────────────┘
运输
必须将从仪表化库中发送的跨度从被跟踪的服务传输到Zipkin收集器。有三种主要传输方式:HTTP,Kafka和Scribe。
组件
Zipkin有4个组件:
-
集电极
-
存储
-
搜索
-
网页用户界面
Zipkin收藏家
一旦跟踪数据到达Zipkin收集器守护程序,它就会被Zipkin收集器验证,存储和索引以供查找。
存储 Zipkin最初是为了在Cassandra上存储数据而构建的,因为Cassandra是可扩展的,具有灵活的模式,并且在Twitter中大量使用。但是,我们使这个组件可插拔。除了Cassandra,我们原生支持ElasticSearch和MySQL。其他后端可能会作为第三方扩展提供。
Zipkin查询服务 一旦数据被存储和索引,我们需要一种方法来提取它。查询守护程序提供了一个简单的JSON API,用于查找和检索跟踪。此API的主要使用者是Web UI。
Web UI 我们创建了一个GUI,它为查看跟踪提供了一个很好的界面。 Web UI提供了一种基于服务,时间和注释查看跟踪的方法。注意:UI中没有内置身份验证!
Data Model
请注意,此页面已过期。请查看Zipkin Api文档,该文档详细说明了模型中的字段,直到此页面更新为止。
为了说明Zipkin显示的跟踪数据,让我们将它与Zipkin数据模型中的等效信息联系起来。
通过比较这些,我们看到了
-
入站和出站请求的跨度不同
-
包含cs的跨度可以记录它们的去向
当目标协议不是Zipkin检测时,例如MySQL,这会有所帮助。 首先,我们看到Zipkin跟踪查看器中显示的一条跟踪:
对应的视图 json 如下:
[
{
"traceId": "bd7a977555f6b982",
"name": "get",
"id": "bd7a977555f6b982",
"timestamp": 1458702548467000,
"duration": 386000,
"annotations": [
{
"endpoint": {
"serviceName": "zipkin-query",
"ipv4": "192.168.1.2",
"port": 9411
},
"timestamp": 1458702548467000,
"value": "sr"
},
{
"endpoint": {
"serviceName": "zipkin-query",
"ipv4": "192.168.1.2",
"port": 9411
},
"timestamp": 1458702548853000,
"value": "ss"
}
],
"binaryAnnotations": []
},
{
"traceId": "bd7a977555f6b982",
"name": "get-traces",
"id": "ebf33e1a81dc6f71",
"parentId": "bd7a977555f6b982",
"timestamp": 1458702548478000,
"duration": 354374,
"annotations": [],
"binaryAnnotations": [
{
"key": "lc",
"value": "JDBCSpanStore",
"endpoint": {
"serviceName": "zipkin-query",
"ipv4": "192.168.1.2",
"port": 9411
}
},
{
"key": "request",
"value": "QueryRequest{serviceName=zipkin-query, spanName=null, annotations=[], binaryAnnotations={}, minDuration=null, maxDuration=null, endTs=1458702548478, lookback=86400000, limit=1}",
"endpoint": {
"serviceName": "zipkin-query",
"ipv4": "192.168.1.2",
"port": 9411
}
}
]
},
{
"traceId": "bd7a977555f6b982",
"name": "query",
"id": "be2d01e33cc78d97",
"parentId": "ebf33e1a81dc6f71",
"timestamp": 1458702548786000,
"duration": 13000,
"annotations": [
{
"endpoint": {
"serviceName": "zipkin-query",
"ipv4": "192.168.1.2",
"port": 9411
},
"timestamp": 1458702548786000,
"value": "cs"
},
{
"endpoint": {
"serviceName": "zipkin-query",
"ipv4": "192.168.1.2",
"port": 9411
},
"timestamp": 1458702548799000,
"value": "cr"
}
],
"binaryAnnotations": [
{
"key": "jdbc.query",
"value": "select distinct `zipkin_spans`.`trace_id` from `zipkin_spans` join `zipkin_annotations` on (`zipkin_spans`.`trace_id` = `zipkin_annotations`.`trace_id` and `zipkin_spans`.`id` = `zipkin_annotations`.`span_id`) where (`zipkin_annotations`.`endpoint_service_name` = ? and `zipkin_spans`.`start_ts` between ? and ?) order by `zipkin_spans`.`start_ts` desc limit ?",
"endpoint": {
"serviceName": "zipkin-query",
"ipv4": "192.168.1.2",
"port": 9411
}
},
{
"key": "sa",
"value": true,
"endpoint": {
"serviceName": "spanstore-jdbc",
"ipv4": "127.0.0.1",
"port": 3306
}
}
]
},
{
"traceId": "bd7a977555f6b982",
"name": "query",
"id": "13038c5fee5a2f2e",
"parentId": "ebf33e1a81dc6f71",
"timestamp": 1458702548817000,
"duration": 1000,
"annotations": [
{
"endpoint": {
"serviceName": "zipkin-query",
"ipv4": "192.168.1.2",
"port": 9411
},
"timestamp": 1458702548817000,
"value": "cs"
},
{
"endpoint": {
"serviceName": "zipkin-query",
"ipv4": "192.168.1.2",
"port": 9411
},
"timestamp": 1458702548818000,
"value": "cr"
}
],
"binaryAnnotations": [
{
"key": "jdbc.query",
"value": "select `zipkin_spans`.`trace_id`, `zipkin_spans`.`id`, `zipkin_spans`.`name`, `zipkin_spans`.`parent_id`, `zipkin_spans`.`debug`, `zipkin_spans`.`start_ts`, `zipkin_spans`.`duration` from `zipkin_spans` where `zipkin_spans`.`trace_id` in (?)",
"endpoint": {
"serviceName": "zipkin-query",
"ipv4": "192.168.1.2",
"port": 9411
}
},
{
"key": "sa",
"value": true,
"endpoint": {
"serviceName": "spanstore-jdbc",
"ipv4": "127.0.0.1",
"port": 3306
}
}
]
},
{
"traceId": "bd7a977555f6b982",
"name": "query",
"id": "37ee55f3d3a94336",
"parentId": "ebf33e1a81dc6f71",
"timestamp": 1458702548827000,
"duration": 2000,
"annotations": [
{
"endpoint": {
"serviceName": "zipkin-query",
"ipv4": "192.168.1.2",
"port": 9411
},
"timestamp": 1458702548827000,
"value": "cs"
},
{
"endpoint": {
"serviceName": "zipkin-query",
"ipv4": "192.168.1.2",
"port": 9411
},
"timestamp": 1458702548829000,
"value": "cr"
}
],
"binaryAnnotations": [
{
"key": "jdbc.query",
"value": "select `zipkin_annotations`.`trace_id`, `zipkin_annotations`.`span_id`, `zipkin_annotations`.`a_key`, `zipkin_annotations`.`a_value`, `zipkin_annotations`.`a_type`, `zipkin_annotations`.`a_timestamp`, `zipkin_annotations`.`endpoint_ipv4`, `zipkin_annotations`.`endpoint_port`, `zipkin_annotations`.`endpoint_service_name` from `zipkin_annotations` where `zipkin_annotations`.`trace_id` in (?) order by `zipkin_annotations`.`a_timestamp` asc, `zipkin_annotations`.`a_key` asc",
"endpoint": {
"serviceName": "zipkin-query",
"ipv4": "192.168.1.2",
"port": 9411
}
},
{
"key": "sa",
"value": true,
"endpoint": {
"serviceName": "spanstore-jdbc",
"ipv4": "127.0.0.1",
"port": 3306
}
}
]
}
]
检测库
这是一个高级主题。在进一步阅读之前,您可能需要检查平台的检测库是否已存在。
如果没有,如果你想创建一个仪器库,首先要做的事情;跳过Zipkin Gitter聊天频道,告诉我们。我们非常乐意为您提供帮助。