MDC + 微服务请求链路追踪spring cloud sleuth

MDC + 微服务请求链路追踪spring cloud sleuth

MDC

  • mdc相信很多人都已经知道是什么东西了,我们在可以在mdc中put某些属性,比如在请求开始时生成一个唯一的requestId,登陆的用户id,登陆的设备类型等等,然后在日志文件中取出打印,来帮助我们排查问题等
		//可以在filter或者intercepter中putmdc数据,也可以通过aop拦截在防治法执行前处理mdc数据
		MDC.put("APPTYPE","apptype");
		MDC.put("DEVICE_ID","DEVICEID");
	    //每次请求生成唯一的请求码,便于日志查询和分析
	    String requestId = System.currentTimeMillis() + "_" + 					RandomUtils.nextInt(1000);
	    MDC.put("REQUEST_ID",requestId);//请求唯一id,
  • logback.xml 文件配置,通过配置pattern,就可以取出对应的属性值,打印

    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}[%X{REQUEST_ID}][%X{USER_ID}][%thread]%-5level - %logger - %msg%npattern>
    

spring cloud sleuth

上面的场景只适合在单应用的场景中,现在基本上都是微服务调用,服务和服务之间通过rpc调用,那么我们的mdc怎么跨应用传递呢

  • 第一种办法,也是我们以前项目中用到的,在我们A服务代用B服务时,我们的请求参数统一继承自一个基类baseRequestObject。在这个基类中定义mdc中的属性,在服务A调用服务B时从mdc中取出对应的属性,初始化到基类baseRequestObject中,

    在服务B中,通过aop拦截请求参数baseRequestObject,取出对应的属性在放入mdc中,这样我们在服务B中就可以获取到相同的mdc属性值了

    优点 :可以定制化,我们想在mdc中放什么就放什么,可以在非 spring cloud 项目中使用

    缺点 : 过去复杂了,如果我们的服务请求链路很长,每个服务中都要去aop拦截

  • 第二种办法就是spring cloud 支持的 spring cloud sleuth

    • 引入依赖
       <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-sleuthartifactId>
            dependency>
    
    • logback.xml日志文件配置

      <Property name="pattern">%d [%thread] [%X{springAppName}][%X{X-B3-TraceId}] [%X{X-B3-SpanId}] [%X{X-B3-ParentSpanId}] [%X{X-Span-Export}] %-5level %logger{36} %line - %msg%n%exProperty>
      

      springAppName :应用名

      X-B3-TraceId : 每次请求的唯一ID

      X-B3-SpanId: 发生的特定操作的ID,可以看做是应用级别的

      X-Span-Export 是否是发送给Zipkin这个就是一个可视化的请求链路追踪的应用吧,没怎么用过,后面在研究

      2019-06-11 10:19:16.210  INFO [server-b,3db11968703f528a,40fcc734c73c12a1,false] 12352 --- [nio-8082-exec-3] com.example.serverb.ServiceBController   : start service b
      2019-06-11 10:19:16.210  INFO [server-b,3db11968703f528a,40fcc734c73c12a1,false] 12352 --- [nio-8082-exec-3] com.example.serverb.ServiceBController   : end service b
      2019-06-11 10:19:16.210  INFO [server-b,3db11968703f528a,40fcc734c73c12a1,false] 12352 --- [nio-8082-exec-3] com.example.serverb.UserService          : ---prirnt
      2019-06-11 10:19:16.238  INFO [server,3db11968703f528a,b1044aac91569268,false] 516 --- [nio-8081-exec-1] com.example.server.HelloController       : server end
      2019-06-11 10:19:16.261  INFO [client,3db11968703f528a,3db11968703f528a,false] 3292 --- [nio-8080-exec-1] com.example.client.HelloController       : end client
      
      

      3db11968703f528a 就是我们的请求的唯一ID,如果我们整合了ELK日志系统的话,通过这个id去查询日志非常方便定位问题

MDC + 微服务请求链路追踪spring cloud sleuth_第1张图片
这个就是mdc里面存放的东西,

原理其实很简单,spring cloud sleuth 把这些属性放在了请求头中,传递到下一个服务应用当中

MDC + 微服务请求链路追踪spring cloud sleuth_第2张图片
TracingFeignClient 具体的处理逻辑在这个类中

static final Propagation.Setter<Map<String, Collection<String>>, String> SETTER = new Propagation.Setter<Map<String, Collection<String>>, String>() {
		@Override
		public void put(Map<String, Collection<String>> carrier, String key,
				String value) {
			if (!carrier.containsKey(key)) {
				carrier.put(key, Collections.singletonList(value));
				if (log.isTraceEnabled()) {
					log.trace("Added key [" + key + "] and header value [" + value + "]");
				}
			}
			else {
				if (log.isTraceEnabled()) {
					log.trace("Key [" + key + "] already there in the headers");
				}
			}
		}

		@Override
		public String toString() {
			return "Map::set";
		}
	};

优点:简单方便,快速集成,推荐

整合 zipkin未完待续…

你可能感兴趣的:(spring,spring-boot)