•Zuul能够经过加载动态过滤机制,从而实现如下各项功能:spring
•验证与安全保障: 识别面向各种资源的验证要求并拒绝那些与要求不符的请求。后端
•审查与监控: 在边缘位置追踪有意义数据及统计结果,从而为咱们带来准确的生产状态结论。api
•动态路由: 以动态方式根据须要将请求路由至不一样后端集群处。缓存
•压力测试: 逐渐增长指向集群的负载流量,从而计算性能水平。安全
•负载分配: 为每一种负载类型分配对应容量,并弃用超出限定值的请求。并发
•静态响应处理: 在边缘位置直接创建部分响应,从而避免其流入内部集群。app
•多区域弹性: 跨越AWS区域进行请求路由,旨在实现ELB使用多样化并保证边缘位置与使用者尽量接近。socket
配置以下ide
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
适用于ApacheHttpClient,若是是okhttp无效。每一个服务的http客户端链接池最大链接,默认是200.
适用于ApacheHttpClient,若是是okhttp无效。每一个route可用的最大链接数,默认值是20。
Hystrix最大的并发请求 execution.isolation.semaphore.maxConcurrentRequests
,这个值并不是TPS
、 QPS
、 RPS
等都是相对值,指的是1秒时间窗口内的事务/查询/请求, semaphore.maxConcurrentRequests
是一个绝对值,无时间窗口,至关于亚毫秒级的。当请求达到或超过该设置值后,其其他就会被拒绝。默认值是100。参考: Hystrix semaphore和thread隔离策略的区别及配置参考
这个参数原本直接能够经过Hystrix的命名规则来设置,但被zuul从新设计了,使得在zuul中semaphores的最大并发请求有4个方法的参数能够设置,若是4个参数都存在优先级(1~4)由高到低:
须要注意的是:在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.command.default.execution.isolation.thread.timeoutInMilliseconds
用来设置thread和semaphore两种隔离策略的超时时间,默认值是1000。
hystrix.command.[CommandKey].execution.isolation.thread.timeoutInMilliseconds
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中