文档章节

服务网关之Zuul

代码搬运工---
 代码搬运工---
发布于 2017/04/07 13:40
字数 1584
阅读 2825
收藏 5
点赞 0
评论 0

•Zuul可以通过加载动态过滤机制,从而实现以下各项功能:

•验证与安全保障: 识别面向各类资源的验证要求并拒绝那些与要求不符的请求。

•审查与监控: 在边缘位置追踪有意义数据及统计结果,从而为我们带来准确的生产状态结论。

•动态路由: 以动态方式根据需要将请求路由至不同后端集群处。

•压力测试: 逐渐增加指向集群的负载流量,从而计算性能水平。

•负载分配: 为每一种负载类型分配对应容量,并弃用超出限定值的请求。

•静态响应处理: 在边缘位置直接建立部分响应,从而避免其流入内部集群。

•多区域弹性: 跨越AWS区域进行请求路由,旨在实现ELB使用多样化并保证边缘位置与使用者尽可能接近。

配置如下

zuul.ignored-services=*

zuul.routes.api-service.path=/api/**
zuul.routes.api-service.serviceId=api

zuul.sensitiveHeaders=Authorization

zuul.semaphore.max-semaphores=1000
zuul.host.maxTotalConnections=1000
zuul.host.maxPerRouteConnections=500
zuul.SendResponseFilter.post.disable=false
zuul.SendErrorFilter.post.disable=true
#默认1000
zuul.host.socket-timeout-millis=3000
#默认2000
zuul.host.connect-timeout-millis=10000
zuul.SendResponseFilter.post.disable=false
zuul.SendErrorFilter.post.disable=true

 

Zuul 是ZuulFilter链来实现的,分别有pre,routing,post,error ZuulFilter,具体类在

这里主要看下RibbonRoutingFilter实现

@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) {
			context.set(ERROR_STATUS_CODE, ex.nStatusCode);
			context.set("error.message", ex.errorCause);
			context.set("error.exception", ex);
		}
		catch (Exception ex) {
			context.set("error.status_code",
					HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
			context.set("error.exception", ex);
		}
		return null;
	}

这里会看到有个RequestContext context = RequestContext.getCurrentContext(); 该context来源于pre阶段的初始,例如Servlet30WrapperFilter

@Override
	public Object run() {
		RequestContext ctx = RequestContext.getCurrentContext();
		HttpServletRequest request = ctx.getRequest();
		if (request instanceof HttpServletRequestWrapper) {
			request = (HttpServletRequest) ReflectionUtils.getField(this.requestField,
					request);
			ctx.setRequest(new Servlet30RequestWrapper(request));
		}
		else if (RequestUtils.isDispatcherServletRequest()) {
			// If it's going through the dispatcher we need to buffer the body
			ctx.setRequest(new Servlet30RequestWrapper(request));
		}
		return null;
	}

,下面看下RibbonCommandContext 这里封装了个ribbo的context 说明zuul默认是有集成ribbo,,下面继续看forward(。。。)方法,

RibbonCommand command = this.ribbonCommandFactory.create(context);
		try {
			ClientHttpResponse response = command.execute();
			this.helper.appendDebug(info, response.getStatusCode().value(),
					response.getHeaders());
			return response;
		}
		catch (HystrixRuntimeException ex) {
			return handleException(info, ex);
		}

第一步创建RibboCommand  他继承了HystrixExecutable 说明Zuul也集成了Hystrix,可以看到Zuul最后也是通过HttpCient 或者OkHttp RestClient 发起转发请求,

默认Zuul是使用HttpClient ,那我们来看下HttpClientRibboCommandFactory怎么创建HystrixCommand的

@Override
	public HttpClientRibbonCommand create(final RibbonCommandContext context) {
		ZuulFallbackProvider zuulFallbackProvider = getFallbackProvider(context.getServiceId());
		final String serviceId = context.getServiceId();
		final RibbonLoadBalancingHttpClient client = this.clientFactory.getClient(
				serviceId, RibbonLoadBalancingHttpClient.class);
		client.setLoadBalancer(this.clientFactory.getLoadBalancer(serviceId));

		return new HttpClientRibbonCommand(serviceId, client, context, zuulProperties, zuulFallbackProvider);
	}

Hystrix 是不是支持fallback,既然Zuul集成了Hystrix 是否也可以实现FallBack,那我们看下下面这段代码

ZuulFallbackProvider zuulFallbackProvider = getFallbackProvider(context.getServiceId());

 这里的ZuulFallbackProvider 看似应该跟fallback有关系,那我们证实下在RibboCommand里有断代码

	@Override
	protected ClientHttpResponse getFallback() {
		if(zuulFallbackProvider != null) {
			return zuulFallbackProvider.fallbackResponse();
		}
		return super.getFallback();
	}

这是实现HystrixCommand的getFallback由此可以断定zuulFallbackProvider.fallbackResponse();提供了fallback方法,那就简单了 我们只需要创建个ZuulFallbackProvider就能实现Zuul端fallback;

我们再看下ZuulFallbackProvider 具体代码

并没有找到它的实现类那我们需要创建个fallbackprovider 里面有两个方法,一个是获取路由名称,一个是获取ClientHttpRreponse;那这两个方法有什么用,从AbstractRibbonCommandFactory可以看到
fallbackProviderCache.put(provider.getRoute(), provider);通过service为Key缓存在
fallbackProviderCache中,官方说通过*可以通用一个provider目前并未发现有这样的代码,具体例子

	@Bean
	public ZuulFallbackProvider buildFallbackProvider(){
		return new ZuulFallbackProvider() {
			
			@Override
			public String getRoute() {
				// TODO Auto-generated method stub
				return null;
			}
			
			@Override
			public ClientHttpResponse fallbackResponse() {
				// TODO Auto-generated method stub
				return null;
			}
		};
	}

Ok 进入下一步return new HttpClientRibbonCommand(serviceId, client, context, zuulProperties, zuulFallbackProvider); 干嘛的不用说了吧 ,看下参数Client RibbonLoadBalancingHttpClient 实现LB,Ribbo 与Hystrix 不再细说,后面章节会重点叙述;

ClientHttpResponse response = command.execute(); 这就是通过熔断器,然后LB实现请求service响应结果;并将结果保存RequestContext中, 到目前为止RibbonRoutingFilter已经处理完

接下来看下一个的ZuulFilter SendResponseFilter 字面就可以看出来就是发送结果,题外话为什么说说这个类重要 因为在这个类 我们可以做很多事。比如 在此处做统一响应处理,异常处理等,

我们来梳理下流程

首先pre阶段初始化请求数据,如头部,参数,url 映射,route 转发service ,post  响应结果至用户;

流程很简单也很清晰

转述下优化策略 ttp://www.tuicool.com/articles/aMRnIfr

 

zuul 内置参数

zuul.host.maxTotalConnections

适用于ApacheHttpClient,如果是okhttp无效。每个服务的http客户端连接池最大连接,默认是200.

zuul.host.maxPerRouteConnections

适用于ApacheHttpClient,如果是okhttp无效。每个route可用的最大连接数,默认值是20。

zuul.semaphore.max-semaphores

Hystrix最大的并发请求 execution.isolation.semaphore.maxConcurrentRequests ,这个值并非TPS 、 QPS 、 RPS 等都是相对值,指的是1秒时间窗口内的事务/查询/请求, semaphore.maxConcurrentRequests 是一个绝对值,无时间窗口,相当于亚毫秒级的。当请求达到或超过该设置值后,其其余就会被拒绝。默认值是100。参考: Hystrix semaphore和thread隔离策略的区别及配置参考

这个参数本来直接可以通过Hystrix的命名规则来设置,但被zuul重新设计了,使得在zuul中semaphores的最大并发请求有4个方法的参数可以设置,如果4个参数都存在优先级(1~4)由高到低:

  • [优先级1]zuul.eureka.api.semaphore.maxSemaphores
  • [优先级2]zuul.semaphore.max-semaphores
  • [优先级3]hystrix.command.api.execution.isolation.semaphore.maxConcurrentRequests
  • [优先级4]hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests

需要注意的是:在Camden.SR3版本的zuul中 hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests 设置不会起作用,这是因为在 org.springframework.cloud.netflix.zuul.filters.ZuulProperties.HystrixSemaphore.maxSemaphores=100 设置了默认值100,因此 zuul.semaphore.max-semaphores 的优先级高于 hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests 。

zuul.eureka.[commandKey].semaphore.maxSemaphores:

其中commandKey为

参考设置参数:

#
zuul.host.maxTotalConnections: 200
zuul.host.maxPerRouteConnections: 10
#zuul.semaphore.max-semaphores: 128
# 建议使用这种方式来设置,可以给每个不同的后端微服务设置不同的信号量
zuul.eureka.[service id].semaphore.maxSemaphores: 128

其他Hystrix参数:

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds 用来设置thread和semaphore两种隔离策略的超时时间,默认值是1000。

  • 建议设置这个参数,在Hystrix 1.4.0之前,semaphore-isolated隔离策略是不能超时的,从1.4.0开始semaphore-isolated也支持超时时间了。
  • 建议通过CommandKey设置不同微服务的超时时间,对于zuul而言,CommandKey就是service id: hystrix.command.[CommandKey].execution.isolation.thread.timeoutInMilliseconds

ribbon参数

ribbon:
#  # Max number of next servers to retry (excluding the first server)
#  MaxAutoRetries: 1
#  # Whether all operations can be retried for this client
#  MaxAutoRetriesNextServer: 1
#  # Interval to refresh the server list from the source
#  OkToRetryOnAllOperations: true
#  # Interval to refresh the server list from the source
#  ServerListRefreshInterval: 2000
#  # Connect timeout used by Apache HttpClient
  ConnectTimeout: 3000
#  # Read timeout used by Apache HttpClient
  ReadTimeout: 3000

主要是 ConnectTimeout 和 ReadTimeout 2个参数,最终会设置到http Client中

 

 

 

 

 


 

© 著作权归作者所有

共有 人打赏支持
代码搬运工---
粉丝 8
博文 7
码字总数 7389
作品 0
杭州
程序员
阿里云Kubernetes SpringCloud 实践进行时(3): API网关服务Zuul

简介 为了更好地支撑日益增长的庞大业务量,我们常常需要把服务进行整合、拆分,使我们的服务不仅能通过集群部署抵挡流量的冲击,又能根据业务在其上进行灵活的扩展。随着分布式的普及、服务...

osswangxining ⋅ 05/25 ⋅ 0

SpringCloud(九):API网关服务Zuul

SpringCloud(九):API网关服务Zuul Harries Blog™2017-12-111 阅读 clientSpringAppcatAPIbuildapache [TOCM] [TOC] 源码 地址: https :// git hub.com/IsResultXaL/ spring cloud 通过上一......

Harries Blog™ ⋅ 2017/12/11 ⋅ 0

springCloud(13):使用Zuul构建微服务网关-简介

一、为什么要使用微服务网关 不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求。如:一个电影购票的手机APP,可能会调用多个微服务,才能完...

我爱大金子 ⋅ 2017/08/22 ⋅ 0

上传文件,经过Zuul,中文文件名乱码解决办法

转载请标明出处: http://blog.csdn.net/forezp/article/details/77170470 本文出自方志朋的博客 问题描述 在项目中又一个上传文件的oss服务,直接调用服务的上传文件成功,如果经过网关zuu...

forezp ⋅ 2017/08/14 ⋅ 0

sbc(六) Zuul GateWay 网关应用

前言 看过之前SBC系列的小伙伴应该都可以搭建一个高可用、分布式的微服务了。 目前的结构图应该如下所示: 各个微服务之间都不存在单点,并且都注册于 ,基于此进行服务的注册于发现,再通过 ...

crossoverJie ⋅ 2017/11/28 ⋅ 0

微服务网关netflix-zuul

引言:前面一个系列文章介绍了认证鉴权与API权限控制在微服务架构中的设计与实现 ,好多同学询问有没有完整的demo项目,笔者回答肯定有的。由于之前系列文章侧重讲解了权限前置,所以近期补上...

aoho ⋅ 2017/11/14 ⋅ 0

sbc(六) Zuul GateWay 网关应用

image 前言 看过之前SBC系列的小伙伴应该都可以搭建一个高可用、分布式的微服务了。 目前的结构图应该如下所示: image 各个微服务之间都不存在单点,并且都注册于 ,基于此进行服务的注册于发...

crossoverJie ⋅ 2017/11/28 ⋅ 0

Spring Cloud(四) Spring Cloud Security集成CAS (单点登录)对微服务认证

一、前言 由于leader要求在搭好的spring cloud 框架中加入对微服务的认证包括单点登录认证,来确保系统的安全,所以研究了Spring Cloud Security这个组件。在前面搭好的demo中,如何确保微服...

上善若水 ⋅ 2017/09/10 ⋅ 0

Spring Cloud 服务第一次请求超时的优化

1. 问题背景 使用Spring Cloud组件构建的服务集群,在第一次请求时经常会出现timeout的情况,然而第二次就正常了。Spring Cloud版本为Dalston.SR4。 启动涉及到的相关服务: gateway(zuul网关...

aoho ⋅ 2017/11/19 ⋅ 0

Spring Cloud构建微服务架构:服务网关(过滤器)【Dalston版】

在前两篇文章:服务网关(基础)、服务网关(路由配置)中,我们了解了Spring Cloud Zuul作为网关所具备的最基本功能:路由。本文我们将具体介绍一下Spring Cloud Zuul的另一项核心功能:过滤...

程序猿DD ⋅ 2017/09/25 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

构建自定义组件

#前言 接上篇,因项目需由H5转到小程序,故需打造自定义对话框。而这块需使用到微信小程序的自定义组件功能。 小程序自定义组件 点击此处,可以查看小程序自定义组件的api。 从自定义组件的样...

387 ⋅ 13分钟前 ⋅ 0

Maven 项目添加本地jar包的三种方式

Maven 项目添加本地jar包的三种方式 翻译自3 ways to add local jar to maven project [TOC] 简介 在构建 Maven 项目时,有时候需要导入本地的jar包,本文介绍了三种添加本地jar包的方法。 ...

Os_yxguang ⋅ 13分钟前 ⋅ 0

long超过16位之后浏览器自动截断问题处理。

java前后端交互的过程中,定义的Long字段超过16位之后,js发生截断,从而不能跟后台数据进行匹配。 处理方法 把long型字段转成string进行处理。(可以使用json注解转换或者springmvc统一拦截...

strict_nerd ⋅ 15分钟前 ⋅ 0

一文带你搞定Integer

1.1 前言 Integer是int对应的包装类,它包含一个int类型的字段存储数据,并提供了多个基本操作,能在 int 类型和 String 类型之间互相转换。在Java5中,引入了自动装箱和自动拆箱功能,Java可...

筱虾米 ⋅ 16分钟前 ⋅ 0

Linux kernel脉络和主干总结

写在前面 前人常说,对Linux操作系统/内核的理解,是计算机行业从业者的内功,决定了你在技术领域想走多远。但内核的庞大以及学习曲线之陡峭,总让我在学习途中觉得犹如“管中窥豹”。 随着工...

Markz0928 ⋅ 31分钟前 ⋅ 0

在gcc中使用intel风格的内联汇编

很简单,内联汇编使用asm(“.intel_syntax noprefix/n”)声明一下,以后的内联汇编就可以用intel风格了,构建可执行文件时给gcc加上-masm=intel参数。 先写一个小程序测试一下: [cpp] view...

simpower ⋅ 41分钟前 ⋅ 0

NIO 之 ByteBuffer实现原理

相关文章 BIO、NIO、AIO 内部原理分析 NIO 之 Selector实现原理 NIO 之 Channel实现原理 前言 Java NIO 主要由下面3部分组成: Buffer Channel Selector 在传统IO中,流是基于字节的方式进行...

轨迹_ ⋅ 50分钟前 ⋅ 0

Jenkins docker权限问题

环境Ubuntu Server 工具 jenkins-war:2.89.2 报错信息 Cannot connect to the Docker daemon. Is the docker daemon running on this host?Build step 'Execute shell' marked build as fai......

Pulsar-V ⋅ 51分钟前 ⋅ 0

180621-一个简单的时间窗口设计与实现

如何设计一个计数的时间窗口 时间窗口,通常对于一些实时信息展示中用得比较多,比如维持一个五分钟的交易明细时间窗口,就需要记录当前时间,到五分钟之前的所有交易明细,而五分钟之前的数...

小灰灰Blog ⋅ 今天 ⋅ 0

Android之Dalvik、ART、JIT、AOT

Android之Dalvik、ART、JIT、AOT 本文内容:Dalvik、ART、JIT、AOT之间关系 本文定位:知识记录 学习过程记录,加深理解,提升文字组合表达能力。也希望能给学习的同学一些灵感 本文整理于[...

lichuangnk ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部