sping cloud component link tracking Zipkin

Keywords: Dubbo Java Spring network

From Here https://www.jianshu.com/p/1ef5cd97ba2b

 

What is Zipkin

Zipkin is an open source distributed real-time data tracking system, designed based on a paper by Google Dapper and developed by Twitter.Its main function is to aggregate real-time monitoring data from heterogeneous systems.Distributed tracking systems have other mature implementations, such as Naver's Pinpoint, Apache's HTrace, Ali's Eagle Tracing, Hedra in Jingdong, Watchman in Sina, CAT in Meituan's comments, skywalking, and so on.

Why use Zipkin

As business becomes more complex, systems are also split, especially with the rise of micro-service architecture and container technology, a seemingly simple application may be supported by dozens or even hundreds of services in the background; a front-end request may require multiple service calls to complete; when requests are slow or unavailable, we cannot tell which one isAs a result of background services, how to locate service failures quickly is a problem that Zipkin Distributed Tracking System can solve very well.

Zipkin architecture

zipkin architecture

 

As shown in the diagram, Zipkin consists of four main components: a collector, a data store, a query, and a Web interface.Zipkin's collector receives tracking data reported by each system; the data store uses Cassandra by default, or it can be replaced with MySQL; the query service provides the ability to query data to other services, while the Web service is an official default graphical user interface.

The architecture for reporting data to Zipkin by heterogeneous system services is illustrated below.

 

Tracking Information Collection

Zipkin Client Brave

Brave is a class library used to equip Java programs. It provides equipment capabilities for interfaces such as Standard Servlet, Spring MVC, Http Client, JAX RS, Jersey, Resteasy, and MySQL. Applications built on these frameworks can report data to Zipkin by writing simple configuration and code.Brave also provides a very simple and standardized interface that can be easily extended and customized when the above encapsulation fails to meet the requirements.

The following is a diagram of Brave's structure.Brave uses the reporter to send trace information to the Collector of zipkin.

 

Brave

Zipkin Installation

docker-compose.yml

 

version: '2'

services:
  # The zipkin process services the UI, and also exposes a POST endpoint that
  # instrumentation can send trace data to. Scribe is disabled by default.
  zipkin:
    image: openzipkin/zipkin
    container_name: zipkin
    environment:
      #- STORAGE_TYPE=mem
      - STORAGE_TYPE=mysql
      # Point the zipkin at the storage backend
      - MYSQL_DB=zipkin
      - MYSQL_USER=root
      - MYSQL_PASS=123456
      - MYSQL_HOST=192.168.1.8
      - MYSQL_TCP_PORT=3306
      # Uncomment to enable scribe
      # - SCRIBE_ENABLED=true
      # Uncomment to enable self-tracing
      # - SELF_TRACING_ENABLED=true
      # Uncomment to enable debug logging
      # - JAVA_OPTS=-Dlogging.level.zipkin=DEBUG -Dlogging.level.zipkin2=DEBUG
    ports:
      # Port used for the Zipkin UI and HTTP Api
      - 9411:9411
      # Uncomment if you set SCRIBE_ENABLED=true
      # - 9410:9410
    #networks: 
    #  - default 
    #  - my_net #Create network docker network create my_net Delete network docker network rm my_net
#networks: 
  #my_net: 
    #external: true

Access Test: http://localhost:9411

