Zipkin系列总结

场景

最近在做zipkin链路追踪,遇到了一系列的问题,特此总结一下

需求

遇到的主要问题

1.zipkin设置自定义参数,怎么设置定义参数?

2.设置的自定义参数在链路上传递问题(就是在有的服务中获取不到自定义的参数值)

3.http请求进行包装

 

分布式系统中两种使用情况

一种是springMvc中使用

一种是springCloud中使用

两种方式共同的思想都是通过过滤器,拦截到请求,然后在拦截的请求中处理请求头(http请求进行包装包装)中添加自定义参数

springCloud中使用

第一步:在每个服务中添加zipkin依赖

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

第二步:配置让其生效

spring.sleuth.enabled=true
spring.zipkin.base-url=http://192.168.100.88:9411
spring.sleuth.sampler.percentage=1.0

如果不需要做额外处理上面两步就可以,烦就烦在实际中要和业务结合。

如果要将业务和链路结合则须要进行一下处理

第三步:通过过滤器,在请求头上添加自定义参数。

设置拦截过滤器 ------------》然后将过滤器注册

package com.gisquest.gateway.filter;
import java.io.IOException;
import java.util.UUID;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.springframework.cloud.sleuth.Tracer;
import org.springframework.web.filter.GenericFilterBean;

import com.gisquest.gateway.utils.ZipkinFilterWrapper;


public class GisqZipKinFilter extends  GenericFilterBean  {

	private Tracer tracer;
	
	public GisqZipKinFilter(Tracer tracer){
		this.tracer = tracer;
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
			throws IOException, ServletException {
		HttpServletRequest  httpRequest = (HttpServletRequest) request;
		ZipkinFilterWrapper zipkinFilterWrapper = new ZipkinFilterWrapper(httpRequest);
		String uuid = httpRequest.getHeader("gisq-platform-id");
		if (uuid == null) {
			uuid = UUID.randomUUID().toString();
			zipkinFilterWrapper.putHeader("gisq-platform-id", uuid);
			tracer.addTag("gisq-platform-id", uuid);
			filterChain.doFilter(zipkinFilterWrapper, response);
		} else {
			tracer.addTag("gisq-platform-id", uuid);
			filterChain.doFilter(request, response);
		}
	}
}

http请求进行封装

package com.gisquest.gateway.utils;

import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class ZipkinFilterWrapper extends HttpServletRequestWrapper {

	private final Map<String, String> customHeaders;

	public ZipkinFilterWrapper(HttpServletRequest request) {
		super(request);
		this.customHeaders = new HashMap<>(10);
	}

	public void putHeader(String name, String value) {
		this.customHeaders.put(name, value);
	}
//
	@Override
	public Enumeration<String> getHeaderNames() {
		Set<String> set = new HashSet<>(customHeaders.keySet());
		Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaderNames();
		while (e.hasMoreElements()) {
			String n = e.nextElement();
			set.add(n);
		}
		return Collections.enumeration(set);
	}

	@Override
	public String   getHeader(String name){
	    String headerValue = customHeaders.get(name);
	    if (headerValue !=null){
	          return headerValue;
	      }
	    return ((HttpServletRequest) getRequest()).getHeader(name);
	}
}

需要注意的问题:

1.不同版本Tracer获取问题(两种情况都让我给遇到了,真是服了!!!)

在2.0一下版本中是没有Brave的,是通过sleuth获取的tracer

import org.springframework.cloud.sleuth.Tracer
在span中添加参数
tracer.addTag("gisq-platform-id", uuid);
在2.0及以上版本中是通过Brave获取到的Tracer
import brave.Tracer;

在span中添加参数 

   tracer.currentSpan().tag("gisq-platform-id", uuid);

 2.Tracer有时null,导致系统启动不来问题

如果在过滤器中直接注入可能Tracer使用时报异常(tracer.addTag()方法报异常),导致系统起不来了(就是如下情况,过滤器中也没有添加@Component注解)

解决方法,就是通过在过滤器注册时,将tracer对象注入进入就可以。可能是原因是注入对象(Tracer对象在容器中生成的时机有关)

   private GisqZipKinFilter gisqZipKinFilter() {
        return new GisqZipKinFilter(tracer);
    }
    

 

实例流程说明

(以登录流程进行链路追踪说明):

在分布式系统中分登陆前和登陆后两种说法:

在登陆前,首先前端客户端发送登陆请求,直接先经过网关服务(转发auth/auth/oauth/login请求),再经过认证服务生成token,最后到具体的业务服务。

package com.gisquest.gateway.filter;

import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.stereotype.Component;

import com.gisquest.gateway.utils.ZipkinFilterWrapper;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;

@Component
public class CustomTokenFilter extends ZuulFilter {

	@Autowired
	Tracer tracer;
	
    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        if (request.getRequestURL().toString().contains("getUserByNameJoinDeptByPost")||request.getRequestURL().toString().contains("getPlatformDesignerOrExplorerUserOnlyById")){
            return false;
        }
        return true;
    }

    @Override
    public Object run() throws ZuulException {
    	RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest httpRequest = ctx.getRequest();
		ZipkinFilterWrapper zipkinFilterWrapper = new ZipkinFilterWrapper(httpRequest);
		String uuid = httpRequest.getHeader("gisq-platform-id");
		if (uuid == null) {
			uuid = UUID.randomUUID().toString();
			tracer.addTag("gisq-platform-id", uuid);
		} else {
			tracer.addTag("gisq-platform-id", uuid);
		}
		ctx.addZuulRequestHeader("gisq-platform-id", uuid);
    	return null;
    }

}

网关我是这样处理的

 @Override
    public Object run() throws ZuulException {
    	RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest httpRequest = ctx.getRequest();
		ZipkinFilterWrapper zipkinFilterWrapper = new ZipkinFilterWrapper(httpRequest);
		String uuid = httpRequest.getHeader("gisq-platform-id");
		if (uuid == null) {
			uuid = UUID.randomUUID().toString();
			tracer.addTag("gisq-platform-id", uuid);
		} else {
			tracer.addTag("gisq-platform-id", uuid);
		}
		ctx.addZuulRequestHeader("gisq-platform-id", uuid);
    	return null;
    }

注意点:1.这里网关过滤器不是通过注册生效的,而是直接添加@Component注解让其生效的,同时Tracer通过@Autowired注入依赖的。

               2. ctx.addZuulRequestHeader("gisq-platform-id", uuid),在网关过滤器请求头添加自定义参数 。

 

登陆系统后,再次请求接口时候,此时会先通过一个网关认证过滤器判断token是否失效,如果生效则进入网关过滤器,然后进行路由转发,如果不生效就直接让其登陆。

 

代码写三个的过滤器分别用在、网关服务、     认证服务、业务服务 (Aop处理处理)这样同一个链路上,会生成一个相同值得业务id

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值