目录
1 API 网关(zuul)
1.1 zuul简介
Zuul是Spring Cloud全家桶中的微服务API网关。
所有从设备或网站来的请求都会经过Zuul到达后端的Netflix应用程序。作为一个边界性质的应用程序,Zuul提供了动态路由、监控、弹性负载和安全功能。Zuul底层利用各种filter实现如下功能:
- 认证和安全 识别每个需要认证的资源,拒绝不符合要求的请求。
- 性能监测 在服务边界追踪并统计数据,提供精确的生产视图。
- 动态路由 根据需要将请求动态路由到后端集群。
- 压力测试 逐渐增加对集群的流量以了解其性能。
- 负载卸载 预先为每种类型的请求分配容量,当请求超过容量时自动丢弃。
- 静态资源处理 直接在边界返回某些响应。
1.2 zuul准备及初始化配置
服务调用结构

说明:zuul 类似gateway ,可以作为一个服务的转发中心
1.3 统一的调用入口
步骤: 1.新建spring模块:sp06-zuul

2.添加依赖:zuul,sp01,eureka client
<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>
3.yml 配置转发规则
spring:
application:
name: zuul
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
#转发规则
#service-id 作为访问子路径是默认配置,zuul会根据注册表进行相应的配置
#最好手动配置,防止注册表不全
zuul:
routes:
item-service: /item-service/**包含深层路径
item-service: /user-service/**包含深层路径
item-service: /order-service/**包含深层路径
4.启动类注解:@EnableZuulProxy

2 Zuul网关特性
2.1 统一权限校验
通过zuul的过滤器,判断用户权限
- 有权限,继续转发调用
- 没有权限,从网关访问结果
zuul网关结构

说明:前置过滤,路由过滤,后置过滤,异常过滤,消费者过滤
Zuul提供的过滤器是一个父类。父类是ZuulFilter。通过父类中定义的抽象方法filterType,来决定当前的Filter种类是什么。有前置过滤、路由后过滤、后置过滤、异常过滤。
- 前置过滤:是请求进入Zuul之后,立刻执行的过滤逻辑。
- 路由后过滤:是请求进入Zuul之后,并Zuul实现了请求路由后执行的过滤逻辑,路由后过滤,是在远程服务调用之前过滤的逻辑。
- 后置过滤:远程服务调用结束后执行的过滤逻辑。
- 异常过滤:是任意一个过滤器发生异常或远程服务调用无结果反馈的时候执行的过滤逻辑。无结果反馈,就是远程服务调用超时。
代码实例
/**
* Zuul过滤器,必须继承ZuulFilter父类。
* 当前类型的对象必须交由Spring容器管理。使用@Component注解描述。
* 继承父类后,必须实现父类中定义的4个抽象方法。
* shouldFilter、 run、 filterType、 filterOrder
*/
@Component
public class LoggerFilter extends ZuulFilter {
private static final Logger logger = LoggerFactory.getLogger(LoggerFilter.class);
@Override
public boolean shouldFilter() {
return true;
}
/**
* run方法就是过滤器的具体逻辑。
* return 可以返回任意的对象,当前实现忽略。(spring-cloud-zuul官方解释)
* 直接返回null即可。
*/
@Override
public Object run() throws ZuulException {
// 通过zuul,获取请求上下文
RequestContext rc = RequestContext.getCurrentContext();
HttpServletRequest request = rc.getRequest();
logger.info("LogFilter1.....method={},url={}",
request.getMethod(),request.getRequestURL().toString());
// 可以记录日志、鉴权,给维护人员记录提供定位协助、统计性能
return null;
}
/**
* 过滤器的类型。可选值有:
* pre - 前置过滤
* route - 路由后过滤
* error - 异常过滤
* post - 远程服务调用后过滤
*/
@Override
public String filterType() {
return "pre";
}
/**
* 同种类的过滤器的执行顺序。
* 按照返回值的自然升序执行。
*/
@Override
public int filterOrder() {
return 0;
}
}
测试:模拟登录系统
网址说明:
http://localhost:3001/item_service/u56y5g4 没登录,不允许访问
http://localhost:3001/item_service/u56y5g4?token=u6y54t 已登录,可以访问
具体配置:
- 1.继承zuul
- 2.添加@Comment
zuul自动配置类,可以从spring容器自动发现过滤器实例,完成自动配置
代码实现:
@Component
public class AccessFilter extends ZuulFilter {
// pre, routing, post, error
@Override
public String filterType() {
//return "pre";
return FilterConstants.PRE_TYPE;
}
// 过滤器的顺序号
@Override
public int filterOrder() {
// 有5个默认的过滤器,自己的过滤器加到末尾
// 在第5个过滤器中,向Context对象放入了 serviceId,
// 后面组件中,才能访问这个数据
return 6;
}
// 针对当前请求,判断是否要执行过滤代码
// 如果调用 item-service,检查是否登录
// 否则,不检查登录,直接访问
@Override
public boolean shouldFilter() {
// 先获取当前请求的上下文对象
RequestContext ctx = RequestContext.getCurrentContext();
// 当前请求,调用的服务id
String serviceId = (String)
ctx.get(FilterConstants.SERVICE_ID_KEY);// "serviceId"
// 调用的是否是 item-service
return "item-service".equals(serviceId);
}
// 过滤代码
@Override
public Object run() throws ZuulException {
// 获得上下文对象
RequestContext ctx = RequestContext.getCurrentContext();
// 获得 request 对象
HttpServletRequest request = ctx.getRequest();
// http://localhost:3001/item-service/u56y5g4?token=u6y54t
// 接收 token 参数
String token = request.getParameter("token");
// 如果没有 token,阻止继续调用,直接返回响应
// ""、null、" "
if (StringUtils.isBlank(token)) {
// 阻止继续调用
ctx.setSendZuulResponse(false);
// 直接返回响应
// JsonResult --- {code:1,msg:xxx,data:null}
ctx.addZuulResponseHeader(
"Content-Type","application/json;charset=UTF-8");
ctx.setResponseBody(JsonResult
.err()
.code(400)
.msg("Not login! 未登录!")
.toString());
}
return null;// 当前 zuul 版本中,这个返回值没有使用
}
}
测试结果:

2.2 zuul集成rebion
zuul默认启用了负载均衡和重试
- zuul默认启用负载均衡
- zuul默认不启用重试,zuul不推荐启用重试
一般不再网关执行重试,否则,会造成后台大面积服务器压力倍增,重试操作一般在后台服务启动,越往后越高效
zuul启用ribbion重试
1.添加spring-retrey
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
2. yml配置启用zuul重试:zuu1.retryable=true
zuul:
routes:
item-service: /item-service/**
user-service: /user-service/**
order-service: /order-service/**
retryable: true
3.(可选)配置重试参数
#配置格式:
#ribbon:
# MaxAutoRetries: 0
# MaxAutoRetriesNextServer: 1
#对Item-service 配置重试参数
#item-service:
# ribbon:
# MaxAutoRetris: 1
2.3 zuul集成Hystrix (容错,限流)
zuul默认已经启动了Hystrix,可以直接写降级代码
1.实现FallbackProvider 接口
@Component
public class OrderFB implements FallbackProvider {
@Override
public String getRoute() {
return "order-service";
}
2.添加@Compont
zuul 会用自动配置类,对降级类进行自动配置
代码段:
@Component
public class ItemFB implements FallbackProvider {
/*返回一个 service-id,表示当前降级类是针对哪个后台服务的降级类,
- item-service --- 只针对商品服务降级
- * --- 对所有服务都应用这个降级类
- null --- 等同于**/
@Override
public String getRoute() {
return "item-service";
}
//发回客户端的降级对象
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
@Override //获取状态码
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
@Override //获取原始状态码
public int getRawStatusCode() throws IOException {
return HttpStatus.INTERNAL_SERVER_ERROR.value();
}
@Override //获取状态文本
public String getStatusText() throws IOException {
return HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();
}
@Override public void close() { }
@Override public InputStream getBody() throws IOException {
//JsonResult---{code:500,msg:xxx,data:null}
String json = JsonResult.err().code(500).msg("服务调用后台服务出错").toString;
return new ByteArrayInputStream(json.getBytes("Utf-8"));
}
@Override public HttpHeaders getHeaders() {
HttpHeaders h=new HttpHeaders();
h.add("Content-Type", "application/json;charset=UTF-8");
return h;
}
};
}
}
配置文件:
#配置格式:
#ribbon:
# MaxAutoRetries: 0
# MaxAutoRetriesNextServer: 1
#对Item-service 配置重试参数
#item-service:
# ribbon:
# MaxAutoRetris: 1
测试结果:
3 hystrix限流工具(等同sentilel)
3.1 hystrix应用场景——熔断
当流量过大,后台服务出现故障,可以断开后台服务区的链路,等待后台服务恢复
路器的打开条件:
- 10秒20次请求(必须首先满足)
- 50%失败,执行的降级代码
半开状态:
- 断路器打开一段时间后,会进入半开状态
- 会尝试发送一次客户端调用
- 成功,关闭断路器,恢复正常
- 失败,继续保持打开状态
代码测试
测试:
在课前资料中找到httpd-2.4.39-o102r-x86-vc14.zip
解压后进入Apache24\bin,并执行cmd进入doc界面
执行ab -n 20000 -c 50 http://localhost:3001/item-service/35
3.2 Hystrix监控
对Hystrix降级和熔断的情况进行监控,可以通过日志快速定位错误,查找系统中的问题
在06项目中,Hystrix利用actuator来暴露自己的监控日志数据
1.添加actuator依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
2.yml配置暴露监控日志
m.e.w.e.i="*" 暴露所有监控日志
m.e.w.e.i=health.bean,mappings
m.e.w.e.i=hystrix
3.访问localhost:3001/actors
3.3 搭建Hystrix Dashboard
搭建Hystrix Dashboard
1.新建spring 模块:sp07-hystrix dashboard