Dubbo Integration Zipkin

    1. POM.xml

 

    <properties>
        <brave.version>4.19.2</brave.version>
        <zipkin-reporter.version>2.1.3</zipkin-reporter.version>
        <zipkin.version>2.8.1</zipkin.version>
    </properties>
    <dependencies>
        <!-- wrong WEB starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <!-- dubbo starter -->
        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>0.2.0</version>
        </dependency>

        <dependency>
            <groupId>io.zipkin.reporter2</groupId>
            <artifactId>zipkin-reporter</artifactId>
            <version>2.6.0</version>
            <type>pom</type>
        </dependency>
        <dependency>
            <groupId>io.zipkin.reporter2</groupId>
            <artifactId>zipkin-sender-okhttp3</artifactId>
            <version>2.6.0</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave</artifactId>
            <version>4.19.2</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-context-log4j2</artifactId>
            <version>4.19.2</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-instrumentation-http</artifactId>
            <version>4.19.2</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-instrumentation-http-tests</artifactId>
            <version>4.19.2</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-instrumentation-servlet</artifactId>
            <version>4.19.2</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-tests</artifactId>
            <version>4.19.2</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.zipkin2</groupId>
            <artifactId>zipkin</artifactId>
            <version>${zipkin.version}</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin</artifactId>
            <version>${zipkin.version}</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-junit</artifactId>
            <version>${zipkin.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.13</version>
        </dependency>
    </dependencies>
    1. JAVA Configuration Class

 

package com.suoron.login.api.config;

import brave.Tracing;
import brave.servlet.TracingFilter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import zipkin2.reporter.AsyncReporter;
import zipkin2.reporter.Reporter;
import zipkin2.reporter.Sender;
import zipkin2.reporter.okhttp3.OkHttpSender;
import zipkin2.Span;
import javax.servlet.Filter;

@Configuration
public class TracingConfig {

    /**
     * Configure zipkin service address
     */
    @Value("${zipkin.tracing.endpoint:http://10.3.135.166:9411/api/v2/spans}")
    private String zipkinEndPoint;

    @Value("${zipkin.tracing.local-service-name:local-service-name}")
    private String localServiceName;

    /**
     * Configure sender
     * @return
     */
    @Bean
    public Sender sender(){
        OkHttpSender sender = OkHttpSender
                .newBuilder()
                .endpoint(zipkinEndPoint)
                .build();
        return sender;
    }

    /**
     * Configure reporter
     * @param sender
     * @return
     */
    @Bean
    public Reporter<Span> reporter(Sender sender){
        return AsyncReporter
                .builder(sender)
                .build();
    }

    /**
     * Configure dubbo-consumer tracing
     * @param reporter
     * @return
     */
    @Bean
    public Tracing tracing(Reporter reporter){
        return Tracing.newBuilder()
                .localServiceName(localServiceName)
                .spanReporter(reporter)
                .build();
    }

    /**
     * Configure http tracing
     * @param reporter
     * @return
     */
    @Bean
    public Tracing tracing2(Reporter reporter){
        return Tracing.newBuilder()
                .localServiceName(localServiceName + "_http")
                .spanReporter(reporter)
                .build();
    }

    /**
     * Configure servlet filter
     * @param tracing2
     * @return
     */
    @Bean
    public Filter filter(Tracing tracing2){
        return TracingFilter.create(tracing2);
    }

    /**
     * Register filter
     * @param filter
     * @return
     */
    @Bean
    public FilterRegistrationBean filterRegistration(Filter filter) {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(filter);
        registration.addUrlPatterns("/*");
        registration.setName("zipkin-filter");
        registration.setOrder(1);
        return registration;
    }
}
    1. Dubbo filter
      DubboZipkinConsumerFilter.java

 

package com.suoron.login.api.filter;

import brave.Span;
import brave.Tracer;
import brave.Tracing;
import brave.propagation.TraceContext;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory;
import com.alibaba.dubbo.rpc.*;
import com.alibaba.dubbo.rpc.support.RpcUtils;
import com.suoron.login.api.utils.ZipkinHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;

import static com.suoron.login.api.utils.ZipkinHelper.SETTER;

@Activate(group = Constants.CONSUMER)
public class DubboZipkinConsumerFilter implements Filter {
    private static final Logger log = LoggerFactory.getLogger(DubboZipkinConsumerFilter.class);

    private SpringExtensionFactory springExtensionFactory = new SpringExtensionFactory();
    private Tracer tracer;

    // tracing Context Message Injection
    private TraceContext.Injector<Map<String, String>> injector;

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        log.info("dubbo zipkin consumer filter......");

        Tracing tracing = springExtensionFactory.getExtension(Tracing.class, "tracing");
        tracer = tracing.tracer();
        if (tracer == null){
            return invoker.invoke(invocation);
        }

        if (null == injector){
            injector = tracing.propagation().injector(SETTER);
        }

        RpcContext rpcContext = RpcContext.getContext();
        Span span = tracer.nextSpan();
        injector.inject(span.context(), invocation.getAttachments());

        ZipkinHelper.buildSpan(span, Span.Kind.CONSUMER, rpcContext.getRemoteAddress(), invoker.getInterface().getSimpleName(),
                RpcUtils.getMethodName(invocation));

        return ZipkinHelper.spanTracing(span, tracer, invoker, invocation, rpcContext);
    }

}

DubboZipkinProviderFilter.java

 

package com.suoron.login.api.filter;

import brave.Span;
import brave.Tracer;
import brave.Tracing;
import brave.propagation.TraceContext;
import brave.propagation.TraceContextOrSamplingFlags;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory;
import com.alibaba.dubbo.rpc.*;
import com.alibaba.dubbo.rpc.support.RpcUtils;
import com.suoron.login.api.utils.ZipkinHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;

import static com.suoron.login.api.utils.ZipkinHelper.*;

@Activate(group = Constants.PROVIDER)
public class DubboZipkinProviderFilter implements Filter {

    private static final Logger log = LoggerFactory.getLogger(DubboZipkinProviderFilter.class);

    private SpringExtensionFactory springExtensionFactory = new SpringExtensionFactory();
    private Tracer tracer;

    // tracing Context Message Extraction
    private TraceContext.Extractor<Map<String, String>> extractor;

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        log.info("dubbo zipkin provider filter......");

        Tracing tracing = springExtensionFactory.getExtension(Tracing.class, "tracing");
        tracer = tracing.tracer();
        if (null == tracer){
            return invoker.invoke(invocation);
        }

        if (null == extractor){
            extractor = tracing.propagation().extractor(GETTER);
        }

        TraceContextOrSamplingFlags extracted = extractor.extract(invocation.getAttachments());
        Span span = extracted.context() != null
                ? tracer.joinSpan(extracted.context())
                : tracer.nextSpan(extracted);

