spring cloud zuul的工作原理

阅读数:98 评论数:0

跳转到新版页面

分类

python/Java

正文

ZuulProxyAutoConfiguration

首先我们看一下zuul的配置类ZuulProxyAutoConfiguration, 这个类有一项工作是初始化Zuul默认自带的Filter,其中有一个Filter很重要, 它就是RibbonRoutingFilter. 它主要是完成请求的路由转发,接下来我们看下它的run方法:

@Override
	public Object run() {
		RequestContext context = RequestContext.getCurrentContext();
		this.helper.addIgnoredHeaders();
		try {
			RibbonCommandContext commandContext = buildCommandContext(context);
			ClientHttpResponse response = forward(commandContext);
			setResponse(response);
			return response;
		}
		catch (ZuulException ex) {
			throw new ZuulRuntimeException(ex);
		}
		catch (Exception ex) {
			throw new ZuulRuntimeException(ex);
		}
	}

可以看到进行转发的方法是forward, 我们进一步看这个方法,具本内容如下:

protected ClientHttpResponse forward(RibbonCommandContext context) throws Exception {
		Map<String, Object> info = this.helper.debug(context.getMethod(),
				context.getUri(), context.getHeaders(), context.getParams(),
				context.getRequestEntity());
 
		RibbonCommand command = this.ribbonCommandFactory.create(context);
		try {
			ClientHttpResponse response = command.execute();
			this.helper.appendDebug(info, response.getRawStatusCode(), response.getHeaders());
			return response;
		}
		catch (HystrixRuntimeException ex) {
			return handleException(info, ex);
		}
 
	}

ribbonCommandFactory指的是在RibbonCommandFactoryConfiguration完成初始化的(触发RibbonCommandFactoryConfiguration的加载动化是利用ZuulProxyAutoConfiguration类上面的@Import标签),以HttpClientRibbonCommandFactory为例,我们来看一下它的create方法具本做了哪些事情:

@Override
	public HttpClientRibbonCommand create(final RibbonCommandContext context) {
        //当zuul调用失败后的降级方法
		FallbackProvider zuulFallbackProvider = getFallbackProvider(context.getServiceId());
		final String serviceId = context.getServiceId();
        //创建处理请求转发类,该类会利用Apache的Http client进行请求的转发
		final RibbonLoadBalancingHttpClient client = this.clientFactory.getClient(
				serviceId, RibbonLoadBalancingHttpClient.class);
		client.setLoadBalancer(this.clientFactory.getLoadBalancer(serviceId));
        
        //将降级方法、处理请求转发类、以及其他一些内容包装成HttpClientRibbon(这个类继承了HystrixCommand)
		return new HttpClientRibbonCommand(serviceId, client, context, zuulProperties, zuulFallbackProvider,
				clientFactory.getClientConfig(serviceId));
	}

接下来调用的是command.execute()方法,通过刚刚的分析我们知道了command其实指的是HttpClientRibbonCommand,同时我们也知道HttpClientRibbonCommand继承了HystrixCommand所以当执行command.execute()时,其实执行的是HttpClientRibbonCommand的run方法。查看源码我们并没有发现run方法,但是我们发现HttpClientRibbonCommand直接继承了AbstractRibbonCommand,所以其实执行的是AbstractRibbonCommand的run方法。

@Override
	protected ClientHttpResponse run() throws Exception {
		final RequestContext context = RequestContext.getCurrentContext();
 
		RQ request = createRequest();
		RS response;
		
		boolean retryableClient = this.client instanceof AbstractLoadBalancingClient
				&& ((AbstractLoadBalancingClient)this.client).isClientRetryable((ContextAwareRequest)request);
		
		if (retryableClient) {
			response = this.client.execute(request, config);
		} else {
			response = this.client.executeWithLoadBalancer(request, config);
		}
		context.set("ribbonResponse", response);
 
		// Explicitly close the HttpResponse if the Hystrix command timed out to
		// release the underlying HTTP connection held by the response.
		//
		if (this.isResponseTimedOut()) {
			if (response != null) {
				response.close();
			}
		}

在代码里查看后发现,isClientRetryable返回的一直是false,所以run方法里一般是调用executeWithLoadBalancer方法,通过上面的介绍我们知道client指的是RibbonLoadBalancingHttpClient,而RibbonLoadBalancingHttpClient里面并没有executeWithLoadBalancer方法(这里面会最终调用它的父类AbstractLoadBalancerAwareClient的executeWithLoadBalancer).

 

工作原理

在zuul中,整个请求的的过程是这样的,首先将请求给zuulservlet处理,zuulservlet中有一个zuulRunner对象,该对象中初始化了RequestContext:作为存储整个请求的一些数据,并所有的zuulfilter共享。zuulRunner中还有FIlterProcessor,FilterProcessor作为执行所有的zuulFilter的管理器,FilterProcessor从filterLoader中获取zuulFilter,有些这些filter之后,zuulServlet首先执行Pre类型的过滤器,再执行route类型的过滤器,最后执行的是post类型的过滤器,如果在执行这些过滤器有错误的时候则会执行error类型的过滤器,执行完这些过滤器,最终的请求的结果返回给客户端。

如果使用zuul,其中不可缺少的一个步骤就是在程序的启动类加上@EnableZuulProxy

@EnableCircuitBreaker
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ZuulProxyMarkerConfiguration.class)
public @interface EnableZuulProxy {
}

其中,引用了ZuulProxyMarkerConfiguration,该类注入了一个Marker bean,这个bean会触发ZuulProxyAutoConfiguration。

