本文概览:介绍了Zuul服务搭建;Zuul的路由配置和过滤器两大功能,如下

  • Zuul的四种路由配置。
  • 三种过滤器:前置过滤器、路由过滤器、后置过滤器。三种过滤器只是执行点不同,都是继承自ZuulFilter。
  • 使用前置过滤器实现traceId
  • 使用路由过滤器实现Abtest

1 网关引入与Zuul

1.1 网关引入

1、两大功能

主要包括 路由和过滤器 两大功能。主要功能体现在过滤器,实现“横切关注点”水平切分各个服务的公共部分,如日志记录等功能,作为服务来提供。

2、Zull和nginx区别

(1)动态注册和注销 客户端服务时,网关服务可以立刻生效。Nginx需要通过修改配置文件才能生效。

(2)横切服务关注点

1.2 Zuul介绍

在没有网关之前,客户端服务包括两个步骤:

  • 从EurekaServer获取一个客户端服务的所有地址
  • 通过Ribbon负载均衡选择一个机器进行访问

WX20181127-232833

引入网关之后,客户端通过 “http://gateway/服务ID/url” URL格式调用网关,网关执行包括两个步骤:

  • 使用服务ID查找客户端服务
  • 使用Netflix Ribbon对调用服务进行负载均衡。

2

2  Zuul服务搭建

1、pom.xml

2、使用注解@EnableZuulProxy

3、配置文件

4、启动之后

30417783

5、可以通过 http://localhost:8763/routes 查看网关当前路由信息

49450231

如果出现There was an unexpected error (type=Unauthorized, status=401).”,解决该问题就是添加一个配置如下:

3 Zuul 路由

3.1 默认配置

URL的格式如下,默认情况下都是Eureka上注册的服务ID。

  • gateway,网关服务在Eureka注册的服务ID
  • 服务ID,客户端服务在Eureka注册的服务ID
  • url,访问客户端服务的url。

下面以三种查询服务方式的为例,实现通过网关访问。三种查询服务方式参考:

SpringCloud服务查找

3.1.1 DiscoverClient方式

1、使用DiscoveryClient

2、测试

3、执行结果

51332654

3.1.2 SpringCloud增强版的Rest Template

1、使用网关来访问微服务

2、测试

3、执行结果

51317884

3.1.3 Netflix Feign

1、使用Feign调用网关

2、测试

3、结果

51263227

3.2 手动配置

3.2.1   手动配置实例

1、在网关服务中的配置文件中添加

此时重新启动网关服务,访问网关服务的 /routes 接口,如下。发现除了默认的根据eureka注册服务ID的映射之外,还有一个是自己手动配置映射记录。

49450231

2、客户端使用

在使用网关时,此时只需要把网关名字由服务ID(service-prodvider1)改为自己定义的名字(provider1)就可以了。如下

3.2.3 其他配置

1、取消默认配置

(1)取消一个服务的默认配置

(2)取消所有服务的自动配置

3.3 静态配置

对于Spring mvc和非JVM(python等)服务并没有在Eureka上注册,此时在网关进行配置路由时只能指定一台服务,无法使用Ribbon进行负载均衡。

解决方案就是将这两类服务注册到Eureka。后续会介绍这两类服务的注册。

3.4 动态配置

使用spring cloud或者apollo来进行配置路由。

4 Zuul过滤器

过滤器是网关GateWay 引入最重要的一点,实现了横切关注点,即将服务的一些功能移动到网关服务中,如添加traceID、验证/授权等。目前主要有前置过滤器、路由过滤器和后置过滤器 三种过滤器。如下图:

  • 前置过滤器。在Zull网关调用服务之前,对请求request进行处理。如添加traceId,请求的验证和授权。
  • 路由过滤器。在Zull网关调用服务之前,重新设置新的路由规则,可以覆盖zuul的路由配置。如A/B 测试。
  • 后置过滤器。在Zull网关调用服务之后,对response进行处理。如添加traceId。

Snip20181116_5

三种过滤器区别就在于执行时间点不同,对于前置过滤器和路由过滤器是在Zuul网关调用下游服务前;对于后置过滤器是在Zuul网关调用下游服务之后。

三种过滤器共同点都是继承自ZuulFilter,需要实现四个方法:

  • filterType。值有:pre/post/route,对应的常量值为FilterConstants.PRE_TYPE、FilterConstants.POST_TYPE、FilterConstants.POST_TYPE。
  • filterOrder。filter执行顺序
  • shouldFilter。是否需要执行此过滤器。
  • run。过滤器执行逻辑

5  前置过滤器

使用前置过滤器可以为各服务生成一个TraceId为例,TracId可以将各个服务的日志串联起来,方便查询问题。实现此串联TrancId的功能主要包括网关和客户端两部分:

(1)网关。负责在请求中生成traceID

  • Zuul前置过滤器。从http request中获取traceID,保存到上下文RequestContext中;如果traceId不存在就生成一个traceId中。

(2)客户端。负责从请求获取traceID、使用traceID、传递TranceID到下游服务

  • 过滤器Filter。从HTTP Request的头部获取TraceId.
  • 执行服务的业务逻辑。使用RequestContext中traceId,如打印日志。
  • 添加RestTemplate拦截器。在请求下游服务时,添加traceId,把TraceID传递到下游服务。

74537290

5.1 Zuul前置过滤器-生成TraceId

1、生成TraceId

在请求达到网关服务之后,首先判断request的header中是否存在traceId,如果存在就直接跳过,否则生成一个traceId,放到request的header中。

注意:

  • RequestContext使用的是zuul提供的,不是Spring提供的。

2、测试

在网关生成traceId之后,就可以在客户端通获取上面的traceId了

5.2 客户端使用TraceId

客户端可以通过过滤器获取请求head中的traceId,并把TraceId保存到上下文中;执行业务逻辑时就可以从这个上下文中获取traceId。

1、获取Http Request头部中的traceId

2、使用上下文中的traceId

3、上下文和上下文Holder

(1)上下文

(2)上下文Holder

5.3 客户端RestTemplate拦截器

1、定义SpringTemplate的拦截器,在发送的Request的头部添加tranceId

2、将新定义的拦截器加入到RestTemplate。

3、测试

使用上面的RestTemplate,进行访问其他服务,如下代码。这个新定义的RestTemplate属于服务查找方式中“SpringCloud 增强版的RestTemplate”。

6 后置过滤器

通过后置过滤器可以处理Response。如在response中添加traceID,如下:

7 路由过滤器

路由过滤器功能就是可以覆盖Zuul原来的路由配置,重新路由请求。在实际中,灰度发布、Abtest都可以通过这个过滤器实现。

7.1 AB test的实现

这里以实现A/B test为例。首先介绍下AB test:

A/B test,或者说灰度发布。对于一次升级,并不想要一次让所有用户看到,而是循序渐进的让更多用户看到,这样也方便优化。灰色,介于白色和黑色之间,寓意一个功能即不是全部给用户看到也不是所有用户看不到,而是部分用户可见。

如下是一个简单Abtest的实现流程,主要包括如下步骤:

  • 获取Ab Test的配置信息。如服务的灰度机器列表信息等。
  • 校验是否需要走新的路由。AB test 的策略
  • 获取新的服务地址。需要考虑负载均衡
  • 转发路由。

83054971

7.1.1 定义后置过滤器

如下是路由过滤器定义,需要注意:

  • filterOrder()。返回的是SIMPLE_HOST_ROUTING_FILTER_ORDER – 1。SimpleHostRoutingFilter中改返回值是SIMPLE_HOST_ROUTING_FILTER_ORDER, 所以这里要减一,保证此过滤器在SimpleHostRoutingFilter之前执行。

7.1.2 获取AB test的配置信息

为了测试方便,这里把配置信息当成常量来写了,其实应该是调用配置中心来获取的。这里需要注意的有:

  • 需要有一个灰度开关。在不需要灰度,可以关闭次开关。

对应配置信息类为:

7.1.3 路由策略

7.1.4 获取新服务地址

7.1.5 转发路由

用到了OkHttpClient,需要引入下面的maven包

转发路由的逻辑如下:

7.1.6 测试

1、客户端

默认是请求客户端服务Provider1,如下

2、Provider1提供的query接口逻辑如下

3、Provider2提供的query接口逻辑如下

4、返回结果为

81328642

7.2 关于其他策略

1、根据用户ID后两位实现AB test的路由策略

对于部分用户可以看到新功能或者新服务,除了上面的随机概率方式,我们还可以根据userId的后两位,如为00,10,20,30…90结尾用户可见,此时就占10%的用户可以看到了新服务了。

2、项目中也常会遇到,对于上线新产品,需要开小流量,即只有部分用户可以看到这个产品,这种场景就不需要通过Zull来完成了,只需要在代码添加开关就可以了。因为这些代码需要全量上线的。对于代码只上线部分机器,并进行观察的场景,可以考虑Zuul实现灰度

8 Zull相关配置

8.1 超时配置

1、全部服务

2、指定服务

如果服务ID为provider1,则替换default,如下

参考文献:

Zuul官网:https://cloud.spring.io/spring-cloud-static/spring-cloud-netflix/2.1.0.M1/multi/multi__router_and_filter_zuul.html

分类&标签