API 网关服务: Spring Cloud Zuul
Sping Cloud Zuul 是什么?
spring cloud zuul
是netflix提供的一个组件,功能类似于nginx,用于反向代理,可以提供动态路由、监控、授权、安全、调度等边缘服务。
微服务场景下,每一个微服务对外暴露了一组细粒度的服务。客户端的请求可能会涉及到一串的服务调用,如果将这些微服务都暴露给客户端,那么会增加客户端代码的复杂度。
将细粒度的服务组合起来提供一个粗粒度的服务,所有请求都导入一个统一的入口,那么整个服务只需要暴露一个api,对外屏蔽了服务端的实现细节,也减少了客户端与服务器的网络调用次数。这就是api gateway。
有了api gateway之后,一些与业务关系并不大的通用处理逻辑可以从api gateway中剥离出来,api gateway仅仅负责服务的编排与结果的组装。
Spring Cloud Netflix的Zuul组件可以做反向代理的功能,通过路由寻址将请求转发到后端的粗粒度服务上,并做一些通用的逻辑处理。
为什么需要API Gateway
1、简化客户端调用复杂度
在微服务架构模式下后端服务的实例数一般是动态的,对于客户端而言很难发现动态改变的服务实例的访问地址信息。因此在基于微服务的项目中为了简化前端的调用逻辑,通常会引入API Gateway作为轻量级网关,同时API Gateway中也会实现相关的认证逻辑从而简化内部服务之间相互调用的复杂度。
2、数据裁剪以及聚合
通常而言不同的客户端对于显示时对于数据的需求是不一致的,比如手机端或者Web端又或者在低延迟的网络环境或者高延迟的网络环境。
因此为了优化客户端的使用体验,API Gateway可以对通用性的响应数据进行裁剪以适应不同客户端的使用需求。同时还可以将多个API调用逻辑进行聚合,从而减少客户端的请求数,优化客户端用户体验
3、多渠道支持
当然我们还可以针对不同的渠道和客户端提供不同的API Gateway,对于该模式的使用由另外一个大家熟知的方式叫Backend for front-end, 在Backend for front-end模式当中,我们可以针对不同的客户端分别创建其BFF
4、遗留系统的微服务化改造
对于系统系统而言进行微服务改造通常是由于原有的系统存在或多或少的问题,比如技术债务,代码质量,可维护性,可扩展性等等。API Gateway的模式同样适用于这一类遗留系统的改造,通过微服务化的改造逐步实现对原有系统中的问题的修复,从而提升对于原有业务响应力的提升。通过引入抽象层,逐步使用新的实现替换旧的实现。
简单使用
1、添加依赖
org.springframework.cloud
spring-cloud-starter-zuul
引入spring-cloud-starter-zuul
包
2、配置文件
spring.application.name=gateway-service-zuul
server.port=8888
3、启动类
@SpringBootApplication
@EnableZuulProxy
public class GatewayServiceZuulApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayServiceZuulApplication.class, args);
}
}
启动类添加@EnableZuulProxy
,支持网关路由。
路由的配置
传统路由
在上面的配置中使用了zuul.toutes..path
和zuul.toutes..url
参数的方式配置单实例的路由,而在微服务架构中,为了服务的高可用,一般会将一个服务部署多个。传统的多实例的路由配置,Zuul提供了以下方法:
通过zuul.toutes.
zuul.routes.feign-consumer.path=/feign/**
zuul.routes.feign-consumer.serviceId=feign-consumer
robbin.eureka.enable=false
feign-consumer.ribbon.listOfServers=http://localhost:50000/,http://localhost:50001/
该配置实现了对符合/feign/**
规则的请求转发到http://localhost:50000/,http://localhost:50001/
两个实例地址的路由规则。这里的serviceId是有程序员手动命名的服务名称。robbin.eureka.enable=false
设置Ribbon不根据服务发现机制来获取配置服务对应的实例清单。
服务路由
zuul:
routes:
api-a:
path: /api-a/**
serviceId: feign-consumer
该配置实现了对符合/api-a/**
规则的请求路径转发到名为feign-consumer
的服务实例上去的路由规则。api-a
是任意的路由名称。还可以使用一种更加简洁的方法zuul.routes.=
,这里serviceId指定具体的服务名,path配置匹配的请求表达式。
其他配置
zuul.ignored-services=hello-service:忽略掉一个服务;
zuul.ignored-patterns=/**/feign/**: 忽略/feign接口路由;
zuul.prefix:为路由添加统一前缀;
zuul.add-host-header: true:在请求路由转发前为请求设置Host头信息;
zuul.sensitiveHeaders=:设置全局参数为空来覆盖默认敏感头信息
zuul.routes..customSensitiveHeaders=true:对指定路由开启自定义敏感头
zuul.routes..sentiviteHeaders=:将指定路由的敏感头设置为空。
zuul.retryable=false:关闭重试机制
zuul.routes..retryable=false:指定路由关闭重试机制
zuul...disable=true:禁用指定的过滤器,代表过滤器的类名,代表过滤器的类型。
在Zuul中Hystrix和Ribbon的配置与传统的Hystrix和Ribbon服务的配置一样。
Zuul 的核心
Filter
是Zuul的核心,用来实现对外服务的控制。Filter的生命周期有4个,分别是“PRE”、“ROUTING”、“POST”、“ERROR”,整个生命周期可以用下图来表示。
Zuul大部分功能都是通过过滤器来实现的,这些过滤器类型对应于请求的典型生命周期。
PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。
POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
ERROR:在其他阶段发生错误时执行该过滤器。 除了默认的过滤器类型,Zuul还允许我们创建自定义的过滤器类型。例如,我们可以定制一种STATIC类型的过滤器,直接在Zuul中生成响应,而不将请求转发到后端的微服务。
路由熔断
当我们的后端服务出现异常的时候,我们不希望将异常抛出给最外层,期望服务可以自动进行一降级。Zuul给我们提供了这样的支持。当某个服务出现异常时,直接返回我们预设的信息。
我们通过自定义的fallback方法,并且将其指定给某个route来实现该route访问出问题的熔断处理。主要继承ZuulFallbackProvider接口来实现,ZuulFallbackProvider默认有两个方法,一个用来指明熔断拦截哪个服务,一个定制返回内容。
public interface ZuulFallbackProvider {
/**
* The route this fallback will be used for.
* @return The route the fallback will be used for.
*/
public String getRoute();
/**
* Provides a fallback response.
* @return The fallback response.
*/
public ClientHttpResponse fallbackResponse();
}
路由重试
有时候因为网络或者其它原因,服务可能会暂时的不可用,这个时候我们希望可以再次对服务进行重试,Zuul也帮我们实现了此功能,需要结合Spring Retry 一起来实现。 此处略。
Zuul高可用
性能优化参考
在application.yml文件中配置线程数、缓冲大小
server:
tomcat:
max-threads: 128 # 最大worker线程
min-spare-threads: 64 # 最小worker线程
undertow:
io-threads: 8 # IO线程数,默认为CPU核心数,最小为2
worker-threads: 40 # 阻塞任务线程池,值设置取决于系统的负载,默认为io-threads * 8
buffer-size: 512 # 每块buffer的空间大小
buffers-per-region: 10 # 每个区分配的buffer数量
direct-buffers: 512 # 是否分配的直接内存
在application.yml文件中配置zuul和ribbon
zuul:
host:
max-total-connections: 500 # 每个服务的http客户端连接池最大连接,默认值是200
max-per-route-connections: 50 # 每个route可用的最大连接数,默认值是20
ribbon-isolation-strategy: THREAD # 可选:SEMAPHORE THREAD
Less is more.