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
-
- 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>
-
- 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; } }
-
- Dubbo filter
DubboZipkinConsumerFilter.java
- Dubbo filter
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(); } } }
-
- configuration file
META-INF/spring.factories
- configuration file
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
-
- 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.