        RpcContext rpcContext = RpcContext.getContext();
        ZipkinHelper.buildSpan(span, Span.Kind.SERVER, rpcContext.getRemoteAddress(), invoker.getInterface().getSimpleName(),
                RpcUtils.getMethodName(invocation));

        return ZipkinHelper.spanTracing(span, tracer, invoker, invocation, rpcContext);
    }
}

ZipkinHelper.java -- Auxiliary Class

 

package com.suoron.login.api.utils;

import brave.Span;
import brave.Tracer;
import brave.propagation.Propagation;
import com.alibaba.dubbo.remoting.exchange.ResponseCallback;
import com.alibaba.dubbo.rpc.*;
import com.alibaba.dubbo.rpc.protocol.dubbo.FutureAdapter;
import com.alibaba.dubbo.rpc.support.RpcUtils;
import com.alibaba.fastjson.JSON;
import zipkin2.Endpoint;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.Future;

/**
 * @author Suoron
 * @Description:
 * @date 2018/6/22 10:44
 */
public class ZipkinHelper {

    public static final Propagation.Setter<Map<String, String>, String> SETTER =
            new Propagation.Setter<Map<String, String>, String>() {
                @Override
                public void put(Map<String, String> carrier, String key, String value) {
                    carrier.put(key, value);
                }
                @Override
                public String toString() {
                    return JSON.toJSONString(this);
                }
            };
    public static final Propagation.Getter<Map<String, String>, String> GETTER =
            new Propagation.Getter<Map<String, String>, String>() {
                @Override
                public String get(Map<String, String> carrier, String key) {
                    return carrier.get(key);
                }

                @Override
                public String toString() {
                    return JSON.toJSONString(this);
                }
            };

    public static void buildSpan(Span span, Span.Kind kind, InetSocketAddress remoteAddress, String service, String method){
        if (!span.isNoop()) {
            span.kind(kind).start();
            span.kind(kind);
            span.name(service + "/" + method);
            Endpoint.Builder remoteEndpoint = Endpoint.newBuilder().port(remoteAddress.getPort());
            if (!remoteEndpoint.parseIp(remoteAddress.getAddress())) {
                remoteEndpoint.parseIp(remoteAddress.getHostName());
            }
            span.remoteEndpoint(remoteEndpoint.build());
        }
    }

    public static Result spanTracing(Span span, Tracer tracer, Invoker<?> invoker, Invocation invocation, RpcContext rpcContext){
        boolean isOneway = false;
        boolean deferFinish = false;
        try (Tracer.SpanInScope scope = tracer.withSpanInScope(span)) {
            Result result = invoker.invoke(invocation);
            if (result.hasException()) {
                onError(result.getException(), span);
            }
            isOneway = RpcUtils.isOneway(invoker.getUrl(), invocation);
            Future<Object> future = rpcContext.getFuture(); // the case on async client invocation
            if (future instanceof FutureAdapter) {
                deferFinish = true;
                ((FutureAdapter) future).getFuture().setCallback(new ZipkinHelper.FinishSpanCallback(span));
            }
            return result;
        } catch (Exception e) {
            onError(e, span);
            throw e;
        } finally {
            if (isOneway) {
                span.flush();
            } else if (!deferFinish) {
                span.finish();
            }
        }
    }

    public static void onError(Throwable error, Span span) {
        span.error(error);
        if (error instanceof RpcException) {
            span.tag("dubbo.error_code", Integer.toString(((RpcException) error).getCode()));
        }
    }

    public static final class FinishSpanCallback implements ResponseCallback {
        final Span span;

        FinishSpanCallback(Span span) {
            this.span = span;
        }

        @Override
        public void done(Object response) {
            span.finish();
        }

        @Override
        public void caught(Throwable exception) {
            onError(exception, span);
            span.finish();
        }
    }
}
    1. configuration file
      META-INF/spring.factories

 

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.suoron.login.api.config.TracingConfig

META-INF/dubbo/com.alibaba.dubbo.rpc.Filter

 

zipkinConsumerDubboFilter=com.suoron.login.api.filter.DubboZipkinConsumerFilter
zipkinProviderDubboFilter=com.suoron.login.api.filter.DubboZipkinProviderFilter

application.yml

 

# Consumer Configuration
zipkin:
  tracing:
    local-service-name: login-consumer
# Provider Configuration
zipkin:
  tracing:
    local-service-name: login-provider
    1. Filter usage

 

// Provider Interface Implementation Class
@Service(version = "1.0.0",token = "12345678",filter = "zipkinProviderDubboFilter")
public class ILoginServiceImpl implements ILoginService {
    ...
}
// Consumer Call Class
    @Reference(version = "1.0.0",filter = "zipkinConsumerDubboFilter")
    public ILoginService iLoginService;



Author: Solen x
Link: https://www.jianshu.com/p/1ef5cd97ba2b
Copyright belongs to the author.For commercial reprinting, please contact the author for authorization. For non-commercial reprinting, please indicate the source.

Published an original article. Praise 0. Visits 10
Private letter follow

Posted by agriz on Fri, 07 Feb 2020 17:46:32 -0800