2.添加依赖:Hytrix Dashboard
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
3. yml:
server:
port: 4001
hystrix:
#允许抓取的数据服务器列表
dashboard:
proxy-stream-allow-list: localhost
允许抓取的服务器列表:localhost,a,b,c
4.启动类注解:@EnableHysteixDashboard
5.访问:localhost:4001/hystrix 在输入框中填写日志数据的地址
4 总结
API网关(zuul)
zuul网关可以对转发调用不同服务模块的请求。并能在服务执行前后进行预处理,是一个较为普遍的转发调用的服务中心,除此外,zuul还默认集成调用了rabbion和hystrix,可以通过配置文件的配置实现相应的转发和调用功能。
配置转发规则
zuul网关转发调用实现在于配置文件的配置,通过配置文件配置对哟的文件路径,以实现转发和调用,具体的代码展示如下:
zuul:
routes:
item-service: /item-service/**
user-service: /user-service/**
order-service: /order-service/**
retryable: true
统一权限校验
统一权限校验是指通过zuul的过滤器,判断用户权限,有权限,继续转发调用,没有权限,从网关访问定义好的结果的一个过程,这也是用户在的登录成功或失败是后端对应的功能实现,通过统一的权限校验,用户可以更为便捷的进行相应的访问和调用。
Hystrix监控,限流,熔断
对Hystrix降级和熔断的情况进行监控,可以通过日志快速定位错误,查找系统中的问题
此外,Hystrix也是实现多用户访问时的一个极好的限流和熔断工具。
本文详细介绍了Spring Cloud Zuul作为API网关的使用,包括Zuul的基本概念、配置转发规则、统一权限校验的实现,以及如何集成Ribbon进行负载均衡和Hystrix进行容错、限流。通过代码实例展示了Zuul过滤器的编写,以及如何处理未登录用户的请求。同时,文章还探讨了Hystrix监控和搭建HystrixDashboard的步骤,帮助读者深入理解Zuul在微服务架构中的重要角色。

4085

被折叠的 条评论
为什么被折叠?



