spring cloud sleuth and zipkin进行分布式跟踪

spring cloud sleuth

  1. 用于生成关联ID(与具体的请求有关)并装备到HTTP调用上,并将生成数据提供给OpenZipkin的钩子;
  2. 关联ID:随机生产、唯一的数字或字符串,在事务启用时分配给事务,当事务流经多个服务时,关联ID会从一个服务传递到另一个服务;
  3. spring cloud sleuth的每个日志条目:应用程序名称(默认为spring.application.name),关联ID,跨度ID(表示整个事务中某一部分的唯一ID,参与事务的每个服务都有自己的跨度ID),是否将数据发送到Zipkin;
  4. 依赖包:
           <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-sleuth</artifactId>
            </dependency>
    
  5. 使用Zuul将关联ID添加到HTTP响应:

    1. 将spring cloud sleuth依赖导入Zuul项目中;

    2. 通过添加zuul后置过滤器,将关联ID添加到HTTP响应中;

      package com.thoughtmechanix.zuulsvr.filters;
      
      
      import com.netflix.zuul.ZuulFilter;
      import com.netflix.zuul.context.RequestContext;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.cloud.sleuth.Tracer;
      import org.springframework.stereotype.Component;
      
      @Component
      public class ResponseFilter extends ZuulFilter{
          private static final int  FILTER_ORDER=1;
          private static final boolean  SHOULD_FILTER=true;
          private static final Logger logger = LoggerFactory.getLogger(ResponseFilter.class);
      
      
          @Autowired
          Tracer tracer;
      
          @Override
          public String filterType() {
              return "post";
          }
      
          @Override
          public int filterOrder() {
              return FILTER_ORDER;
          }
      
          @Override
          public boolean shouldFilter() {
              return SHOULD_FILTER;
          }
      
          @Override
          public Object run() {
              RequestContext ctx = RequestContext.getCurrentContext();
              ctx.getResponse().addHeader("tmx-correlation-id", tracer.getCurrentSpan().traceIdString());
      
              return null;
          }
      }
      
    3. 导入依赖包后,自动装配的Tracker类可用于访问正在执行的当前spring cloud sleuth跟踪信息,然后将其添加到zuul发出的HTTP响应中。

    4. zuul网关不会盲目的转发HTTP调用,它接收传入的HTTP请求并终止这个调用,然后构建一个信息的到目标服务的调用,同是会去掉一些敏感信息,如cookie、token等。

  6. 使用OpenZipkin进行分布式跟踪:

    1. Zipkin是一个分布式跟踪平台,可用于跟踪跨多个服务调用的事务,Zipkin提供了可视化UI用于查看事务占用的时间量,以及每个微服务所用的时间。

    2. 建立spring cloud sleuth和Zipkin涉及的四个操作:

      1. 将spring cloud sleuth和Zipkin依赖添加到捕获跟踪数据的服务中;

      2. 在每个服务中配置spring属性以指向收集跟踪数据的Zipkin服务器;

      3. 安装配置Zipkin服务器;

      4. 定义每个客户端所使用的采样策略,以便向Zipkin服务器发送数据。

    3. 在将跟踪数据发送到Zipkin服务器的每个服务中添加spring cloud 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>
    4. 配置服务以指向zipkin(也可以通过rabbitMq和kafka将数据发送到Zipkin服务器),并定义每个服务向Zipkin服务器发送信息的频率:

      spring:
        zipkin:
          baseUrl:  localhost:9411 #Zipkin服务地址
        sleuth:
          sampler:
            percentage: 0.5 #值在0-1之间,默认为0.1
    5. 安装和配置Zipkin服务器:

      1. 导入依赖包;

         <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-autoconfigure-ui</artifactId>
         </dependency>
         <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-server</artifactId>
         </dependency>
      2. 开启注解,如果需要通过消息代理(rabbitMq或kafka)来接收数据,则使用sping cloud团队提供的@EnableZipkinStreamServer,此时跟踪并向Zipkin服务器发送消息的服务需要将消息发送到消息代理,同时zipkin服务器也需要配置监听的消息代理,否则使用@EnableZipkinServer注解;

      3. Zipkin服务器可以将接收到的数据存储到内存、mysql、或者Elasticsearch等;

      4. spring cloud sleuth和Zipkin允许添加自定义跨度,以便跟踪与第三方调用相关的执行时间;

        package com.thoughtmechanix.licenses.clients;
        
        import com.thoughtmechanix.licenses.model.Organization;
        import com.thoughtmechanix.licenses.repository.OrganizationRedisRepository;
        
        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;
        import org.springframework.beans.factory.annotation.Autowired;
        
        import org.springframework.cloud.sleuth.Span;
        import org.springframework.cloud.sleuth.Tracer;
        import org.springframework.data.redis.core.RedisTemplate;
        import org.springframework.http.HttpMethod;
        import org.springframework.http.ResponseEntity;
        import org.springframework.stereotype.Component;
        import org.springframework.web.client.RestTemplate;
        
        @Component
        public class OrganizationRestTemplateClient {
            @Autowired
            RedisTemplate<String, Organization> redisTemplate;
        
            @Autowired
            private RestTemplate restTemplate;
        
            @Autowired
            Tracer tracer;
        
            @Autowired
            OrganizationRedisRepository orgRedisRepo;
        
            private Organization checkRedisCache(String organizationId) {
                Span newSpan = tracer.createSpan("readLicensingDataFromRedis");
                try {
                    return (Organization) redisTemplate.opsForHash().get("organization", organizationId);
                } catch (Exception ex) {
                    return null;
                } finally { //使用finally块关闭跨度
                    //可以将标签信息添加到跨度中,此处提供了将要被捕获的服务的名称,表示我们要捕获访问redis的执行时间
                    newSpan.tag("peer.service", "redis");
                    //记录一个时间,告诉spring cloud sleuth它应该完成的时间
                    newSpan.logEvent(org.springframework.cloud.sleuth.Span.CLIENT_RECV);
                    //关闭跟踪,否则在日志中会得到错误消息,指示跨度已经被打开却尚未关闭
                    tracer.close(newSpan);
                }
            }
        
            private void cacheOrganizationObject(Organization org) {
                try {
                    orgRedisRepo.saveOrganization(org);
                } catch (Exception ex) {
                }
            }
        
            public Organization getOrganization(String organizationId) {
        
                Organization org = checkRedisCache(organizationId);
                if (org != null) {
                    return org;
                }
                ResponseEntity<Organization> restExchange =
                        restTemplate.exchange(
                                "http://zuulservice/api/organization/v1/organizations/{organizationId}",
                                HttpMethod.GET,
                                null, Organization.class, organizationId);
        
                /*Save the record from cache*/
                org = restExchange.getBody();
        
                if (org != null) {
                    cacheOrganizationObject(org);
                }
        
                return org;
            }
        }
        
      5. 查看可视化界面,地址:http://ip:port

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值