zipkin Span 分析

zipkin 的Span有两个版本V1及V2,但是最终再代码的运转亦或是ES中存储的所体现的其实都是V2的Span,下面我们来分析分析这两个Span有什么异同。

V1的Span 应该是我们所熟悉的,它就是来源与谷歌的那篇论文,拥有CR,CS,SR,SS等Annotation,同时还拥有BinaryAnnotation。我们来看看其主要成员。

 public final long traceIdHigh;

  public final long traceId;
  
  public final String name;
 
  @Nullable
  public final Long parentId;
 
  @Nullable
  public final Long timestamp;
  
  @Nullable
  public final Long duration;
 
  public final List<Annotation> annotations;
  
  public final List<BinaryAnnotation> binaryAnnotations;

  @Nullable
  public final Boolean debug;

来看一个存储的Span

两个SPAN
Trace e8d779e43243cd5b
[
  {
    "traceId": "e8d779e43243cd5b",
    "id": "e8d779e43243cd5b",
    "name": "ttt",
    "timestamp": 1553414640395000,
    "duration": 96581,
    "binaryAnnotations": [
      {
        "key": "chane",
        "value": "1234",
        "endpoint": {
          "serviceName": "shopservicename",
          "ipv4": "192.168.88.103"
        }
      },
      {
        "key": "lc",
        "value": "tttttt",
        "endpoint": {
          "serviceName": "shopservicename",
          "ipv4": "192.168.88.103"
        }
      }
    ]
  },
  {
    "traceId": "e8d779e43243cd5b",
    "id": "ac75f268aab05339",
    "name": "queryflowprcpln",
    "parentId": "e8d779e43243cd5b",
    "timestamp": 1553414640399000,
    "duration": 94000,
    "annotations": [
      {
        "timestamp": 1553414640399000,
        "value": "cs",
        "endpoint": {
          "serviceName": "shopservicename",
          "ipv4": "192.168.88.103"
        }
      },
      {
        "timestamp": 1553414640493000,
        "value": "cr",
        "endpoint": {
          "serviceName": "shopservicename",
          "ipv4": "192.168.88.103"
        }
      }
    ]
  }
]
 

我们再来看看V2 的Span

  // Custom impl to reduce GC churn and Kryo which cannot handle AutoValue subclass
  // See https://github.com/openzipkin/zipkin/issues/1879
  final String traceId, parentId, id;
  final Kind kind;
  final String name;
  final long timestamp, duration; // zero means null, saving 2 object references
  final Endpoint localEndpoint, remoteEndpoint;
  final List<Annotation> annotations;
  final Map<String, String> tags;
  final int flags; // bit field for timestamp and duration, saving 2 object references

实际存储

{
    "took": 3,
    "timed_out": false,
    "_shards": {
        "total": 20,
        "successful": 20,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 2,
        "max_score": 0,
        "hits": [
            {
                "_index": "zipkin:span-2019-03-24",
                "_type": "span",
                "_id": "xHu6rmkB4ZW4b3UBVS-t",
                "_score": 0,
                "_source": {
                    "traceId": "e8d779e43243cd5b",
                    "duration": 94000,
                    "localEndpoint": {
                        "serviceName": "shopservicename",
                        "ipv4": "192.168.88.103"
                    },
                    "timestamp_millis": 1553414640399,
                    "kind": "CLIENT",
                    "name": "queryflowprcpln",
                    "id": "ac75f268aab05339",
                    "parentId": "e8d779e43243cd5b",
                    "timestamp": 1553414640399000
                }
            },
            {
                "_index": "zipkin:span-2019-03-24",
                "_type": "span",
                "_id": "xXu6rmkB4ZW4b3UBVS-t",
                "_score": 0,
                "_source": {
                    "traceId": "e8d779e43243cd5b",
                    "duration": 96581,
                    "localEndpoint": {
                        "serviceName": "shopservicename",
                        "ipv4": "192.168.88.103"
                    },
                    "timestamp_millis": 1553414640395,
                    "name": "ttt",
                    "id": "e8d779e43243cd5b",
                    "timestamp": 1553414640395000,
                    "tags": {
                        "chane": "1234",
                        "lc": "tttttt"
                    }
                }
            }
        ]
    }
}

两者有比较大的不一样。当zipkin Server 接收到V1 时会有一个转换器将其转换成V2。那这两者是怎么转换的呢。

CR 及 CS 的Annoation 会转换成Kind 为Client。其次CR 及CS 下的EndPoint 会被转换为localEndpoint。

至于我们经常用来存储key-value 的BinaryAnnoation 也会被转换成tags中的一条Entry<String,String>。

zipkin 采用的ES来进行存储,我们来看看其在ES中的索引是怎么定义的。