@Configuration
@Import({ RibbonCommandFactoryConfiguration.RestClientRibbonConfiguration.class,
		RibbonCommandFactoryConfiguration.OkHttpRibbonConfiguration.class,
		RibbonCommandFactoryConfiguration.HttpClientRibbonConfiguration.class,
		HttpClientConfiguration.class })
@ConditionalOnBean(ZuulProxyMarkerConfiguration.Marker.class)
public class ZuulProxyAutoConfiguration extends ZuulServerAutoConfiguration

在ZuulProxyAutoConfiguration中会注入一系列的filter。在它的父类ZuulServerAutoConfiguration,引入了一些相关的配置,在缺失zuulServlet bean的情况下注入了ZuulServlet,该类是zuul的核心类。同时也注入了其他的过滤器。

@Configuration
	protected static class ZuulFilterConfiguration {
 
		@Autowired
		private Map<String, ZuulFilter> filters;
 
		@Bean
		public ZuulFilterInitializer zuulFilterInitializer(
				CounterFactory counterFactory, TracerFactory tracerFactory) {
			FilterLoader filterLoader = FilterLoader.getInstance();
			FilterRegistry filterRegistry = FilterRegistry.instance();
			return new ZuulFilterInitializer(this.filters, counterFactory, tracerFactory, filterLoader, filterRegistry);
		}
 
	}

初始化ZuulFilterInitializer类,将所有filter向FilterRegistry注册。FilterRegistry管理了一个ConcurrentHashMap,用作存储过滤器,并有一些基本的CRUD方法。

Zuulservlet作用类似于Spring MVC中的DispatchServlet,起到了前端控制器的作用,所有的请求都由它接管。

public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        try {
            this.init((HttpServletRequest)servletRequest, (HttpServletResponse)servletResponse);
            RequestContext context = RequestContext.getCurrentContext();
            context.setZuulEngineRan();
 
            try {
                this.preRoute();
            } catch (ZuulException var13) {
                this.error(var13);
                this.postRoute();
                return;
            }
 
            try {
                this.route();
            } catch (ZuulException var12) {
                this.error(var12);
                this.postRoute();
                return;
            }
 
            try {
                this.postRoute();
            } catch (ZuulException var11) {
                this.error(var11);
            }
        } catch (Throwable var14) {
            this.error(new ZuulException(var14, 500, "UNHANDLED_EXCEPTION_" + var14.getClass().getName()));
        } finally {
            RequestContext.getCurrentContext().unset();
        }
    }

跟踪init(),可以发现这个方法为每个请求生成RequestContext, RequestContext继承了ConcurrentHashMap<String,Object>,在请求结束时销毁掉该RequestContext,RequestContext的生命周期为请求到zuulServlet开始处理,直到请求结束返回结果。RequestContext对象在处理请求的过程中,一直存在,所以这个对象为所有FIlter共享。

从ZuulServlet的service方法可知,它是先处理pre()类型的处理器,然后处理route()类型的处理器,最后再处理post类型的处理器。

首先来看一下pre()的处理过程,它会进入到ZuulRunner,该类的作用是将请求的HtppServletRequest,HttpSerletResponse放在RequestContext类中,并包装一个FitlerProcessor。而FilterProcessor调用Filters类,比如调用pre类型所有的过滤器,

 

zuul的两种隔离

1、信号量隔离

每次调用线程,当前请求通过计数信号量进行限制,当信号大于最大请求数时,进行限制,调用fallback接口快速返回。

最重要的是,信号量的调用是同步的,也就是说,每次调用都得阻塞调用方的线程,直到结果返回,这样就导致了无法访问做超时(只能依靠协议超时,无法主动释放)。

 

2、线程池隔离

每个隔离的粒度是线程滨,互相不干扰。当线程池达到maxSize时,调用fallback接口,进行熔断,同时支持超时设置。




相关推荐

Tomcat Tomcat的最大并发数是可以配置的,实际运用中,最大并发数与硬件性能有很大关系的。Tomcat默认的HTTP实现是采用阻塞式的Socket通信,每个请求都需要创

使用ab工具对spring cloud的zuul进行压力测试,我的网关只有验证token的逻辑,如果token不存在返回一个提示。但是测试时发现qps(这里也可以理解为tps)只有400左右。但

Eureka Server在运行期间会去统计心跳失败比例在15分钟之内是否低于85%,如果低于85

mvn依赖 &lt;dependency&gt; &lt;groupId

什么是jwt (json web token)jwt是一生中用来在网络上声明某种身份的令牌(TOKEN),它的特点是紧凑且自包含并且基于JSON,通过一些常用的算法对包含的主体

Hystrix Dashboard是作为断路器状态的一个组件,提供了数据监控和友好的图表化界面。 修改service-hi 1、在pom工程文件引入相应的依赖</

简介 Spring cloud Sleuth主要功能就是在分布式系统中提供追踪解决方案,并且兼容支持zipkin,你只需要在pom文件中引入相应的依赖即可。 1、

简介 在spring cloud中,有分布式配置中心组件spring cloud config,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程git仓库中,在该组

spring cloud微服务系统中,一种常见的负载均衡方式是,客户端的请求首先经过负载均衡(zuul、ngnix),再到达服务网关(zuul集群),然后再到具体的服务。服务统一注册到高可用的服

一、JAVA项目中网络接口调用工具 1、HttpClient 它是Apache Jakarta Common下的子项目,用来提供高效、最新的、功能丰富的支持Http协议的客户端编程工具包。 HttpC