06-微服务网关zuul
06-微服务网关zuul
微服务网关zuul开发
一. 微服务网关介绍和使用场景
1. 什么是网关
API Gateway,是系统的唯一对外的入口,介于客户端和服务器端之间的中间层,处理非业务功能 提供路由请求、鉴权、监控、缓存、限流等功能
统一接入
智能路由
AB测试、灰度测试
负载均衡、容灾处理
日志埋点(类似Nignx日志)
流量监控
限流处理
服务降级
安全防护
鉴权处理
监控
机器网络隔离
2. 主流的网关
zuul:是Netflix开源的微服务网关,和Eureka,Ribbon,Hystrix等组件配合使用,Zuul 2.0比1.0的性能提高很多
kong: 由Mashape公司开源的,基于Nginx的API gateway
nginx+lua:是一个高性能的HTTP和反向代理服务器,lua是脚本语言,让Nginx执行Lua脚本,并且高并发、非阻塞的处理各种请求
二. springCloud网关组件zuul的基本使用
1. 主要依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
2. 启动类加入注解
@EnableZuulProxy
3. 访问规则
-
默认访问
http://gateway:port/service-id/**
例如:localhost:9000/order-service/api/v1/.. -
自定义路由转发
在配置文件中添加
zuul:
routes:
order-service: /order/**注意事项
**代表所有字符包括/
*代表所有字母数字下划线(不包括/)这里有个坑,同一个地址只能被一个服务所用,如果不同服务用了同一路由,前面配置的不能使用,即路由覆盖问题
有两种配置方式(待定)
第一种:order-service: /order/**
第二种: zuul.routes.order.path=/order/**
zuul.routes.order.serviceId=order-service
即分别指定service-id和路径 -
环境隔离配置
ignored-patterns: /*-service/** 忽略包含-service的全部请求
prefix: /apigateway 所有请求前缀必须加上apigateway
例如:http://localhost:9000/apigateway/product/api/v1/product/list
三. 高级篇幅之Zuul常用问题分析和网关过滤器原理分析
必要时可以查看zuul源码,在ZuulProperties.class中配置
1. 路由名称定义问题
路由映射重复覆盖问题(见上)
2. Http请求头过滤问题
如果使用zuul网关,cookie在后台会被zuul过滤掉,可以参考源码所示:
解决方案
在配置文件中加入如下配置:zuul:
sensitiveHeaders:
即将默认的sensitiveHeaders清空
3. 过滤器执行问题
zuul执行流程如下图
过滤器order越小,越先执行
4. 共享RequestContext,上下文对象
四. 自定义Zuul过滤器实现登陆鉴权
Zuul实际上就是一堆Filter的集合
1. 创建继承了ZuulFilter的自定义类
public class LoginFilter extends ZuulFilter {}
2. 重写抽象方法,并加注解
@Component
public class LoginFilter extends ZuulFilter {
@Override
public String filterType() {
return null;
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return false;
}
@Override
public Object run() throws ZuulException {
return null;
}
}
3. 分别编写每个方法
filterType 过滤器类型,分为pre,post,route,error 可以参考FilterConstants这个类
filterOrder 过滤器顺序,越小越先执行
shouldFilter 过滤器是否生效
run 生效后执行的业务逻辑
完整代码如下
@Component
public class LoginFilter extends ZuulFilter {
/**
* 选择过滤类型(pre,post,route,error)
* @return
*/
@Override
public String filterType() {
return PRE_TYPE;
}
/**
* 过滤器顺序,越小越先执行
* @return
*/
@Override
public int filterOrder() {
return 4;
}
/**
* 过滤器是否生效
* @return
*/
@Override
public boolean shouldFilter() {
//ACL
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
if("/apigateway/order/api/v1/order/save/save".equalsIgnoreCase(request.getRequestURI())){
return true;
}
return false;
}
/**
* 业务逻辑
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
//JWT
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
String token = request.getHeader("token");
if(StringUtils.isBlank(token)){
token = request.getParameter("token");
}
if(StringUtils.isBlank(token)){
requestContext.setSendZuulResponse(false);
requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
}
return null;
}
4. 细节整理
-
requestContext
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();用来在zuul中获取request对象 requestContext为上下文
-
其他
requestContext.setSendZuulResponse(false); 设置是否继续发送请求到下游服务器,即是否拦截,false为拦截
requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); 可以使用Spring封装好的状态码
五. 高级篇幅之高并发情况下接口限流特技
使用Google的Guava框架做限流处理
1. nginx层限流
2. 网关层限流
1. 原理分析
在木桶里每秒放一定数量的令牌,表示最大的承载量,有请求进入时一次取一个,如果取完了,说明达到了最大的承载量,则该请求被抛弃,达到限流的目的.
2. 代码编写
@Component
public class OrderRateLimiterFilter extends ZuulFilter {
//每秒产生1000个令牌
private static final RateLimiter RATE_LIMITER = RateLimiter.create(1000);
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public int filterOrder() {
return -4;
}
@Override
public boolean shouldFilter() {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
//只对订单接口做限流
if("/apigateway/order/api/v1/order/save/save".equalsIgnoreCase(request.getRequestURI())){
return true;
}
return false;
}
@Override
public Object run() throws ZuulException {
RequestContext requestContext = RequestContext.getCurrentContext();
if(!RATE_LIMITER.tryAcquire()){
requestContext.setSendZuulResponse(false);
requestContext.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
}
return null;
}
}
六. Zuul微服务网关集群搭建
- nginx + lvs + keepalive