Sleuth

原理介绍

Sleuth通过Trace定义一次业务调用链,根据它的信息,我们就知道多少个系统参与了该业务处理。
Span用来记录系统间的调用顺序和时间戳信息。
Trace和Span的信息经过整合,就能知道该业务的完整调用链。

Brave和Zipkin

Brave是一个用于捕捉分布式系统之间调用信息的工具库,然后将这些信息以Span的形式发送给Zipkin。
参考:https://github.com/openzipkin/brave

从2.0.0版本开始,Sleuth不再自己存储上下文信息,而是使用Brave作为调用链工具库,并且遵循Brave的命名和标记惯例。

如果你想延用老版本的使用方式,可以配置spring.sleuth.http.legacy.enabled=true

Zipkin是一个基于Google Dapper论文设计的分布式跟踪系统,它收集系统的延时数据并提供展示界面,以便用户排查问题。
参考:https://github.com/openzipkin/zipkin

Zipkin启动方式

  • java -jar zipkin.jar
  • 还支持源码部署和Docker镜像启动。
  • Zipkin支持各种持久化方式,默认存储在内存中
  • 部署后,默认的启动端口位9411,http://localhost:9411/

使用

引入spring-cloud-starter-sleuth依赖之后,我们的日志组件可以自动打印Span信息。可以随着feign、restTemplate往服务端传递,也可以在父子线程间传递。

依赖

<!--sleuth-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

<!--openfeign-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>


<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

Sleuth对feign的支持

  • Feign提供了feign.Client接口以便开发者自定义远程调用功能。
  • Sleuth使用了TracingFeignClient实现Feign接口,在Http调用前,在Header中添加Span信息。
public Response execute(Request request, Options options) throws IOException {
    Map<String, Collection<String>> headers = new HashMap(request.headers());
    Span span = this.handleSend(headers, request, (Span)null);
    if (log.isDebugEnabled()) {
        log.debug("Handled send of " + span);
    }

    Response response = null;
    IOException error = null;

    Object var9;
    try {
        SpanInScope ws = this.tracer.withSpanInScope(span);
        Throwable var8 = null;

        try {
            var9 = response = this.delegate.execute(this.modifiedRequest(request, headers), options);
        } catch (Throwable var27) {
            var9 = var27;
            var8 = var27;
            throw var27;
        } finally {
            if (ws != null) {
                if (var8 != null) {
                    try {
                        ws.close();
                    } catch (Throwable var26) {
                        var8.addSuppressed(var26);
                    }
                } else {
                    ws.close();
                }
            }

        }
    } catch (RuntimeException | Error | IOException var29) {
        error = var29;
        throw var29;
    } finally {
        this.handleReceive(span, response, error);
        if (log.isDebugEnabled()) {
            log.debug("Handled receive of " + span);
        }

    }

    return (Response)var9;
}

Sleuth对RestTemplate的支持

对RestTemplate的支持并不是临时初始化的,需要将RestTemplate注册成一个Bean。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package brave.spring.web;

import brave.Span;
import brave.Tracer;
import brave.Tracing;
import brave.Tracer.SpanInScope;
import brave.http.HttpClientAdapter;
import brave.http.HttpClientHandler;
import brave.http.HttpTracing;
import brave.propagation.Propagation.Setter;
import brave.propagation.TraceContext.Injector;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;

public final class TracingClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
    static final Setter<HttpHeaders, String> SETTER = new Setter<HttpHeaders, String>() {
        public void put(HttpHeaders carrier, String key, String value) {
            carrier.set(key, value);
        }

        public String toString() {
            return "HttpHeaders::set";
        }
    };
    final Tracer tracer;
    final HttpClientHandler<HttpRequest, ClientHttpResponse> handler;
    final Injector<HttpHeaders> injector;

    public static ClientHttpRequestInterceptor create(Tracing tracing) {
        return create(HttpTracing.create(tracing));
    }

    public static ClientHttpRequestInterceptor create(HttpTracing httpTracing) {
        return new TracingClientHttpRequestInterceptor(httpTracing);
    }

    @Autowired
    TracingClientHttpRequestInterceptor(HttpTracing httpTracing) {
        this.tracer = httpTracing.tracing().tracer();
        this.handler = HttpClientHandler.create(httpTracing, new TracingClientHttpRequestInterceptor.HttpAdapter());
        this.injector = httpTracing.tracing().propagation().injector(SETTER);
    }

    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        Span span = this.handler.handleSend(this.injector, request.getHeaders(), request);
        ClientHttpResponse response = null;
        IOException error = null;

        Object var9;
        try {
            SpanInScope ws = this.tracer.withSpanInScope(span);
            Throwable var8 = null;

            try {
                var9 = response = execution.execute(request, body);
            } catch (Throwable var27) {
                var9 = var27;
                var8 = var27;
                throw var27;
            } finally {
                if (ws != null) {
                    if (var8 != null) {
                        try {
                            ws.close();
                        } catch (Throwable var26) {
                        }
                    } else {
                        ws.close();
                    }
                }

            }
        } catch (RuntimeException | Error | IOException var29) {
            error = var29;
            throw var29;
        } finally {
            this.handler.handleReceive(response, error, span);
        }

        return (ClientHttpResponse)var9;
    }

    static final class HttpAdapter extends HttpClientAdapter<HttpRequest, ClientHttpResponse> {
        HttpAdapter() {
        }

        public String method(HttpRequest request) {
            return request.getMethod().name();
        }

        public String url(HttpRequest request) {
            return request.getURI().toString();
        }

        public String requestHeader(HttpRequest request, String name) {
            Object result = request.getHeaders().getFirst(name);
            return result != null ? result.toString() : "";
        }

        public Integer statusCode(ClientHttpResponse response) {
            try {
                return response.getRawStatusCode();
            } catch (IOException var3) {
                return null;
            }
        }
    }
}

Sleuth对多线程的支持

Sleuth提供了三种多线程实现

  • LazyTraceExecutor
  • TraceableExecutorService
  • TraceableScheduleExecutorService
    它们可以在创建新的任务时新建一个Span。
    必须使用这三种多线程实现才有效。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值