Zuul介绍
Zuul是Netlix开源的微服务网关,它可以和Eureka、Ribbon、 Hystrix 等组件配合使用。Zuul的核心是一系列的过滤器,这些过滤器可以完成以下功能。
身份认证与安全: 识别每个资源的验证要求,并拒绝那些与要求不符的请求。
审查与监控: 在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图。
动态路由: 动态地将请求路由到不同的后端集群。
压力测试: 逐渐增加指向集群的流量,以了解性能。
负载分配: 为每一 种负载类型分配对应容量,并弃用超出限定值的请求。
静态响应处理: 在边缘位置直接建立部分响应,从而避免其转发到内部集群。
多区域弹性: 跨越AWS Region进行请求路由,旨在实现ELB ( Elastic Load Balancing )使用的多样化,以及让系统的边缘更贴近系统的使用者。
路由入门案例
编写案例
新建微服务gateway,并导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
编写启动类,并添加 @EnableZuulProxy注解
@EnableZuulProxy
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class);
}
}
编写配置application.yml,配置路由
server:
port: 8083
#配置路由
zuul:
routes:
hehe: #路由id
path: /user-service/** #匹配user-service为前缀的路径(用户服务的请求)
url: http://127.0.0.1:8081 #转发到该路径下
测试
问题分析
缺点:上述配置中的路径写死,不够灵活(面向路径)
改进:可以同过从Eureka拉取服务(面像服务路由)
改进案例
gateway中引入eureka客户端
<!--引入eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
修改配置
server:
port: 8083
eureka:
client:
service-url:
defaultZone: http://localhost:8082/eureka
#配置路由
zuul:
routes:
hehe: #路由id
path: /user-service/** #匹配user-service为前缀的路径
serviceId: user-service #转发到该服务下
测试
改进配置文件
zuul会再eureka上拉取所有的服务列表,默认为每一个微服务创建一个默认的配置,所以配置也可以写成这样
server:
port: 8083
eureka:
client:
service-url:
defaultZone: http://localhost:8082/eureka
#配置路由
#可以直接写服务的id和路径
zuul:
routes:
user-service: /user-service/** #key服务的id,值服务的映射路径,遵循该路径的都会被转发到 user-service服务
简化配置
#配置路由
zuul:
routes:
user-service: /user/** #简化配置
若有不想被拉去的服务可以选择配置不暴露该服务
zuul:
routes:
user-service: /user/**
ignored-services: # 配置不暴露的服务
- consumer-service
访问路径太繁琐,可以选择配置去除前缀
zuul:
routes:
user-service:
path: /user/** #匹配user-service为前缀的路径
serviceId: user-service #转发到该服务下
strip-prefix: false #去掉前缀,即通过路径访问时可以省略前缀
配置完成后的访问路径:localhost:8083/ user / user/2
Zuul过滤器
过滤器主要方法
主要方法
public abstract ZuulFilter implements IZuulFilter(){
abstract public String filterType();//返回字符串,意为过滤器类型
abstract public int filterOrder(;//过滤器的优先级
boolean shouldFilter(); //是否过滤
Object run() throws ZuulException(); //过滤的逻辑
}
4种过滤器类型
filterType(),返回字符串,意为过滤器类型
pre:请求路由之前执行
routing:在路由请求时调用
post:在routing和error之间执行
error:处理请求时发生错误调用
模拟登录案例的过滤
模拟登录案例,路径中需要包含路径信息,若包含给予登录,若不包含返回所需的信息
编写LoginFilter继承ZuulFilter
@Component
public class LoginFilter extends ZuulFilter {
@Override
public String filterType() { //过滤器类型
return FilterConstants.PRE_TYPE;// 或者直接 return "pre";
}
@Override
public int filterOrder() { //过滤器顺序
return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
}
@Override
public boolean shouldFilter() { //是否需要过滤器
return true;
}
@Override
public Object run() throws ZuulException { //业务逻辑
//获取请求上下文
RequestContext ctx = RequestContext.getCurrentContext();
//获取request
HttpServletRequest request = ctx.getRequest();
//获取请求参数 access-token
String token = request.getParameter("access-token");
//判断是否存在
if (StringUtils.isBlank(token)){ //commons-lang3的工具类,判断字符串是否为空
//不存在,未登录,给予拦截
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(HttpStatus.SC_FORBIDDEN); //int SC_FORBIDDEN = 403;
}
return null;
}
}
测试
不包含登录信息
添加登录状态信息access-token后
Zuul中的负载均衡和熔断
Zuul中默认就已经集成了Ribbon负载均衡和Hystix熔断机制。但是所有的超时策略都是走的默认值,比如熔断超时时间只有1S,很容易就触发了。因此建议我们手动进行配置:
hystrix:
command:
defaulet:
execution:
isolation:
thread:
timeoutInMilliseconds: 6000
ribbon:
ConnectionTimeOut: 500
ReadTimeOut: 1000
ribbon的超时时长,默认真实值是 (read + connect)* 2,必须小于hystrix时长
Zuul高可用
启动多个Zuul服务,自动注册到Eureka,形成集群。如果是服务内部访问,你访问Zuul,自动负载均衡,没问题。但是,Zuul更多是外部访问,PC端、 移动端等。他们无法通过Eureka进行负载均衡,那么该怎么办?此时,我们会使用其它的服务网关,来对Zuu进行代理。比如: Nginx、Eureka、Ribbon、Hystix、 Feign、 Zuul。