您的位置:

Skywalking链路追踪深度解析

一、Skywalking链路追踪概述

Skywalking是一款全面的分布式系统监控解决方案,它能够监控Spring、Dubbo、Spring Cloud、gRPC、.NET Core等多种服务类型,可以完全覆盖不同复杂程度的分布式应用程序。在Skywalking中,链路追踪是非常核心的一部分,通过链路追踪可以详细了解服务调用的每个节点、延迟和调用关系,有助于排查故障和优化性能。

二、Skywalking链路追踪原理

Skywalking采用的是追踪点的方式来实现链路追踪,它在分布式应用程序的关键节点上埋入了追踪点,通过在服务调用时请求追踪点去生成Span(各个服务向追踪点发送的请求和响应),同时在每个Span中嵌入Trace(整个追踪的根节点)。这样,就可以构建出完整的调用链路,包含每个服务的调用情况和调用耗时。


Trace
└── Span(服务A)
    ├── Span(服务B)
    │   ├── Span(服务C)
    │   └── Span(服务D)
    ├── Span(服务C)
    └── Span(服务D)

三、Skywalking链路追踪实践

1、通过Skywalking进行服务调用链路追踪

首先,需要在应用程序(Java应用)中添加Skywalking的Agent依赖,并配置统一的Agent Server地址。然后,在需要进行链路追踪的代码中添加Skywalking提供的Tracing API。


import org.apache.skywalking.apm.toolkit.trace.Trace;

public class ServiceA {
    @Trace
    public void callServiceB() {
        ...
    }
}

2、Skywalking链路追踪中的Tag和Log

除了默认的Span信息和Metrics信息外,Skywalking还支持自定义添加Tag和Log信息,这是非常有用的一种方式,可以在业务代码中打出一定的标记,方便后续排查问题。

添加Tag信息


Tracer tracer = TracingContextManager.get().getTracer();
tracer.tag("key", "value");

添加Log信息


Tracer tracer = TracingContextManager.get().getTracer();
tracer.log("log message");

3、通过Skywalking实现服务调用性能优化

Skywalking可以通过支持的多种插件来获取更多的性能数据,比如数据库连接池插件、Redis插件等。通过不同的插件,可以深入到底层,了解应用程序的性能瓶颈,从而进行调优。

四、Skywalking链路追踪中的常见问题及解决方案

1、Skywalking无法追踪到Web请求

解决方案:需要在应用程序中添加Skywalking针对Web请求的Filter,以保证能够追踪Web请求。


import org.apache.skywalking.apm.toolkit.trace.TraceCrossThread;

public class WebRequestFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        TracingContext tracingContext = TracingContextManager.getContext();
        if (tracingContext == null) {
            return;
        }
        Tracer tracer = tracingContext.getTracer();
        TraceCrossThread traceCrossThread = tracer.buildSpan("HttpRequest").startActive().get().traceCrossThread();
        try {
            traceCrossThread.setCarrier((key, value) -> {
                response.setHeader(key, value);
            });
            chain.doFilter(request, response);
        } finally {
            traceCrossThread.finish();
        }
    }
}

2、Skywalking链路追踪信息不完整

解决方案:需要在应用程序中添加Skywalking的全部插件进行深度监控,以保证链路追踪信息的完整性。

五、Skywalking链路追踪实战演练

在本节内容中,我们将演示如何通过Skywalking追踪Spring Cloud应用程序的调用链路,并使用Tag和Log记录关键点信息。

演示项目介绍

此次演示使用的是Spring Cloud官方提供的"Dalston.SR2"版本,该版本包含了Eureka、Feign等基本组件,以及两个微服务"service1"和"service2"。

演示步骤

1、下载并启动Skywalking Server

通过官网下载最新的Skywalking Server,并启动。


./bin/startup.sh

2、修改服务端配置(service1和service2)

修改bootstrap.yml文件,添加Skywalking Agent配置。


skywalking:
  agent:
    service_name: service1
    collector_address: localhost:11800
  trace:
    segment:
      enable: true

3、添加Skywalking Agent依赖

在服务1和服务2的pom.xml文件中,添加Skywalking Agent依赖,以及所需的Spring Cloud组件。


<dependency>
    <groupId>org.apache.skywalking</groupId>
    <artifactId>apm-toolkit-trace</artifactId>
    <version>8.0.0</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-feign</artifactId>
</dependency>

4、编写Service API

在服务1和服务2中,编写出一套简单的Service API。


@RequestMapping("/service1")
public interface Service1Api {
    @GetMapping("/call")
    String call();
}

@RequestMapping("/service2")
public interface Service2Api {
    @GetMapping("/call")
    String call();
}

5、编写Feign Client

在服务1中,编写出对服务2的Feign Client,实现调用Service2的逻辑。


@FeignClient(name = "service2")
public interface Service2Client {
    @GetMapping("/service2/call")
    String call();
} 

6、编写调用逻辑代码

在服务1中,编写出调用Service2的逻辑代码。


@RestController
public class Service1Controller implements Service1Api {
    @Autowired
    private Service2Client service2Client;
    @Autowired
    private Tracer tracer;
    @Override
    public String call() {
        Span span = tracer.buildSpan("Service1.call").start();
        try (Scope scope = tracer.scopeManager().activate(span, false)) {
            return service2Client.call();
        } finally {
            span.finish();
        }
    }
}

7、启动Eureka Server、Service1和Service2

分别启动Eureka Server、Service1和Service2。


java -jar eureka-server.jar
java -jar service1.jar
java -jar service2.jar

8、访问Service1并查看结果

访问"http://localhost:8081/service1/call",并在Skywalking控制台中查看调用链路和Tag、Log信息。

六、总结

通过本文的介绍,我们了解了Skywalking链路追踪的概念和原理,学会了如何在实践中使用Skywalking进行链路追踪,并掌握了如何通过Skywalking完善的插件和Tag/Log功能,来进行性能优化和问题排查。