Zuul
1.集成了Ribbon
2.集成了Hystrix(流量防卫兵)
3.就相当于一个代理
4.基于过滤器
5.统一的请求入口
6.统一权限校验
使用步骤:
1.先建spring模块
2.pom.xml 添加 zuul + eureka client + sp01-commons
3.yml
zuul:
route:
item-service: /item-service/**
user-service: /user-service/**
order-service: /oreder-service/**
4.启动类添加注解: @EnableZuulProxy
统一的权限校验:
1.首先去先建一个AccessFilter 继承ZuulFilter(过滤器的父类)
2.按规则实现
3.添加@Component 注解
4.zuul默认有5个过滤器
5.重写ZuulFilter中的4个抽象方法
filterType(返回值为String):设置这个过滤器的类型
(return "pre" ;return FilterConstants.PRE_TYPE;这两种都可以指定过滤器类型)
filterOrder(返回类型:int): 设置过滤器的执行顺序(只能往后加过滤器,不能往这五个之前加)retrun 就是顺序
shouldFliter(返回类型:Boolean) :针对当前请求是否执行下面的过滤
run(Object):对应的过滤代码
完成拦截器:(举个栗子,只有登录了带有token才可以去访问商品服务)
1.设定过滤器类型为pre
2.设置该浏览器执行顺序为6
3.分析业务,当请求商品服务的时候,要对其进行判断权限,请求其他模块的时候不需要进行验证直接访问,所以我们要在shouldFilfter中进行业务逻辑的书写,通过RequsetContext对象获去上下文对象(通过该对象的.getCurrentContext()可以获取上下文返回值类型为RequestContext)紧接着通过上下文信息对象去获取serviceId也就是服务名,【上下文对象.get(FilterConstants.SERVICE_ID_KEY)获取到对应的服务名,返回值是Object,要强转为String类型】,最后比对ServiceId是否等于商品服务对应的服务名,若相同返回true,执行run方法,若不相等返回false,直接放行
4.完成run方法,这个方式是当shouldFliter为true的时候才会调用,根据业务,我们首先也要获取上下文对象,(重复上个方法的操作),但我们这次要比对的是token的值是否有,通过上下文对象的方法getRequest()获取请求的信息对象(返回值是一个HttpServletRequest类型),通过这个请求信息对象使用方法getParameter("要获取的信息名")在这个业务就要这样写【getParameter("token")返回值是一个String】
StringUtils的两个Api:
.isBlank可以判断一个字符串是否为 null / ""(空串) / " "(里面只有空格) 符合返回TRUE, 反之返回False
.isEmpty可以判断一个字符串是否为 null 与 空串 返回一样Boolean类型,规则同上
5.还是在run方法中去判断token是否存在于这个请求中,通过StringUtils.isBlank(token)去做判断
若是空的或者为null就去阻止这个请求后续的调用通过:
currentContext/*该请求的上下文信息对象*/.setSendZuulResponse(false); //false表示阻止,true表示放行
做完上述操作,要对返回客户端的数据进行定义,第一步告诉客户端返回的数据是啥类型的
currentContext/*(该请求的上下文信息对象)*/.addZuulResponseHeader("Context-type","application/json;charset=utf8"); /*"Context-type","application/json;charset=utf8"这段代码的意义在于写响应的头,确定了返回值类型为json,编译用utf8*/
第二步:将响应转换为json格式的字符串进行传递给前端,我们使用的是通用服务里的JsonResult对象进行封装,其有一个静态方法,.build(状态码,提示信息)返回值类型为String。
第三步:currentContext/*(该请求的上下文信息对象)*/.setResponseBody(json)
上一步方法在于设置响应体里的东西 。注意:这个run方法有个return,当前zuul版本没有使用这个返回值,返回啥都是无效的,就是反不返回都可以,作者为了zuul后续版本的更新
- 默认启用负载均衡
- 默认不启用重试
- 在网关启用重试会使后台服务压力倍增,大面积出现故障‘’
- 启用重试(不推荐)1.添加依赖:spring-retry依赖 2.yml配置 zuul.retryable = true
Hystrix(与sentinel功能类似)
系统容错和限流工具 (两个手段降级限流)
- 容错 - 通过降级来容错 容错是处理错误的,执行降级
- 限流 - 通过熔断来限流 过热保护,断开链路
- 流量过大,后台服务出现故障,通过熔断,限制后台服务的流量
- 熔断的条件:自动触发的
- 10秒内,达到20次请求,就会认为请求过大 (要首先满足,才回去检查下一个条件)
- 50%出错,执行降级代码
- 断路器(全自动打开与关闭,不需要任何配置)打开后(拉闸),会进入半开状态,尝试向后台服务发一次客户端请求
- 调用成功,关闭断路器(合闸)
- 调用失败,继续保持打开状态(拉闸)
Zuul集成了Hystrix实现容错(降级)
Zuul默认已经启用了Hystrix
怎么实现降级呢:
1.在zuul网关这个服务中新建一个降级类,实现FallbackProvider 接口
2.添加@Component注解 将这个降级类加入到spring容器进行管理
3.这个降级类中里面要实现接口的两个方法 getRoute是指定要进行过滤的类
/*
* 设置对那个服务应用进行降级
* item-service 只针对一个服务降级
* “*” 所有服务都应用当前降级类
* null 所有服务都应用当前降级类
*
*/
@Override
public String getRoute() {
return "item-service";
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
//状态码 HttpStatus 状态码 + 状态信息
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
// RawStatusCode 单独返回上面的状态码
@Override
public int getRawStatusCode() throws IOException {
return HttpStatus.INTERNAL_SERVER_ERROR.value();
}
//StatusText 单独返回HttpStatus 中的状态信息
@Override
public String getStatusText() throws IOException {
return HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();
}
@Override
public void close() {
// 用来关闭InputStream
// ByteArrayInputStream 不占用底层系统资源,不需要关闭,在JVM内存里面的Byte数组
}
@Override
public InputStream getBody() throws IOException {
String json = JsonResult.build(500, "调用后台服务出错", null).toString();
//将json封装到一个输入流中,使用ByteArrayInputStream
ByteArrayInputStream s = new ByteArrayInputStream(json.getBytes("UTF-8"));
return s;
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders h = new HttpHeaders();
h.add("Content-type", "application/json;charset=UTF-8");
return h;
}
};
}
- zuul的自动配置,会自动发现降级类的实例,自动完成配置
Hystrix数据监控
1.用actuator(导入zuul时已经导入了)暴露Hystrix的监控数据 默认是输出health 和 info等级
1.健康状态
2.spring容器中的所有对象
3.spring mvc 的所有路径
4.java虚拟机的堆内存镜像
5.hystrix利用actuator暴露了自己的监控日志数据
请求:http://localhost:3001/actuator 显示actuator的目录,里面有对应的网址可以查看数据
Hystrix Dashboard 监控图表
1.新建Spirng模块:sp07-hysrtix-dashboard
2.在Dashboard服务中添加依赖:hystrix-dashboard 并且让其称为父项目的子项目
3.yml 允许抓取的服务器列表
4.启动类注解:@EnableHystrixDashboard
访问:http://localhost:4001/hystrix 就可以去看到进行监控的服务的图表,但当服务没有访问的时候也不会自动显示
网关也要高可用,
知识点:想要监控多个服务器的日志,怎么办,引入Turbine,这个组件可以从多个服务器抓取日志进行聚合
怎么使用Turbine:
1.新建Turbine模块
2.pom.xml
1.添加turbine依赖
spring-cloud-starter-netflix-turbine
2.添加Eureka依赖(因为要去注册表获取服务的地址,才能实现监控)
spring-cloud-starter-netflix-eureka-client
3.yml配置
1.聚合的服务: zuul (若有多个服务逗号隔开)
2.为聚合后的数据进行命名: new String("default")(默认的就是default,格式必须这么写)
pring:
application:
name: turbin
server:
port: 5001
eureka: #添加eureka客户端的配置
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
turbine: #设定turbine要聚合的服务
app-config: zuul #服务多了就用逗号隔开
cluster-name-expression: new String("default")
4.启动类注解: @EnableTurbine
1.聚合日志的地址: http://localhost:5001/turbine.stream