【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
使用zipkin做二次开发,第一步是要对zipkin整体有一个了解,能够简单的搭建DEMO跑一跑,前面两篇文章,就是做这个用的,接下来最重要的一点,就是了解他存储在elasticsearch的数据结构。
span结构
zipkin存储span的话,存在elasticsearch里面,每一天的数据自动创建一个index, 格式如下
zipkin:span-2018-08-06
zipkin:span-2018-08-07 # 2018-08-07这一天的span都存储在这个index下面
1
2
一个span的数据结构如下
{
"_index": "zipkin:span-2018-08-07",
"_type": "span",
"_id": "AWUSkiT_lG0UQ3Osck2S",
"_version": 1,
"_score": 1,
"_source": {
"traceId": "6c3c748ff257f23b",
"duration": 2928879,
"localEndpoint": {
"ipv4": "10.208.204.119",
"port": 7900,
"serviceName": "sleuthconsumer"
},
"timestamp_millis": 1533614872966,
"kind": "SERVER",
"name": "http:/consumer",
"id": "6c3c748ff257f23b",
"timestamp": 1533614872966000,
"parentId": "6c3c748ff257f23b",
"tags": {
"mvc.controller.class": "HomeController",
"mvc.controller.method": "service1",
"lc": "hystrix",
"spring.instance_id": "DESKTOP-CBSVPL2:sleuthConsumer:7900",
"thread": "hystrix-sleuthConsumer2-1"
}
}
}
这个是从elasticsearch里面拷贝出来的数据结构,其实主要看下面这一块就好了
{
"traceId": "6c3c748ff257f23b",
"duration": 2928879,
"localEndpoint": {
"ipv4": "10.208.204.119",
"port": 7900,
"serviceName": "sleuthconsumer"
},
"timestamp_millis": 1533614872966,
"kind": "SERVER",
"name": "http:/consumer",
"id": "6c3c748ff257f23b",
"timestamp": 1533614872966000,
"parentId": "6c3c748ff257f23b",
"tags": {
"mvc.controller.class": "HomeController",
"mvc.controller.method": "service1",
"lc": "hystrix",
"spring.instance_id": "DESKTOP-CBSVPL2:sleuthConsumer:7900",
"thread": "hystrix-sleuthConsumer2-1"
}
}
traceId : 同一次http请求的traceId都是一样的,他表示了一个调用链的产生,同一个调用链里面的span的traceId都是一样的
duration : 耗时,一个span的产生表示一次调用请求。duration 就是这次请求从接收到所耗费的时间 ,单位: 微秒
localEndpoint : 本地服务器的网络信息
ipv4 : 本地服务器IP
port : 本地服务端口
serviceName: 本地服务名
timestamp_millis : 本次请求的开始时间,单位: 毫秒
kind : span的类型,有server和client的区分。
name : 调用的本服务的接口地址
id : spanID
parentId : 父节点ID,用来关联调用关系
tags : 针对这个span所打的标签,里面的内容具有不确定性。
dependency结构
zipkin存储调用链的话,存在elasticsearch里面,每一天的调用链分别用一个index存储, 格式如下
zipkin:span-2018-08-06
zipkin:span-2018-08-07 # 2018-08-07这一天的调用链都存储在这个index下面
1
2
{
"_index": "zipkin:dependency-2018-08-07",
"_type": "dependency",
"_id": "sleuthconsumer|sleuthconsumer2",
"_version": 3,
"_score": 1,
"_source": {
"id": "sleuthconsumer|sleuthconsumer2",
"parent": "sleuthconsumer",
"child": "sleuthconsumer2",
"callCount": 56,
"errorCount": 4
}
}
id : 由parent和child构成
parent : 调用开始的服务名
child : 被调用的服务名
callCount : 调用次数
errorCount : 调用的错误次数
以上说的是存储在数据库最原始的数据结构,下面来讲一下,zipkin在程序里面已经组装好了的数据结构。
完整trace数据结构
调用链如下:
sleuthconsumer : http:/consumer
在consumer 方法中,
调用sleuthprovider: http:/provider
调用sleuthconsumer2: http:/consumer2
sleuthprovider: http:/provider
方法的调用层次如上,界面的生成的数据结构如下 , 前端返回的json数据,总共生成了四个span标签,表示四个http请求。
[
{
"traceId": "aac7faa56867fbc3", # traceId , 表示同一次请求
"id": "aac7faa56867fbc3", # 请求的第一个span,ID 和traceId相同
"name": "http:/consumer", # 访问的接口
"timestamp": 1533293762448000, # 请求开始时间 ,单位微秒
"duration": 30060, # 整个请求的耗时,根节点的耗时,其实就是整个调用链完成的耗时时间
"annotations": [
{
"timestamp": 1533293762448000, # 服务接收到请求的时间,也就是请求开始时间
"value": "sr", # service receiverd
"endpoint": { # 服务本地的网络信息,应用名,IP,端口
"serviceName": "sleuthconsumer",
"ipv4": "10.208.204.119",
"port": 7900
}
},
{
"timestamp": 1533293762478060, #整个调用链的结束时间
"value": "ss", # service send 虽然这个地方显示的是service send , 但是实际上是整个调用链的结束
"endpoint": { # 服务本地的网络信息,应用名,IP,端口
"serviceName": "sleuthconsumer",
"ipv4": "10.208.204.119",
"port": 7900
}
}
],
"binaryAnnotations": [ # 服务的一系列标签信息
{
"key": "mvc.controller.class",
"value": "HomeController",
"endpoint": {
"serviceName": "sleuthconsumer",
"ipv4": "10.208.204.119",
"port": 7900
}
}
# 省略剩余的标签
]
},
{
"traceId": "aac7faa56867fbc3", # 调用链全局公用一个traceID
"id": "4aab338d1c5bcc52", # spanID
"name": "http:/provider", # 请求的URI
"parentId": "aac7faa56867fbc3", # 他的上级请求ID,sleuthconsumer 的ID,表示请求是从sleuthconsumer 发过来的
"timestamp": 1533293762450000, # 请求的开始时间,从 sleuthconsumer 发出请求开始算起
"duration": 4000, # sleuthprovider 服务provider接口的耗时
"annotations": [
{
"timestamp": 1533293762450000, # sleuthconsumer 发出调用http:/provider的时间
"value": "cs", # client send
"endpoint": { # 服务本地的网络信息,应用名,IP,端口
"serviceName": "sleuthconsumer",
"ipv4": "10.208.204.119",
"port": 7900
}
},
{
"timestamp": 1533293762452000, # sleuthprovider 接收到请求的时间
"value": "sr", # service receive
"endpoint": { # 服务本地的网络信息,应用名,IP,端口
"serviceName": "sleuthprovider",
"ipv4": "10.208.204.119",
"port": 7902
}
},
{
"timestamp": 1533293762453000, # sleuthprovider 请求完成,发出返回值的时间
"value": "ss", # service send
"endpoint": {
"serviceName": "sleuthprovider",
"ipv4": "10.208.204.119",
"port": 7902
}
},
{
"timestamp": 1533293762454000, # sleuthconsumer接收到 sleuthprovider 的返回值的时间, 至此,这个调用完成,总共耗时4毫秒
"value": "cr", # client receive
"endpoint": {
"serviceName": "sleuthconsumer",
"ipv4": "10.208.204.119",
"port": 7900
}
}
],
"binaryAnnotations": [ # 标签信息,列出了跟本次请求相关的标签
{
"key": "http.host",
"value": "localhost",
"endpoint": {
"serviceName": "sleuthconsumer",
"ipv4": "10.208.204.119",
"port": 7900
}
}
# 省略剩余的标签
]
},
{
"traceId": "aac7faa56867fbc3", # 调用链全局公用一个traceID
"id": "66193640803fca1b", # sleuthconsumer 请求 sleuthconsumer2 这次请求的spanId
"name": "http:/consumer2", # 接口URI
"parentId": "aac7faa56867fbc3", # 表示从哪个请求发过来的,aac7faa56867fbc3 是sleuthconsumer的ID
"timestamp": 1533293762455000, # 请求的开始时间,从sleuthconsumer发出请求的时候开始算起 ,单位: 微秒
"duration": 22000, # 本次请求从开始到完成的耗费时间 ,单位微秒
"annotations": [
{
"timestamp": 1533293762455000, # sleuthconsumer发出请求的时间
"value": "cs", # client send
"endpoint": { #sleuthconsumer的应用信息
"serviceName": "sleuthconsumer",
"ipv4": "10.208.204.119",
"port": 7900
}
},
{
"timestamp": 1533293762457000, # sleuthconsumer2接收到请求的时间
"value": "sr", # service receive
"endpoint": { #sleuthconsumer2的本地应用信息
"serviceName": "sleuthconsumer2",
"ipv4": "10.208.204.119",
"port": 7901
}
},
{
"timestamp": 1533293762477000, #sleuthconsumer2请求处理完成,发出响应结果的时间
"value": "ss", # service send
"endpoint": {
"serviceName": "sleuthconsumer2",
"ipv4": "10.208.204.119",
"port": 7901
}
},
{
"timestamp": 1533293762477000, # sleuthconsumer 收到返回值的时间,此时表示一个请求的完成
"value": "cr",
"endpoint": {
"serviceName": "sleuthconsumer",
"ipv4": "10.208.204.119",
"port": 7900
}
}
],
"binaryAnnotations": [ # 标签信息,列出了跟本次请求相关的标签
{
"key": "http.host",
"value": "localhost",
"endpoint": {
"serviceName": "sleuthconsumer",
"ipv4": "10.208.204.119",
"port": 7900
}
}
# 省略剩余的标签
]
},
{
"traceId": "aac7faa56867fbc3", # 调用链全局公用一个traceID
"id": "dd53905167c2ec13", # sleuthconsumer2 调用 sleuthprovider 产生的spanId
"name": "http:/provider", # 本次请求的接口URI
"parentId": "66193640803fca1b", # 他的上级节点ID,也就是哪个span调用的它, 此处表示sleuthconsumer2 的span
"timestamp": 1533293762458000, # sleuthconsumer2 发出http:/provider请求的开始时间
"duration": 17000, # 请求开始到结束的耗时时间
"annotations": [
{
"timestamp": 1533293762458000, # sleuthconsumer2 发出http:/provider请求的开始时间
"value": "cs", # client send
"endpoint": { # sleuthconsumer2的应用信息
"serviceName": "sleuthconsumer2",
"ipv4": "10.208.204.119",
"port": 7901
}
},
{
"timestamp": 1533293762471000, # sleuthprovider收到请求的时间
"value": "sr", # service receive
"endpoint": { # sleuthprovider本地的应用信息
"serviceName": "sleuthprovider",
"ipv4": "10.208.204.119",
"port": 7902
}
},
{
"timestamp": 1533293762475000, # sleuthprovider请求处理完成,返回响应结果的时间
"value": "ss", # service send
"endpoint": {
"serviceName": "sleuthprovider",
"ipv4": "10.208.204.119",
"port": 7902
}
},
{
"timestamp": 1533293762475000, # sleuthconsumer2 收到请求的相应结果的时间 ,请求至此结束
"value": "cr", # client receive
"endpoint": {
"serviceName": "sleuthconsumer2",
"ipv4": "10.208.204.119",
"port": 7901
}
}
],
"binaryAnnotations": [
{
"key": "http.host",
"value": "localhost",
"endpoint": {
"serviceName": "sleuthconsumer2",
"ipv4": "10.208.204.119",
"port": 7901
}
}
#省略剩余的标签
]
}
]
以上所有和时间相关的,单位都是微秒
一个请求的完成,有四个比较重要的概念:
cs - Client Send : 客户端已经提出了请求。这就设置了跨度的开始。
sr - Server Receive: 服务器已收到请求并将开始处理它。这与CS之间的差异将是网络延迟和时钟抖动的组合。
ss - Server Send: 服务器已完成处理,并将请求发送回客户端。这与SR之间的差异将是服务器处理请求所花费的时间
cr - Client Receive : 客户端已经收到来自服务器的响应。这就设置了跨度的终点。当记录注释时,RPC被认为是完整的。
https://www.scienjus.com/zipkin-statistics-based-on-elasticsearch/
https://github.com/openzipkin/zipkin/tree/master/zipkin-storage
来源:oschina
链接:https://my.oschina.net/xiaominmin/blog/3143614