分布式链路跟踪——OpenZipkin(推特使用)

        如果将分布式系统比作高速公路网,每个前端的请求就相当于高速上行驶的车辆,而处理请求的应用就是高速上的收费站,在收费站上将车辆通行信息记录成日志,包括时间、车牌、站点、公路、价格等,如果将所有收费站上的日志整合在一起,便可以通过唯一的车牌号确定该车的完整通行记录;分布式调用系统跟踪和监控就是类比这种思想,对每一次请求进行跟踪,进而明确每个请求所经过的应用、耗时等信息。

业界非常知名的分布式链路跟踪服务:

阿里:鹰眼

大众点评:CAT

美团:OCTO

京东: Hydra

Twitter—OpenZipkin

鹰眼系统简介:

         阿里中分布式调用跟踪是采用鹰眼(EagleEye)系统来实现的,鹰眼是基于日志的分布式调用跟踪系统,其理念脱胎于Google Dapper论文,其关键核心在于调用链,为每个请求生成全局唯一的ID(Traceld),通过它将不同系统的“孤立的”调用信息关联在一起,还原出更多有价值的数据。         

        可以在业务异常日志的错误信息中找到Traceld(比如TraceId=ac18287913742691251746923),之后在鹰眼系统中只需要输入Traceld,就可以看到调用链中具体的情况,在调用链上更加直观地定位到问题,层层排查后确定问题的所在。

springcloud 整合ZipKin

        ZipKin是一个链路跟踪工具,可以用来监控微服务集群中调用链路的通畅情况

        首先,ZipKin是Spring Cloud 的分布式链路跟踪解决方案:

         比如存在两个子项目,并在一个项目中使用RestTemplate或者Feign等方法调用另外一个项目中的接口,这样就可以利用ZipKin进行跟踪服务!

        第一步:需要一个zipkin-server服务

        第二步:需要两个trace服务,然后进行调用跟踪

代码实现

1.server/serversteam / eureka/多个trace1(服务提供者)/trace2

server端代码实现

pom代码:

最好把数据存到ES上:数据量大,查询快

<dependency>
              <groupId>io.zipkin.java</groupId>
              <artifactId>zipkin-server</artifactId>
          </dependency>
          <dependency>
              <groupId>io.zipkin.java</groupId>
              <artifactId>zipkin-autoconfigure-storage-mysql</artifactId>
          </dependency>
          <dependency>
              <groupId>io.zipkin.java</groupId>
              <artifactId>zipkin-autoconfigure-ui</artifactId>
          </dependency>

<dependency>
              <groupId>org.jooq</groupId>
              <artifactId>jooq</artifactId>
          </dependency>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.bfxy</groupId>
    <artifactId>spring-cloud-master</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>spring-cloud-08-zipkin-server</artifactId>

  <dependencies>
	  	<dependency>
	  		<groupId>io.zipkin.java</groupId>
	  		<artifactId>zipkin-server</artifactId>
	  	</dependency>
	  	<dependency>
	  		<groupId>io.zipkin.java</groupId>
	  		<artifactId>zipkin-autoconfigure-storage-mysql</artifactId>
	  	</dependency>
	  	<dependency>
	  		<groupId>io.zipkin.java</groupId>
	  		<artifactId>zipkin-autoconfigure-ui</artifactId>
	  	</dependency>
	  	<dependency>
	  		<groupId>org.springframework.boot</groupId>
	  		<artifactId>spring-boot-starter-jdbc</artifactId>
	  	</dependency>
	  	<dependency>
	  		<groupId>mysql</groupId>
	  		<artifactId>mysql-connector-java</artifactId>
	  	</dependency>
	  	<dependency>
	  		<groupId>org.jooq</groupId>
	  		<artifactId>jooq</artifactId>
	  	</dependency>
  </dependencies>





  <dependencyManagement>
  	<dependencies>
  		<dependency>
  			<groupId>org.springframework.cloud</groupId>
  			<artifactId>spring-cloud-dependencies</artifactId>
  			<!-- <version>Dalston.SR5</version>  -->
  			<version>Edgware.SR4</version>
  			<!-- <version>Finchley.SR1</version>  -->
  			<type>pom</type>
  			<scope>import</scope>
  		</dependency>
  	</dependencies>
  </dependencyManagement>


  <build>
  		<finalName>spring-cloud-08-zipkin-server</finalName>
	  	<plugins>
	  		<plugin>
	  			<groupId>org.springframework.boot</groupId>
	  			<artifactId>spring-boot-maven-plugin</artifactId>
	  			<configuration>
	  				<mainClass>com.bfxy.springcloud.Application</mainClass>
	  			</configuration>
	  		</plugin>
	  	</plugins>
  </build>
