文章目录
添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
配置yml
zuul:
routes:
# ** 包含深层子路径
# * 只包含一层路径
# service-id 作为访问子路径,是默认设置
# 根据注册表中的注册信息,zuul可以自动配置
# 最好自己手动配置,防止注册表不全
item-service: /item-service/**
user-service: /user-service/**
order-service: /order-service/**
启动类添加注解
@EnableZuulProxy
自定义zuul过滤器
package cn.tedu.sp06.filter;
import cn.tedu.web.util.JsonResult;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class AccessFilter extends ZuulFilter {
//过滤器位置,前置,后置。。。
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;//也可直接reture "pre";
}
//设置顺序号,插入的位置
@Override
public int filterOrder() {
//前置过滤器中有5个默认的过滤器,自定义过滤器放到末尾
return 6;
}
//针对当前请求是否要执行下面的过滤代码
@Override
public boolean shouldFilter() {
/*测试:
* 调用商品,需要判断权限
* 调用用户或订单不检查权限
* */
//获得一个请求上下文对象
RequestContext ctx = RequestContext.getCurrentContext();
//从上下文对象获得调用的后台服务的serviceid
String serviceId =
(String)ctx.get(FilterConstants.SERVICE_ID_KEY); //"serviceid"
//如果调用的是 item-service,返回true
return "item-service".equals(serviceId);
}
//过滤代码
@Override
public Object run() throws ZuulException {
// http://localhost:3001/item-service/iuy4tgf3?token=uy4t34t
// 获得上下文对象
RequestContext ctx = RequestContext.getCurrentContext();
// 获得 request 对象
HttpServletRequest request = ctx.getRequest();
// 接收 token 参数
String token = request.getParameter("token");
// 如果 token 不存在: null, "", " "
if (StringUtils.isBlank(token)) {
// 阻止继续调用
ctx.setSendZuulResponse(false);//发送zuul相应关闭
// 直接返回响应
String json = JsonResult.build().code(400).msg("Not Login,未登录").toString();
ctx.addZuulResponseHeader("Content-Type", "application/json;charset=UTF-8");
ctx.setResponseBody(json);
}
return null;//zuul当前版本这个返回值不起任何作用
}
}
配置重试
默认zuul是关闭重试的
添加依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
</dependencies>
配置yml
zuul:
routes:
# ** 包含深层子路径
# * 只包含一层路径
# service-id 作为访问子路径,是默认设置
# 根据注册表中的注册信息,zuul可以自动配置
# 最好自己手动配置,防止注册表不全
item-service: /item-service/**
user-service: /user-service/**
order-service: /order-service/**
# 配置重试
retryable: true
# 对所有服务都有效
ribbon:
MaxAutoRetries: 1
# 对item-service单独配置
item-service:
ribbon:
MaxAutoRetries: 0
zuul默认集成Hystrix
Hystrix是容错和限流工具
- Hystrix容错:降级
- Hystrix限流:熔断
Zuul 网关使用 Hystrix 进行容错处理,执行降级
Zuul 默认已经启用Hystrix,任何基础配置都不用做
调用后台服务失败,执行前面模块中的降级代码,向客户端返回降级结果
错误提示
缓存数据
根据业务逻辑,返回任何结果都可以
新建降级类 ItemFB,实现 FallbackProvider 接口
添加注解 @Component
Zuul的自动配置,可以自动发现降级类实例,完成自动配置
实现FallbackProvider类
熔错降级处理
package cn.tedu.sp06.fb;
import cn.tedu.web.util.JsonResult;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@Component
public class ItemFb implements FallbackProvider {
/*
* 设置针对哪个后台服务进行降级
* - 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() {
//用来关闭下面的流
//BAIS不占用底层系统资源,不需要关闭
}
@Override
public InputStream getBody() throws IOException {
String json = JsonResult.build()
.code(500)
.msg("后台服务器出错,请稍后重试")
.toString();
//字符串变成byte[]数组,封装到BAIS
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;
}
};
}
}
zuul集成Hystrix断路器实现限流,熔断
当流量过大,后台服务出现故障,可以udankai链路,限制后台故障服务的流量,等待它从故障中恢复
- 断路器打开条件:
- 10秒20次请求(必须首先满足)
- 50%请求出错,执行了降级代码
断路器打开后,会进入半开状态
在半开状态下,会向后台服务尝试发送一次客户端调用
调用成功,自动关闭断路器恢复正常
调用失败,继续保持打开状态
actuator
- http://localhost:3001/actuator
从eureka网关暴露日志路径
配置3001服务的yml
# 暴露 actuator 监控指标
management:
endpoints:
web:
exposure:
include: "*" # 暴露所有指标
Hystrix dashboard 仪表盘
新建项目,添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
配置yml
server:
port: 4001
hystrix:
dashboard:
# 允许抓取的服务器列表
proxy-stream-allow-list: localhost
启动类上加注解
@EnableHystrixDashboard
访问
http://localhost:4001/hystrix