zipkin日志追踪分析笔记

客户端数据收集:
采样率是由org.springframework.cloud.sleuth.sampler.SamplerProperties里面
spring.sleuth.sampler.percentage
来控制的

org.springframework.cloud.sleuth.autoconfig.SleuthProperties里面通过
spring.sleuth.enabled=true来控制的

请求过滤:
SleuthWebProperties里面的DEFAULT_SKIP_PATTERN常量默认过来掉一部分请求
public static final String DEFAULT_SKIP_PATTERN =
"/api-docs.*|/autoconfig|/configprops|/dump|/health|/info|/metrics.*|/mappings|/trace|/swagger.*|.*\\.png|.*\\.css|.*\\.js|.*\\.html|/favicon.ico|/hystrix.stream";

可以通过SleuthSchedulingProperties里面设置spring.sleuth.scheduled.skipPattern属性进行业务请求过滤

org.springframework.cloud.sleuth.instrument.web.TraceFilter里面有一个doFilter方法进行请求拦截收集
调用
detachOrCloseSpans
调用
recordParentSpan(span);
调用
spanReporter().report(parent);
调用
ZipkinSpanListener-----》public void report(Span span)
调用
this.reporter.report(convert(span));

org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter类的
public void report(Span span) {
this.delegate.report(span);
}
实现了http方式的数据传输
HttpZipkinSpanReporter中定义了
this.sender = new RestTemplateSender(restTemplate, baseUrl);




org.springframework.cloud.sleuth.stream.StreamSpanReporter类实现了SpanReporter接口里面的 report(Span span)方法收集日志数据,poll方法通过MQ的方式发送数据
@InboundChannelAdapter(value = SleuthSource.OUTPUT, poller = @Poller(POLLER))
public Spans poll() {
List result = new LinkedList<>();
this.queue.drainTo(result);
for (Iterator iterator = result.iterator(); iterator.hasNext();) {
Span span = iterator.next();
if (span.getName() != null && span.getName().equals("message/" + SleuthSource.OUTPUT)) {
iterator.remove();
}
}
if (result.isEmpty()) {
return null;
}
if (log.isDebugEnabled()) {
log.debug("Processed [" + result.size() + "] spans");
}
this.spanMetricReporter.incrementAcceptedSpans(result.size());
return new Spans(this.endpointLocator.locate(result.get(0)), result);
}

微服务发送请求时会在控制台打出如下所示的日志:
2017-08-08 09:28:13.246 INFO [registry,c6628fc0c29455da,c6628fc0c29455da,false]3468 --- [ask-scheduler-3] o.s.i.codec.kryo.CompositeKryoRegistrar : registering [40, java.io.File] with serializer org.springframework.integration.codec.kryo.FileSerializer
2017-08-08 09:28:13.279 DEBUG [registry,2bd2dac9b3506e76,2bd2dac9b3506e76,true]
其中[ registry,c6628fc0c29455da,c6628fc0c29455da,false] 这四个值分别表示:
  • 第一个值:registryi表示的是应用的名称
  • 第二个值:c6628fc0c29455da,spring cloud sleuth生成的一个ID,叫做Trace ID 用来标识一条链路请求,一条链路请求包含一个Trace ID,多个Span ID
  • 第三个值:c6628fc0c29455da,spring cloud sleuth生成的一个Span ID ,表示一个基本的工作单元,比如发送一个http请求
  • 第四个值:false,表示是否将改信息输出打牌Zipkin服务收集和展示

服务端数据消费:
HTTP:
ZipkinHttpCollector

MQ:
org.springframework.cloud.sleuth.zipkin.stream.ZipkinMessageListener这个类中定义了消息监听的实现方法sink
@StreamListener(SleuthSink.INPUT)
public void sink(Spans input) {
List converted = ConvertToZipkinSpanList.convert(input);
this.collector.accept(converted, Callback.NOOP);
}
其中SleuthSink.INPUT定义了默认的监听输入通道"sleuth"
执行顺序为:
this.collector.accept调用 zipkin.collector.Collector.accept()方法:
public void accept(List spans, Callback callback) {
if (spans.isEmpty()) {
callback.onSuccess(null);
return;
}
metrics.incrementSpans(spans.size());

List sampled = sample(spans);
if (sampled.isEmpty()) {
callback.onSuccess(null);
return;
}

try {
storage.asyncSpanConsumer().accept(sampled, acceptSpansCallback(sampled));
callback.onSuccess(null);
} catch (RuntimeException e) {
callback.onError(errorStoringSpans(sampled, e));
return;
}
}
接着调用zipkin.storage.InternalBlockingToAsyncSpanConsumerAdapter中的accept()方法
@Override
public void accept(final List spans, Callback callback) {
executor.execute(new InternalCallbackRunnable(callback) {
@Override Void complete() {
delegate.accept(spans);
return null;
}

@Override public String toString() {
return "Accept(" + spans + ")";
}
});
}
接着调用zipkin.storage.mysql.MySQLSpanConsumer中的accept(List spans)方法进行数据存储

数据使用jooq进行存储的,存储的入口在
zipkin.storage.mysql.MySQLSpanConsumer这个类里面的accept(List spans)方法

你可能感兴趣的:(微服务)