路由是微服务架构中必须(integral )的一部分,比如,“/” 可能映射到你的WEB程序上,”/api/users
“可能映射到你的用户服务上,“/api/shop”可能映射到你的商品服务商。(注解:我理解这里的这几个映射就是说通过Zuul这个网关把服务映射到不同的服务商去处理,从而变成了微服务!)
1. Zuul 简介
Zuul是Netflix开源的微服务网关,他可以和Eureka,Ribbon,Hystrix等组件配合使用。Zuul组件的核心是一系列的过滤器,这些过滤器可以完成以下功能:
# 身份认证和安全: 识别每一个资源的验证要求,并拒绝那些不符的请求
# 审查与监控:
# 动态路由:动态将请求路由到不同后端集群
# 压力测试:逐渐增加指向集群的流量,以了解性能
# 负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求
# 静态响应处理:边缘位置进行响应,避免转发到内部集群
# 多区域弹性:跨域AWS Region进行请求路由,旨在实现ELB(ElasticLoad Balancing)使用多样化
Spring Cloud对Zuul进行了整合和增强。目前,Zuul使用的默认是Apache的HTTP Client,也可以使用Rest Client,可以设置ribbon.restclient.enabled=true.
2. 编写Zuul微服务网关
添加依赖
Zuul的依赖肯定是要加的,如何和Eureka配合使用, Zuul需要注册到Eureka上,但是Zuul的依赖不包含Eureka Discovery客户端,所以还需要添加Eureka的客户端依赖
启动类加上注解@EnableZuulProxy
它默认加上了@EnableCircuitBreaker和@EnableDiscoveryClient
配置application.yml或者application.properties
***
3. 微服务网关相关的配置
路由路径的配置
zuul:
ignoredServices: '*' // 忽略所有请求
routes:
服务名: /xxx/** //允许将服务名映射到xxx
以下表示只要HTTP请求是 /XXX开始的,就会forward到服务id为users_service的服务上面
zuul:
routes:
users:
path:/XXX/** // 路由路径
serviceId: users_service // 服务id
zuul:
routes:
users: // 路由名称,随意,唯一即可
path: /XXX/** // 路由路径
url:http://localhost:9000
不破坏Zuul的Hystrix和Ribbon特性
***
使用正则表达式指定Zuul的路由匹配规则
借助PatternServiceRoute Mapper实现从微服务到映射路由的正则配置,例如:
@Bean
publicPatternServiceRouteMapper serviceRouteMapper(){
// servicePattern: 指的是微服务的pattern
// routePattern: 指的是路由的pattern
// 当你访问/microservice-provider-user/v1 其实就是
// localhost:8040/v1/microservice-provider-user/user/1
return newPatternServiceRouteMapper(
"(?<name>^.+)-(?<version>v.+$)","${version}/${name}"
);
}
4. Zuul的过滤器
过滤器是Zuul的核心组件,Zuul大部分功能都是通过过滤器来实现的。
4.1. 过滤器类型和请求生命周期
Zuul中定义了四种标准的过滤器类型,这些过滤器类型对应于典型的生命周期。
PRE: 这种过滤器在请求被路由之前调用。可利用其实现身份验证等
ROUTING: 这种过滤器将请求路由到微服务,用于构建发送给微服务的请求,并使用Apache Http Client或者Netflix Ribbon请求微服务
POST: 这种过滤器在路由到微服务以后执行,比如为响应添加标准的HTTP Header,收集统计信息和指标,将响应从微服务发送到客户端等
ERROR: 在其他阶段发生错误时执行该过滤器
除了默认的过滤器类型,Zuul还允许创建自定义的过滤器类型。
4.2. 编写Zuul过滤器
我们只需要继承抽象类ZuulFilter过滤器即可,让该过滤器打印请求日志。
public classPreRequestLogFilter extends ZuulFilter {
private static final Logger logger = LoggerFactory.getLogger(
PreRequestLogFilter.class);
@Override
public Object run() {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest reqeust = context.getRequest();
PreRequestLogFilter.logger.info(
String.format("send %srequest to %s",
reqeust.getMethod(),
reqeust.getRequestURL().toString()));
return null;
}
@Override
public boolean shouldFilter() {
// 判断是否需要过滤
return true;
}
@Override
public int filterOrder() {
// 过滤器的优先级,越大越靠后执行
return 1;
}
@Override
public StringfilterType() {
// 过滤器类型
return "pre";
}
}
修改启动类,为启动类添加:
@SpringBootApplication
@EnableZuulProxy
public classZuulFilterApplication {
@Bean
publicPreRequestLogFilter preRequestLogFilter(){
return newPreRequestLogFilter();
}
public static void main(String[] args) throws Exception {
SpringApplication.run(ZuulFilterApplication.class, args);
}
}
5. Zuul聚合微服务
许多场景下,一个外部请求,可能需要查询Zuul后端多个微服务。比如说一个电影售票系统,在购票订单页上,需要查询电影微服务,还需要查询用户微服务获得当前用户信息。如果让系统直接请求各个微服务,就算Zuul转发,网络开销,流量耗费,时长都不是很好的。这时候我们就可以使用Zuul聚合微服务请求,即应用系统只发送一个请求给Zuul,由Zuul请求用户微服务和电影微服务,并把数据返给应用系统。