</project>


配置文件:zipkin.storage.type=mysql

zipkin标准表:官网能下载

spring.datasource.schema=classpath:/zipkin.sql

表示加载resources下的sql文件

spring.datasource.schema=classpath:/zipkin.sql
spring.datasource.initialize=true

spring.application.name=zipkin-server
server.port=9500

spring.datasource.url=jdbc:mysql://localhost:3306/zipkin?characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useUnicode=true
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.schema=classpath:/zipkin.sql
spring.datasource.initialize=true
spring.datasource.continue-on-error=true

zipkin.storage.type=mysql
CREATE TABLE IF NOT EXISTS zipkin_spans (
  `trace_id` BIGINT NOT NULL,
  `id` BIGINT NOT NULL,
  `name` VARCHAR(255) NOT NULL,
  `parent_id` BIGINT,
  `debug` BIT(1),
  `start_ts` BIGINT COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL',
  `duration` BIGINT COMMENT 'Span.duration(): micros used for minDuration and maxDuration query'
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED;

ALTER TABLE zipkin_spans ADD UNIQUE KEY(`trace_id`, `id`) COMMENT 'ignore insert on duplicate';
ALTER TABLE zipkin_spans ADD INDEX(`trace_id`, `id`) COMMENT 'for joining with zipkin_annotations';
ALTER TABLE zipkin_spans ADD INDEX(`trace_id`) COMMENT 'for getTracesByIds';
ALTER TABLE zipkin_spans ADD INDEX(`name`) COMMENT 'for getTraces and getSpanNames';
ALTER TABLE zipkin_spans ADD INDEX(`start_ts`) COMMENT 'for getTraces ordering and range';

CREATE TABLE IF NOT EXISTS zipkin_annotations (
  `trace_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.trace_id',
  `span_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.id',
  `a_key` VARCHAR(255) NOT NULL COMMENT 'BinaryAnnotation.key or Annotation.value if type == -1',
  `a_value` BLOB COMMENT 'BinaryAnnotation.value(), which must be smaller than 64KB',
  `a_type` INT NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation',
  `a_timestamp` BIGINT COMMENT 'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp',
  `endpoint_ipv4` INT COMMENT 'Null when Binary/Annotation.endpoint is null',
  `endpoint_ipv6` BINARY(16) COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address',
  `endpoint_port` SMALLINT COMMENT 'Null when Binary/Annotation.endpoint is null',
  `endpoint_service_name` VARCHAR(255) COMMENT 'Null when Binary/Annotation.endpoint is null'
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED;

ALTER TABLE zipkin_annotations ADD UNIQUE KEY(`trace_id`, `span_id`, `a_key`, `a_timestamp`) COMMENT 'Ignore insert on duplicate';
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`, `span_id`) COMMENT 'for joining with zipkin_spans';
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`) COMMENT 'for getTraces/ByIds';
ALTER TABLE zipkin_annotations ADD INDEX(`endpoint_service_name`) COMMENT 'for getTraces and getServiceNames';
ALTER TABLE zipkin_annotations ADD INDEX(`a_type`) COMMENT 'for getTraces';
ALTER TABLE zipkin_annotations ADD INDEX(`a_key`) COMMENT 'for getTraces';

CREATE TABLE IF NOT EXISTS zipkin_dependencies (
  `day` DATE NOT NULL,
  `parent` VARCHAR(255) NOT NULL,
  `child` VARCHAR(255) NOT NULL,
  `call_count` BIGINT
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED;

ALTER TABLE zipkin_dependencies ADD UNIQUE KEY(`day`, `parent`, `child`);

主入口:@zipkin.server.internal.EnableZipkinServer

package com.bfxy.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@zipkin.server.internal.EnableZipkinServer
@SpringBootApplication	//SpringBoot 核心配置
public class Application {
	
	public static void main(String[] args) {
		
		SpringApplication.run(Application.class, args);
	}
	
}

此时http://localhost:9500  就可以访问zipken界面

trace1(注册到注册中心中):代码

<dependency>
  			<groupId>org.springframework.cloud</groupId>
  			<artifactId>spring-cloud-starter-sleuth</artifactId>
  		</dependency>
  		<dependency>
  			<groupId>org.springframework.cloud</groupId>
  			<artifactId>spring-cloud-sleuth-zipkin</artifactId>
  		</dependency>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.bfxy</groupId>
    <artifactId>spring-cloud-master</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>spring-cloud-08-trace-1</artifactId>
  <name>spring-cloud-08-trace-1</name>
  <description>spring-cloud-08-trace-1</description>

  <dependencies>
	  	<dependency>
	  		<groupId>org.springframework.boot</groupId>
	  		<artifactId>spring-boot-starter-web</artifactId>
	  	</dependency>
	  	<!-- 标识这个工程是一个服务,需要引入此jar -->
  		<dependency>
  			<groupId>org.springframework.cloud</groupId>
  			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  		</dependency>
  		<!-- 动态刷新的一个模块jar -->
  		<dependency>
  			<groupId>org.springframework.boot</groupId>
  			<artifactId>spring-boot-starter-actuator</artifactId>
  		</dependency>

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

  		 <!-- kafka -->
	  	<dependency>
	  		<groupId>org.springframework.cloud</groupId>
	  		<artifactId>spring-cloud-starter-stream-kafka</artifactId>
	  	</dependency>
	  	<dependency>
	  		<groupId>org.springframework.cloud</groupId>
	  		<artifactId>spring-cloud-sleuth-zipkin-stream</artifactId>
	  	</dependency>
  </dependencies>

  <dependencyManagement>
  	<dependencies>
  		<dependency>
  			<groupId>org.springframework.cloud</groupId>
  			<artifactId>spring-cloud-dependencies</artifactId>
  			<!-- <version>Dalston.SR5</version>  -->
  			<version>Edgware.SR4</version>
  			<!-- <version>Finchley.SR1</version>  -->
  			<type>pom</type>
  			<scope>import</scope>
  		</dependency>
  	</dependencies>
  </dependencyManagement>


  <build>
  		<finalName>spring-cloud-08-trace-1</finalName>
	  	<plugins>
	  		<plugin>
	  			<groupId>org.springframework.boot</groupId>
	  			<artifactId>spring-boot-maven-plugin</artifactId>
	  			<configuration>
	  				<mainClass>com.bfxy.springcloud.Application</mainClass>
	  			</configuration>
	  		</plugin>
	  	</plugins>
  </build>




</project>

主入口:

package com.bfxy.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@EnableDiscoveryClient	//标识具体的一个服务,需要向注册中心注册
@SpringBootApplication	//SpringBoot 核心配置
public class Application {

	@Bean
	@LoadBalanced //用于实现内部的服务负载均衡机制: service-id  service-name
	public RestTemplate restTemplate(){
		HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
		httpComponentsClientHttpRequestFactory.setConnectTimeout(10000);
		httpComponentsClientHttpRequestFactory.setConnectionRequestTimeout(10000);
		httpComponentsClientHttpRequestFactory.setReadTimeout(20000);
		return new RestTemplate(httpComponentsClientHttpRequestFactory);
	}
	
	public static void main(String[] args) {
		
		SpringApplication.run(Application.class, args);
	}
	
}

配置:

## 配置zipkin地址 以及sleuth服务抓取日志的采样百分比
spring.zipkin.base-url=http://localhost:9500
spring.sleuth.sampler.percentage=1.0   ##100%请求都会被采集,  0.8表示80%请求会被采集

##bus总线代码

spring.cloud.stream.kafka.binder.zkNodes=192.168.11.111:2181,192.168.11.112:2181,192.168.11.113:2181
spring.cloud.stream.kafka.binder.brokers=192.168.11.51:9092
spring.application.name=trace-1
server.context-path=/
server.port=7001

##需要引入eureka注册中心的地址
eureka.instance.prefer-ip-address=true
eureka.instance.instance-id=${spring.application.name}:${spring.cloud.client.ipAddress}:${server.port}
##租期更新时间间隔
eureka.instance.lease-renewal-interval-in-seconds=10
##租期的到期时间间隔
eureka.instance.lease-expiration-duration-in-seconds=30 
##开启健康检查(必须要引入spring-boot-starter-actuator)
eureka.client.healthcheck.enabled=true  
eureka.client.service-url.defaultZone=http://eureka1:8001/eureka


## 配置zipkin地址 以及sleuth服务抓取日志的采样百分比
spring.zipkin.base-url=http://localhost:9500
spring.sleuth.sampler.percentage=1.0

spring.cloud.stream.kafka.binder.zkNodes=192.168.11.111:2181,192.168.11.112:2181,192.168.11.113:2181
spring.cloud.stream.kafka.binder.brokers=192.168.11.51:9092







测试请求:

package com.bfxy.springcloud.api;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class Trace1Controller {
	
	@Autowired
	private RestTemplate restTemplate;
	
	@RequestMapping(value="/trace1")
	public String trace1(){
		System.err.println("--------------trace1-----------");
		return restTemplate.getForObject("http://trace-2/trace2", String.class);
	}
	
	
}

所有对接口请求的数据都会被监听。在zipkin中生成数据;如果trace1中调用trace2,trace2中调用trace3。则zipkin会根据采集请求概率对三个服务进行采集

数据库中就会出现三条数据。

使用kafka收集数据到zipkin

pom

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-sleuth-zipkin-stream</artifactId>
</dependency>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.bfxy</groupId>
    <artifactId>spring-cloud-master</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>spring-cloud-08-zipkin-server-stream</artifactId>

  <dependencies>
	  	<dependency>
	  		<groupId>io.zipkin.java</groupId>
	  		<artifactId>zipkin-server</artifactId>
	  	</dependency>
	  	<dependency>
	  		<groupId>io.zipkin.java</groupId>
	  		<artifactId>zipkin-autoconfigure-storage-mysql</artifactId>
	  	</dependency>
	  	<dependency>
	  		<groupId>io.zipkin.java</groupId>
	  		<artifactId>zipkin-autoconfigure-ui</artifactId>
	  	</dependency>
	  	<dependency>
	  		<groupId>org.springframework.boot</groupId>
	  		<artifactId>spring-boot-starter-jdbc</artifactId>
	  	</dependency>
	  	<dependency>
	  		<groupId>mysql</groupId>
	  		<artifactId>mysql-connector-java</artifactId>
	  	</dependency>
	  	<dependency>
	  		<groupId>org.jooq</groupId>
	  		<artifactId>jooq</artifactId>
	  	</dependency>
	  	<dependency>
	  		<groupId>org.springframework.cloud</groupId>
	  		<artifactId>spring-cloud-starter-stream-kafka</artifactId>
	  	</dependency>
	  	<dependency>
	  		<groupId>org.springframework.cloud</groupId>
	  		<artifactId>spring-cloud-sleuth-zipkin-stream</artifactId>
	  	</dependency>
  </dependencies>





  <dependencyManagement>
  	<dependencies>
  		<dependency>
  			<groupId>org.springframework.cloud</groupId>
  			<artifactId>spring-cloud-dependencies</artifactId>
  			<!-- <version>Dalston.SR5</version>  -->
  			<version>Edgware.SR4</version>
  			<!-- <version>Finchley.SR1</version>  -->
  			<type>pom</type>
  			<scope>import</scope>
  		</dependency>
  	</dependencies>
  </dependencyManagement>


  <build>
  		<finalName>spring-cloud-08-zipkin-server-stream</finalName>
	  	<plugins>
	  		<plugin>
	  			<groupId>org.springframework.boot</groupId>
	  			<artifactId>spring-boot-maven-plugin</artifactId>
	  			<configuration>
	  				<mainClass>com.bfxy.springcloud.Application</mainClass>
	  			</configuration>
	  		</plugin>
	  	</plugins>
  </build>
</project>


配置:


spring.cloud.stream.kafka.binder.zkNodes=192.168.11.111:2181,192.168.11.112:2181,192.168.11.113:2181
spring.cloud.stream.kafka.binder.brokers=192.168.11.51:9092
zipkin.storage.type=mysql

spring.application.name=zipkin-server
server.port=9500

spring.datasource.url=jdbc:mysql://localhost:3306/zipkin?characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useUnicode=true
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.schema=classpath:/zipkin.sql
spring.datasource.initialize=true
spring.datasource.continue-on-error=true

spring.sleuth.enabled=false
spring.sleuth.sampler.percentage=1.0

spring.cloud.stream.kafka.binder.zkNodes=192.168.11.111:2181,192.168.11.112:2181,192.168.11.113:2181
spring.cloud.stream.kafka.binder.brokers=192.168.11.51:9092
zipkin.storage.type=mysql


      

##elasticsearch config  
#zipkin.storage.type=elasticsearch  
#zipkin.storage.elasticsearch.hosts=192.168.11.34:9200,192.168.11.35:9200,192.168.11.36:9200 
#zipkin.storage.elasticsearch.cluster=elasticsearch_zipkib  
#zipkin.storage.elasticsearch.index=zipkin  
#zipkin.storage.elasticsearch.index-shards=5  
#zipkin.storage.elasticsearch.index-replicas=3  

主入口:@EnableZipkinStreamServer

或者使用

@EnableKafkaStreams但是会提时缺少jar包
package com.bfxy.springcloud;

import java.util.concurrent.ThreadLocalRandom;

import org.apache.commons.lang3.RandomUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.sleuth.zipkin.stream.EnableZipkinStreamServer;
import org.springframework.kafka.annotation.EnableKafkaStreams;

import zipkin.server.EnableZipkinServer;
@EnableZipkinStreamServer
//@EnableKafkaStreams		//用这个注解会提示缺少kafka jar
@SpringBootApplication	//SpringBoot 核心配置
public class Application {
	
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
	
}

三个服务提供者也需要集成kafka:

服务提供者:

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

择业

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值