{
    "zipkin:span-2019-03-24": {
        "aliases": {},
        "mappings": {
            "span": {
                "_source": {
                    "excludes": [
                        "_q"
                    ]
                },
                "dynamic_templates": [
                    {
                        "strings": {
                            "match": "*",
                            "match_mapping_type": "string",
                            "mapping": {
                                "ignore_above": 256,
                                "norms": false,
                                "type": "keyword"
                            }
                        }
                    }
                ],
                "properties": {
                    "_q": {
                        "type": "keyword"
                    },
                    "annotations": {
                        "type": "object",
                        "enabled": false
                    },
                    "duration": {
                        "type": "long"
                    },
                    "id": {
                        "type": "keyword",
                        "ignore_above": 256
                    },
                    "kind": {
                        "type": "keyword",
                        "ignore_above": 256
                    },
                    "localEndpoint": {
                        "dynamic": "false",
                        "properties": {
                            "serviceName": {
                                "type": "keyword"
                            }
                        }
                    },
                    "name": {
                        "type": "keyword"
                    },
                    "parentId": {
                        "type": "keyword",
                        "ignore_above": 256
                    },
                    "remoteEndpoint": {
                        "dynamic": "false",
                        "properties": {
                            "serviceName": {
                                "type": "keyword"
                            }
                        }
                    },
                    "tags": {
                        "type": "object",
                        "enabled": false
                    },
                    "timestamp": {
                        "type": "long"
                    },
                    "timestamp_millis": {
                        "type": "date",
                        "format": "epoch_millis"
                    },
                    "traceId": {
                        "type": "keyword"
                    }
                }
            },
            "_default_": {
                "dynamic_templates": [
                    {
                        "strings": {
                            "match": "*",
                            "match_mapping_type": "string",
                            "mapping": {
                                "ignore_above": 256,
                                "norms": false,
                                "type": "keyword"
                            }
                        }
                    }
                ]
            }
        },
        "settings": {
            "index": {
                "number_of_shards": "5",
                "provided_name": "zipkin:span-2019-03-24",
                "mapper": {
                    "dynamic": "false"
                },
                "creation_date": "1553400823203",
                "requests": {
                    "cache": {
                        "enable": "true"
                    }
                },
                "analysis": {
                    "filter": {
                        "traceId_filter": {
                            "type": "pattern_capture",
                            "preserve_original": "true",
                            "patterns": [
                                "([0-9a-f]{1,16})$"
                            ]
                        }
                    },
                    "analyzer": {
                        "traceId_analyzer": {
                            "filter": "traceId_filter",
                            "type": "custom",
                            "tokenizer": "keyword"
                        }
                    }
                },
                "number_of_replicas": "1",
                "uuid": "eRkq_bCyTuuPByMREL4M_w",
                "version": {
                    "created": "6020399"
                }
            }
        }
    }
}

 

有一个需要主要的是zipkin 会将annoation 及tags。一起写如es的一个字段“_q”,方便查询

* <p>Ex {@code curl -s localhost:9200/zipkin:span-2017-08-11/_search?q=_q:error=500}
   */
  static byte[] prefixWithTimestampMillisAndQuery(Span span, long timestampMillis) {
    Buffer query = new Buffer();
    JsonWriter writer = JsonWriter.of(query);
    try {
      writer.beginObject();

      if (timestampMillis != 0L) writer.name("timestamp_millis").value(timestampMillis);
      if (!span.tags().isEmpty() || !span.annotations().isEmpty()) {
        writer.name("_q");
        writer.beginArray();
        for (Annotation a : span.annotations()) {
          if (a.value().length() > 255) continue;
          writer.value(a.value());
        }
        for (Map.Entry<String, String> tag : span.tags().entrySet()) {
          if (tag.getKey().length() + tag.getValue().length() + 1 > 255) continue;
          writer.value(tag.getKey()); // search is possible by key alone
          writer.value(tag.getKey() + "=" + tag.getValue());
        }
        writer.endArray();
      }
      writer.endObject();
    } catch (IOException e) {
      // very unexpected to have an IOE for an in-memory write
      assert false : "Error indexing query for span: " + span;
      if (LOG.isLoggable(Level.FINE)) {
        LOG.log(Level.FINE, "Error indexing query for span: " + span, e);
      }
      return SpanBytesEncoder.JSON_V2.encode(span);
    }
    byte[] document = SpanBytesEncoder.JSON_V2.encode(span);
    if (query.rangeEquals(0L, ByteString.of(new byte[] {'{', '}'}))) {
      return document;
    }
    byte[] prefix = query.readByteArray();

    byte[] newSpanBytes = new byte[prefix.length + document.length - 1];
    int pos = 0;
    System.arraycopy(prefix, 0, newSpanBytes, pos, prefix.length);
    pos += prefix.length;
    newSpanBytes[pos - 1] = ',';
    // starting at position 1 discards the old head of '{'
    System.arraycopy(document, 1, newSpanBytes, pos, document.length - 1);
    return newSpanBytes;
  }

由于tags。是不可搜索的,所以针对tags.我们可以利用_q进行搜索。针对文中的tag。可以这么搜索

 "term": {
                "_q": "chane"
              }

 "term": {
                "_q": "chane=1234"
              }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值