API服务网关
API服务网关就是出现在微服务边界上的一个面向API的、串行集中式的、对访问请求强管控的服务,采用的是一个外观模式。API服务网关是微服务访问的统一入口,负责服务请求路由、组合及协议转换等处理。
- API服务网关帮助开发者隐藏系统架构实现的细节,提供统一的入口供客户端访问,让微服务使用更为友好。
- 通过微服务的统一访问控制,简化了客户端开发的复杂度,降低了客户端与微服务之间的通信次数,客户端不需要与多个微服务之间进行通信,也不需要了解各个微服务的详细服务。
- 借助API服务网关可统一做切面任务,避免每个微服务自己开发,提升效率,使系统更加标准化。
- 通过API服务网关,可以将异构系统进行统一整合。
- API服务网关需要实现一个高可用伸缩性强的服务,避免单点失效。
API服务网关需要对所有微服务实例所暴露的端点进行统一的管理,
Spring Cloud与Netflix Zuul
Zuul组件的功能:
动态路由:支持与Eureka服务器的整合,可以动态对注册到Eureka服务器中的微服务进行路由映射。Zuul提供了一系列的路由规则配置,可以针对实际情况,实现微服务路由的灵活控制。
- 监控与审查:通过对特定的接口设置访问白名单、访问次数、访问频率等。
- 身份认证与安全:通过Zuul将用户登录认证等类似的功能抽取出来,让微服务系统无须关注认证的逻辑,实现统一的逻辑处理。还可以统一在服务网关层增加一个额外的保护层来防止恶意攻击等。
- 压力测试:通过Zuul所提供的过滤器功能可以逐渐增加对某一服务集群的流量,进行服务性能测试。
- 金丝雀、A/B测试:新版本、新功能需要测试相应的功能,通过API服务网关,控制部分用户访问服务实例。
- 服务迁移:通过Zuul代理可以处理来自旧端点的所有流量,将请求重定向到新的端口。
-
启动Zuul路由服务
1、构建Zuul路由服务器
编写pom文件
编写启动类
编写配置文件
2、路由测试
启动服务治理服务器,端口8260;启动商品微服务;端口8100;启动Zuul路由服务,端口8300。
说明Zuul路由服务器已经将请求自动转发到商品微服务中。
Zuul将默认从Eureka服务器中获取所注册的服务,将服务的ID作为请求路径中的一部分,然后将用户的请求自动转发到这些服务中。
3、负载均衡测试
启动2个用户微服务,端口分别为8000和8001。
然后继续访问http://localhost:8300/product-service/product/comment该接口验证Zuul服务器负载均衡。
如果处理不好Zuul路由服务的话,Zuul路由服务可能会成为一个访问瓶颈,所以在构建API访问网关的时候需要把我两个原则:
KISS原则:Keep it Simple and Stupid,要保持API服务网关的简单和轻量。
stateless原则:无状态,Zuul服务网关中不应该、也不可以保存有关服务调用过程中的状态数据。
4、Hystrix容错测试
关闭调用户微服务,继续访问。
Zuul本身已经默认集成了Hystrix和Ribbon,所以Zuul拥有线程隔离和服务容错的自我保护能力,以及对服务调用的客户端负载均衡功能。路由配置规则
Zuul提供了多种机制对请求路由进行映射:
与Eureka服务器整合自动根据服务的ID进行映射,默认机制。
- 结合微服务ID通过自定义方式进行路由映射。
- 直接使用静态URL路径的方式对微服务进行理由映射。
- 添加全局路由映射
- 通过自定义路由转换器,实现更灵活的路由映射。
1、服务路由默认规则
Zuul可以自动根据Eureka服务器中所注册的服务自动完成路由映射、负载均衡。
http://[zuul路由服务器地址]/[serviceId]/[URI]
2、自定义微服务访问路径
可以在Zuul路由服务器配置文件进行配置
3、忽略指定微服务
我们制定了producet的路由设置,但是之前的http://localhost:8300/product-service/product/comment还是能继续访问。那么就需要把默认的路由映射忽略掉。
这样原有的路由就方位不了了,如果忽略全部服务的路由映射,ignored-services: ““就可以。
4、设置路由前缀
Zuul代理默认转发到服务实例时会自动去掉prefix前缀。如果需要转发时带上的话,则增加zuul.stripPrefix=fasle设置。
5、通过静态URL路径配置路由映射
对于没有注册到Eureka服务器中的服务,可以通过在Zuul理由服务器中配置静态URL,来进行服务的路由映射。
因为没有经过Eureka服务器,就用不到Ribbon的负载均衡了。这种情况下,需要禁用Ribbon与Eureka的自动继承设置,采用手动设置的方法开启。
*6、自定义路由规则
Zuul路由其他设置
1、Header设置
敏感Header设置:默认情况下,Zuul在请求路由时,会过滤HTTP请求头信息中的一些敏感信息。
忽略Header设置:
2、HttpClient配置
Zuul的HTTP客户端支持Apache Http、Ribbon的RestClient、OkHttpClient,默认使用Apache HTTP客户端。
3、路由配置的动态加载
Spring Cloud Config子项目提供了配置文件的统一管理,需要将配置文件yml文件抽取统一存放在版本管理服务器上,然后将Zuul路由服务器的配置从统一的管理服务器中进行加载。当需要修改路由映射规则时,就需要将修改后的配置文件提交到Git中,然后在Zuul路由服务器中使用/refresh端点重新加载配置。
Zuul容错与回退
1、实现Zuul的回退
Zuul提供了ZuulFallbackProvider接口,通过实现该接口可以为Zuul实现降级功能。
代码示例:
- getRoute():返回的是为哪个微服务提供回退功能。PS:该地方返回的是route的名称,而不是微服务的名称
- fallbackResponse():返回ClientHttpResponse对象。
2、服务超时
当Zuul路由服务将客户端请求转发到具体服务时,Zuul会使用HystrixCommand来包装执行过程,所有Hystrix的配置及服务容错降级机制,对于Zuul的请求执行也是一样的,会影响到API网关。
这里需要同时设置Hystrix和Ribbon的值,只设置其中的一个是不生效的。
Zuul过滤器
Zuul其实包含了两个功能:路由和过滤器。路由的功能是负责将外部请求转发到具体的微服务实例上,过滤器的功能则是负责对请求的处理过程进行干预,是实现请求校验,是在微服务之间实现切面的处理。
1、过滤器特性
Zuul过滤器的关键特性:
- Type:定义在请求执行过程中何时被执行
- Execution Order:当存在多个过滤器时,用来指示执行的顺序,值越小越早执行
- Criteria:执行的条件,即该过滤器何时被处罚
- Action:该过滤器具体要执行的动作。
实现一个自定义过滤器时需要实现的方法:
- filterType()方法返回过滤器的类型
- filterOrder()方法返回过滤器的执行顺序
- shouldFilter()方法判断是否需要执行该过滤器
- run()方法是该过滤器所要执行的具体过滤动作。
2、过滤器类型及生命周期
Zuul中4中标准的过滤器类型:
- PRE过滤器:在请求被路由之前调用,可用来上线身份验证、在集群中选择请求的微服务、记录调试信息。
- ROUTING过滤器:在调用目前服务之前被调用,用来处理一些动态理由。如A/B测试。
- POST过滤器:在目标微服务执行后,所返回的结果在送回给客户端时被调用。可以实现为响应添加标准的HTTP Header、数据采集、统计信息和指标、审计日志处理。
- ERROR过滤器:在处理请求过程中发生错误时被调用,可以使用实现对异常、错误的统一处理。
请求整体流程:
- 对于任何注册到Zuul服务网关上的PRE过滤器,在请求被路由之前,该类型的过滤器可以对请求进行监控或修改,但是不可以将服务请求重新定位到不同的服务中。
- 当Zuul执行了PRE过滤器后,服务请求就会被转发到ROUTING过滤器中执行,ROUTING过滤器执行时可以将服务请求根据需要分发到不同的服务实例中执行。
- 根绝ROUTING过滤器处理的结果调用相应的服务进行处理。
- 当目标服务执行后,Zuul将转回执行所注册的POST过滤器,在该过滤器中,我们对返回客户端的结果进行处理。
- 一旦处理过程中发生错误,那么就会转入ERROR过滤器中执行,对异常、错误进行统一处理。
3、自定义Zuul过滤器
4、禁用Zuul过滤器
禁用上面的TestFilter中PRE过滤器。
5、Error过滤器
基于Zuul过滤器进行的逻辑,我们可以添加一个全部异常处理。
新增一个类型为Error的过滤器,在改过滤器中将错误信息写入RequestContext中,这样SendErrorFile就可以获取该错误信息,并转发到Spring Boot中进行通用的错误处理。
@EnableZuulServer与@EnableZuulProxy比较
@EnableZuulProxy注解包含了@EnableZuulServer的所用功能,并加入了@EnableCircuitBreaker和@EnableDiscoveryClient。
1、EnableZuulServer注解的过滤器
PRE类型过滤器
- ServletDetectionFilter:最先执行的,主要用来检查当前请求是通过Spring的DispatcherServlet处理运行的,还是通过ZuulServlet来处理运行的。
- FormBodyWrapperFilter:将符合要求的请求体包装成FormBodyRequestWrapper对象,供后续处理使用。
- DebugFilter:当请求参数中设置了debug参数时,该过滤器将当前请求上下文中的debugRouting和debugRequest设置为true,后续的过滤器可以根据这两个参数信息定义一些deub信息。
ROUTE类型过滤器
- SendForwardFilter:只对请求上下文中存在forward.to参数的请求进行处理。
POST类型过滤器
- SendResponseFilter:是对代理请求所返回的相应进行封装,然后作为本地请求的相应发送给请求者。
Error类型过滤器
- SendErrorFilter:判断当前请求上下文中是否有异常信息,判断的标准是RequestContext.getThrowable()是否不为空。
2、EnableZuulProxy注解的过滤器
@EnableZuulProxy则在@EnableZuulServer的基础上做了增加。
PRE类型过滤器
- PreDecorationFilter:根据提供的RouteLocator确定路由到的地址,以及怎样去路由。
ROUTE类型过滤器
- RibbonRoutingFilter:会针对上下文中存在serviceId的请求进行处理,使用Ribbon、Hystrix和可插拔的HTTP客户端发送请求,并将服务实例的请求结果返回。
- SimpleHostRoutingFilter:检测到routeHost参数设置时,则会通过Apache HttpClient向指定的URL发送请求。此时,该请求不会使用HystrixCommand进行包装,所以这类请求没有线程隔离和服务容错保护功能。