Zuul(路由网关)的使用
Zuul是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet应用。
Zuul 在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架。Zuul 相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门。
Zuul为了实现以上功能必然的它就需要实现一个更为基础的功能:反向代理。
zuul为了能够实现对前端请求的全部代理、拦截、转发,它代理微服框架中的其他服务器。
springcloud对zuul进行了集成: spring-cloud-starter-zuul。
下面开始zuul在springcloud下的整合运用:
1、首先创建一个springboot项目,项目中集成:eureka server 和 zuul 插件
启动类添加注解:@EnableZuulProxy
package com.example.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy zuul作为一个中间介
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
配置文件中添加:端口号、开启服务代理
server:
port: 5200
spring:
application:
name: zuulserver
zuul:
routes:
user: 这个地方随便写就可以了,不过建议用被代理的名称,便于区分
path: /user/** 拦截的位置
serviceId: user 被代理端注册名称
url: http://localhost:5100/ 通过URL地址进行代理
#推荐使用serviceId的映射方式,除了对Zuul维护上更加友好之外,serviceId映射方式还支持了断路器,
对于服务故障的情况下,可以有效的防止故障蔓延到服务网关上而影响整个系统的对外服务
但是:serviceId方式是依赖Eureka服务发现的。
#forward模式 直接转发至zuul提供的rest服务 这个只能是自己编写的一种处理方式,这个可以用来进行token的解析,解/加密操作
zuul.routes.myDemo.path=/myDemo/**
zuul.routes.myDemo.url=forward:/demo
user2:
path: /user2/**
serviceId: user2
eureka:
client:
service-url:
defaultZone: http://localhost:5001/eureka
这样就可以实现代理服务端了。
下一步就是实现代理过程中的前期、中期、后期的拦截处理。
Zuul 的核心是 Filters,根据执行时期分为以下几类:
PRE:这种过滤器在请求被路由之前调用
ROUTING:这种过滤器将请求路由到微服务
POST:这种过滤器在路由到微服务以后执行
ERROR:在其他阶段发生错误时执行该过滤器
需要编写一个拦截器filter的代码:
package com.example.zuul;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import javax.servlet.http.HttpServletRequest;
public class ZuulFilterTest extends ZuulFilter {
/**
* 这个方法返回过滤器的类型,pre(路由前执行),route(路由中执行),post(路由后执行),error(发生错误后执行)
*
* @return
*/
@Override
public String filterType() {
return "pre";
}
/**
* 这个位置是指返回的数字决定执行顺序 多个拦截器的情况下,返回数值越小越靠前执行。
*
* @return
*/
public int filterOrder() {
return 0;
}
/**
* 返回boolean值来决定过滤器是否执行,true执行,false不执行
*
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 过滤器要执行的操作
*
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
RequestContext rtx = RequestContext.getCurrentContext();
HttpServletRequest request = rtx.getRequest();
Object temp = request.getParameter("temp");
if (temp == null){
rtx.setSendZuulResponse(false); 是否将请求通过:false 不通过 true 通过(默认)
//rtx.setResponseStatusCode(404); 返回一个404页面
rtx.setResponseBody("你的请求被拦截了!"); 返回一个message
System.out.println("你的请求被拦截了!"); 这个位置可以是控制台输出
return null;
}
return null;
}
}
启动类里面需要添加:将写好的filter在初始化的时候进行实例化。
package com.example.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
@Bean
public ZuulFilterTest zuulFilterTest(){
return new ZuulFilterTest();
}
}
路由规则说明
传统路由配置:不依赖服务发现,如nginx
* 单例实例配置:通过zuul.routes.<route>.path和zuul.routes.<route>.url参数对的方式来配置
# 传统路由配置
zuul.routes.server-provide.path=/server-provide/**
zuul.routes.server-provide.url=http://127.0.0.1:1001/
* 多实例配置:通过一组zuul.routes.<route>.path与zuul.routes.<route>.serviceId参数对的方式配置
# 多实例
zuul.routes.server-provide.path=/user-service/**
zuul.routes.server-provide.serviceId=user-service
ribbon.eureka.enabled=false
server-provide.ribbon.listOfServers=http://127.0.0.1:1001/,http://127.0.0.1:1001/
服务路由配置:依赖服务发现,结合Eureka
* 默认规则:http://ZUUL_HOST:ZUUL_PORT/微服务实例名(serverId)/** ,转发至serviceId对应的微服务。
* 自定义路由规则:通过一组zuul.routes.<route>.path与zuul.routes.<route>.serviceId参数对的方式配置
# 自定义路由
zuul.routes.server-provide.path=/server-api/**
zuul.routes.server-provide.serviceId=server-provide
比如:
而且,要注意,这些过滤器是path进行最佳路径匹配的,所以,一般上在一些历史系统上,我们会在最后后面加上一个路径/**的匹配规则,以保证历史api可以使用,做到最大兼容性,避免类似404的异常。
zuul.routes.legacy.path=/**
Zuul实现负载均衡
设置多个服务器,在eureka服务器上注册在一个名称下。zuul通过serviceId代理了端口,eureka实现了注册名称和服务地址的关联。这样就可以实现代理端口的负载均衡了。
但是这个负载均衡是属于客户端的负载均衡。在这我也就简要的说下客户端负载均衡。
客户端负载均衡:
基于客户端的负载均衡,简单的说就是在客户端程序里面,自己设定一个调度算法,在向服务器发起请求的时候,先执行调度算法计算出向哪台服务器发起请求,然后再发起请求给服务器。
特点:
1. 由客户端内部程序实现,不需要额外的负载均衡器软硬件投入。
2. 程序内部需要解决业务服务器不可用的问题,服务器故障对应用程序的透明度小。
3. 程序内部需要解决业务服务器压力过载的问题。
使用场景:
1. 可以选择为初期简单的负载均衡方案,和DNS负载均衡一样。
2. 比较适合于客户端具有成熟的调度库函数,算法以及API等
3. 毕竟适合对服务器入流量较大的业务,如HTTP POST文件上传,FTP文件上传,Memcache大流量写入。
4. 可以结合其他负载均衡方案进行架构。