文章目录
八、Netflix Zuul 服务网关
8.1 Zuul 网关简介
8.1.1 什么是网关
在我们的微服务架构中,调用链路错综复杂,我们来简单看一些服务中的调用:
在分布式环境下,由于项目都被拆分成了若干的微服务,造成用户原本只需要请求一次就可以完成的业务,现在需要请求多个微服务来完成业务功能,如果客户端直接和微服务进行通信,会存在以下问题:
-
客户端会多次请求不同微服务,增加客户端的复杂性
-
存在跨域请求,在一定场景下处理相对复杂
-
认证复杂,每一个服务都需要独立认证
-
难以重构,随着项目的迭代,可能需要重新划分微服务,如果客户端直接和微服务通信,那么重构会难以实施
上述问题,都可以借助微服务网关解决。微服务网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过微服务网关。
8.1.2 什么是Zuul
Zuul 是 Netflix 开源的微服务网关,他可以和 Eureka,Ribbon,Hystrix等组件配合使用。Zuul组件的核心是一系列的过滤器,这些过滤器可以完成以下功能:
- 单点入口
- 动态路由
- 限流熔断
- 统一认证
- 日志监控
Spring Cloud 对 Zuul 进行了整合和增强。
引入了 Zuul网关 后,架构图演变为以下形式:
Github官网:https://github.com/Netflix/Zuul
8.2 Zuul 快速入门
8.2.1 搭建Zuul网关工程
1)引入依赖:
<!--zuul网关依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
2)编写application.yml:
server:
port: 10102
spring:
application:
name: zuul-server
3)启动类:
package com.cloud.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
/**
* @author lscl
* @version 1.0
* @intro:
*/
@EnableZuulProxy // 开启Zuul网关代理
@SpringBootApplication
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class);
}
}
8.2.2 Zuul网关路由规则
1)URL地址路由
zuul:
routes:
item-service: # 路由Id,名称任意
path: /item-service/** # 这里是映射路径
url: http://localhost:9000 # 映射路径对应的实际url地址
- 通配符匹配规则:
通配符 | 说明 | 举例 | 示例 |
---|---|---|---|
? | 匹配任意单个字符 | /item-service/? | /item-service/a |
* | 匹配任意数量字符但不包含子路径 | /item-service/* | /item-service/abc |
** | 匹配任意数量的字符包括下属的所有路径 | /item-service/** | /item-service/abc/abc |
访问:http://localhost:10102/item-service/item/findOrderById/1
2)服务名称路由
微服务一般是由几十、上百个服务组成,对于一个URL请求,最终会确认一个服务实例进行处理。如果对每个服务实例手动指定一个唯一访问地址,然后根据URL去手动实现请求匹配,这样做显然就不合理。
Zuul支持与Eureka整合开发,根据ServiceID自动的从注册中心中获取服务地址并转发请求,这样做的好处不仅可以通过单个端点来访问应用的所有服务,而且在添加或移除服务实例的时候不用修改Zuul的路由配置。
1)添加Eureka的依赖:
<!--引入eureka客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2)在ZuulApplication引导类上添加注解:
@EnableEurekaClient
@EnableDiscoveryClient
3)修改application.yml:
server:
port: 10102
spring:
application:
name: zuul-server
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10101/eureka # 注册到Eureka
instance:
prefer-ip-address: true # 使用ip地址注册服务(默认情况下是以主机注册)
instance-id: 127.0.0.1:${server.port} # 实例id
zuul:
routes:
item-service: # 路由Id,名称任意
path: /item-service/** # 这里是映射路径
serviceId: item-service # 将拦截到的请求转发到当前微服务
再次访问:http://localhost:10102/item-service/item/findOrderById/1
tips:服务名称路由的前提条件是服务必须首先注册到Eureka注册中心,然后根据服务名路由,URL路由则可以跳转到任意网站;
3)简化路由配置
当路由id与微服务名称一致时,我们可以不写serviceId,默认取路由id为微服务名称
zuul:
routes:
item-service: # 路由Id,名称任意
path: /abc/** # 这里是映射路径
再次访问:http://localhost:10102/abc/item/findOrderById/1
4)默认路由配置
如果路由id与path路径与微服务名称三者一致时,那么zuul网关的路由配置可以省略,三者默认都为微服务名称,把zuul路由的配置去掉:
#zuul:
# routes:
# item-service: # 路由Id,名称任意
# path: /item-service/** # 这里是映射路径
# serviceId: item-service # 将拦截到的请求转发到当前微服务
访问:http://localhost:10102/item-service/item/findOrderById/1,http://localhost:10102/order-service/order/1
5)路由前缀
zuul:
routes:
item-service: # 路由Id,名称任意
path: /item-service/** # 这里是映射路径
serviceId: item-service # 将拦截到的请求转发到当前微服务
prefix: /api
http://localhost:10102/api/item-service/item/findOrderById/1
8.2.3 路由排除
1)URL地址排除
zuul:
ignored-patterns: /**/item/findOrderById/**,/**/order/** # 忽略这两个路径 多个路径用,隔开
routes:
item-service: # 路由Id,名称任意
path: /item-service/** # 这里是映射路径
serviceId: item-service # 将拦截到的请求转发到当前微服务
2)服务名排除
根据服务名指定该服务不进行路由转发(只能忽略默认路由配置)
zuul:
ignored-services: order-service # order-service的服务请求不进行路由,多个服务用,隔开
3)请求头排除
关于请求头排除的配置有ignored-headers
、sensitiveHeaders
ignored-headers
:默认情况下,我们自己携带的请求头都会被传递到下游服务,通过ignored-headers
参数可以过滤掉一些不需要传递的请求头;
配置方式:
zuul:
ignored-headers: flag_a # 忽略flag_a请求头,flag_a请求头将不会被传递到下游服务
sensitiveHeaders
:和ignored-headers
作用一致,配置拦截下来的请求头,默认情况下Cookie
、Set-Cookie
、Authorization
请求头将被拦截;
配置方式:
zuul:
routes:
item-service: # 路由Id,名称任意
sensitiveHeaders: [] # 针对某个微服务配置,放行Cookie、Set-Cookie、Authorization等请求头
path: /item-service/** # 这里是映射路径
serviceId: item-service # 将拦截到的请求转发到当前微服务
sensitiveHeaders: [] # 全局配置
ignored-headers
只能全局配置,不能局部配置,sensitiveHeaders
可以全局配置和局部配置;
- 测试请求头传递,扩展ItemController:
/**
* 测试zuul传递请求头和Cookie
*
* @param request
* @return
*/
@PostMapping("/testHeader")
public Map testHeader(HttpServletRequest request) {
return new HashMap() {{
put("flag_a", request.getHeader("flag_a"));
put("flag_b", request.getHeader("flag_b"));
put("cookie", Arrays.asList(request.getCookies() == null ? "null" : request.getCookies()));
}};
}
使用Postman发送请求:http://localhost:10102/item-service/item/testHeader
tips:此时zuul并没有配置任何的请求头过滤;
- 配置zuul请求头过滤:
zuul:
routes:
item-service: # 路由Id,名称任意
ignored-headers: flag_a # ignored-headers局部过滤是不生效的
sensitiveHeaders: [] # 将这里设为空,放行Cookie、Set-Cookie、Authorization等请求头
path: /item-service/** # 这里是映射路径
serviceId: item-service # 将拦截到的请求转发到当前微服务
再次访问:http://localhost:10102/item-service/item/testHeader
配置全局忽略:
zuul:
routes:
item-service: # 路由Id,名称任意
path: /item-service/** # 这里是映射路径
serviceId: item-service # 将拦截到的请求转发到当前微服务
ignored-headers: flag_a
sensitiveHeaders: []
8.3 Zuul 的过滤器
在Zuul包含有两大核心功能,第一个是路由,另一个就是过滤器了,路由可以对客户端访问的URL进行跳转,过滤器则是对整个请求的一些拦截操作;在Zuul中提供有一系列内置的过滤器,也可以让用户自定义编写过滤器来实现自身业务的功能;
8.3.1 过滤器的执行流程
在Zuul中提供有4种过滤器,分别为pre
、route
、post
、error
pre
:在请求被路由之前调用;route
:将要进行路由时调用(路由之前调用,只不过比pre
过滤器后执行)post
:路由调用完毕或error
过滤器之后执行error
:在其他过滤器出现异常时执行;
8.3.2 自定义过滤器
如果我们想要自定义一个过滤器可以继承ZuulFilter抽象类:
package com.cloud.zuul.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;
/**
* @author lscl
* @version 1.0
* @intro:
*/
@Component
public class PreFilter extends ZuulFilter {
/**
* 执行时机
* pre: 在路由到下游微服务之前执行
* route: 在路由到下游微服务之前执行(在pre过滤器之后)执行
* post: 执行完了下游微服务的逻辑之后来到post过滤器
* error: 在其他过滤器执行出现异常的时候执行error过滤器
*
* @return
*/
@Override
public String filterType() {
return "pre";
}
/**
* 执行顺序
* 数字越大,优先级越低
*
* @return
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 是否执行该过滤器
* true:执行
* false:不执行
*
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 过滤器执行逻辑
*
* @return 返回null代表放行, 访问对应的微服务
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
System.out.println("PreFilter...." + System.currentTimeMillis());
return null;
}
}
定义四个过滤器,类型分别为pre、route、post、error,发送请求查看执行顺序
8.3.3 Zuul的异常处理
在Zuul网关的众多过滤器中,如果有某个过滤器出现了异常,虽然会执行我们自定义的Error过滤器,但是错误响应信息却不能被我自定义,我们需要禁用Zuul网关提供的错误过滤器,如果出现了异常,则使用我们自己的过滤器,定制错误响应信息:
编写一个Error类型的过滤器:
package com.cloud.zuul.filter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
/**
* @author lscl
* @version 1.0
* @intro:
*/
@Component
public class ErrorFilter extends ZuulFilter {
@Override
public String filterType() {
return "error";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
System.out.println("error...");
// Zuul网关提供的上下文对象
RequestContext context = RequestContext.getCurrentContext();
// 终止请求往下执行
context.setSendZuulResponse(false);
// 状态码
context.setResponseStatusCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
HttpServletResponse response = context.getResponse();
// 自定义响应内容
HashMap jsonMap = new HashMap() {{
put("flag", true);
put("statusCode", "500");
put("message", HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase());
}};
response.setContentType("application/json;charset=utf8");
try {
response.getWriter().write(new ObjectMapper().writeValueAsString(jsonMap));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
在Pre过滤器中触发异常:
package com.cloud.zuul.filter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.bouncycastle.asn1.ocsp.ResponseData;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
/**
* @author lscl
* @version 1.0
* @intro:
*/
@Component
public class PreFilter extends ZuulFilter {
/**
* 执行时机
* pre: 在进入微服网关之间执行
* route: 在执行微服务网关时执行
* post: 在执行微服务网关之后执行
* error: 在执行微服务出错执行
*
* @return
*/
@Override
public String filterType() {
return "pre";
}
/**
* 执行顺序
* 数字越大,优先级越低
*
* @return
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 是否执行该过滤器
* true:执行
* false:不执行
*
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 过滤器执行逻辑
*
* @return 访问对应的微服务
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
System.out.println("PreFilter...." + System.currentTimeMillis());
// 触发异常
int i=1/0;
return null;
}
}
发现错误信息不是我们自定义的错误响应;
- 禁用Zuul默认的Error过滤器:
zuul:
SendErrorFilter:
error:
disable: true
重启Zuul网关,重新访问:
8.3.4 Zuul统一鉴权
设计一个微服务网关,前端传递token=1,否则进行拦截:
package com.cloud.zuul.filter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
/**
* @author lscl
* @version 1.0
* @intro:
*/
@Component
public class PreFilter extends ZuulFilter {
/**
* 执行时机
* pre: 在进入微服网关之间执行
* route: 在执行微服务网关时执行
* post: 在执行微服务网关之后执行
* error: 在执行微服务出错执行
*
* @return
*/
@Override
public String filterType() {
return "pre";
}
/**
* 执行顺序
* 数字越大,优先级越低
*
* @return
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 是否执行该过滤器
* true:执行
* false:不执行
*
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 过滤器执行逻辑
*
* @return 访问对应的微服务
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
System.out.println("PreFilter...." + System.currentTimeMillis());
// Zuul网关提供的上下文对象
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
HttpServletResponse response = context.getResponse();
// 获取提交的token
String token = request.getParameter("token");
response.setContentType("application/json;charset=utf8");
if(!"1".equals(token)){
// 终止请求
context.setSendZuulResponse(false);
HashMap jsonMap = new HashMap() {{
put("flag", true);
put("statusCode", "500");
put("message","权限不足");
}};
// 设置响应体
try {
context.setResponseBody(new ObjectMapper().writeValueAsString(jsonMap));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
// return方法,为了防止代码往下执行,返回值随意
return null;
}
return null;
}
}
访问:http://localhost:10102/item-service/item/findOrderById/1
8.4 Zuul 实现服务降级
在Zuul中提供了FallbackProvider
接口,来帮助我们实现Zuul在路由时进行服务降级,需要注意的是,Zuul提供的服务降级只针对于timeout超时情况的降级,如果路由到的具体下游服务出现异常,那么不会触发Zuul的降级处理,应该由具体微服务来提供降级处理;
Tips:在Edgware版本之前(不含),Zuul降级接口为
ZuulFallbackProvider
,从Edgware后(含),Zuul提供FallbackProvider
来提供降级处理;
修改ItemController:
@GetMapping("/findOrderAll")
public Map findOrderAll() {
// 模拟线程阻塞
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Map resultMap = restTemplate.getForObject("http://order-service/order/", Map.class);
return resultMap;
}
1)降级处理类
- 在Zuul网关服务编写降级类:
package com.cloud.zuul.fallback;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.HashMap;
/**
* @author lscl
* @version 1.0
* @intro:
*/
@Component
public class ItemFallBack implements FallbackProvider {
/**
* 需要降级的服务名称 '*'表示为所有服务提供降级
*/
@Override
public String getRoute() {
return "item-service";
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
/**
* ClientHttpResponse 的 fallback 的状态码 返回HttpStatus
*/
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
/**
* ClientHttpResponse 的 fallback 的状态码 返回 int
*/
@Override
public int getRawStatusCode() throws IOException {
return getStatusCode().value();
}
/**
* ClientHttpResponse 的 fallback 的状态码 返回 String
*/
@Override
public String getStatusText() throws IOException {
return getStatusCode().getReasonPhrase();
}
/**
* 设置响应体
*/
@Override
public InputStream getBody() throws IOException {
HashMap jsonMap = new HashMap() {{
put("flag", true);
put("statusCode", "500");
put("message", "服务器忙,请稍后重试!");
}};
String jsonResult = new ObjectMapper().writeValueAsString(jsonMap);
return new ByteArrayInputStream(jsonResult.getBytes());
}
/**
* 设置响应的头信息
*/
@Override
public HttpHeaders getHeaders() {
HttpHeaders httpHeaders = new HttpHeaders();
MediaType mediaType = new MediaType("application", "json", Charset.forName("utf-8"));
httpHeaders.setContentType(mediaType);
return httpHeaders;
}
@Override
public void close() {
}
};
}
}
访问:http://localhost:10102/item-service/item/findOrderAll
2)修改超时设置
Zuul的路由转发是通过Ribbon来转发实现的,因此超时设置是通过Ribbon的超时设置来控制的:
- 在ZuulServer中的application.yml配置:
ribbon:
ReadTimeout: 4000 # zuul路由到具体微服务,微服务响应的时间
ConnectTimeout: 4000 # zuul路由到具体微服务的连接时间
Tips:默认情况下,如果没有配置降级,超时则执行Error类型的Filter来处理;
8.5 Zuul 整合Hystrix DashBoard
我们搭建微服务网关后,由于网关提供了下游服务的统一路口,请求都是由网关统一路由到下游服务,我们可以通过之前学习过的Hystrix仪表盘来监控网关达到监控各个微服务的调用情况;
8.5.1 搭建DashBoard工程
1)引入Dash Board依赖:
<!--dashboard监控依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
2)编写配置:
server:
port: 8888
hystrix:
dashboard:
proxy-stream-allow-list: "localhost" # 允许本机访问
3)启动类:
package com.cloud.dashboard;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
/**
* @author lscl
* @version 1.0
* @intro:
*/
@EnableHystrixDashboard // 开启DashBoard仪表盘
@SpringBootApplication
public class DashBoardApplication {
public static void main(String[] args) {
SpringApplication.run(DashBoardApplication.class);
}
}
8.5.2 修改Zuul网关工程
1)引入actuator依赖:
<!--SpringBoot监控依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2)开放端点:
management:
endpoints:
web:
exposure:
include: '*' # 开放所有监控端点
8.5.3 测试
访问DashBoard工程:http://localhost:8888/hystrix
访问:http://localhost:10102/actuator/hystrix.stream
访问任意接口:http://localhost:10102/item-service/item/findOrderById/1?token=1
查看Hystrix DashBoard:
8.6 Zuul 服务限流
我们都知道Zuul是所有服务的入口,Zuul提供了一套完善的服务限流机制,在访问量过大时,我们可以通过Zuul提供的限流机制来对大流量进行限流处理,保护下游服务;
任何的服务都应该流量限制功能,在防止流量异常激增导致下游服务出现雪崩等情况,如:
- 双十一、618等
- 微博热搜
- 秒杀活动
- 恶意请求等
上述情况都属于未知场景,超出的流量远远大于微服务所能承受的最大极限,我们希望在到达服务流量极限时,我们可以对客户端进行限流处理,防止服务瘫痪、溢出等严重情况的发生;
通常的限流算法有:计数器算法(Counter)、漏桶算法(Leaky Bucket)、令牌通算法(Token Bucket)等;
8.6.1 计数器算法
1)算法原理
计数器算法是限流算法里最简单也是最容易实现的一种算法。比如我们限制一个接口每分钟调用不能超过100次,我们可以这样设计,定义2个变量,一个是访问次数,一个是记录访问次数计算的开始时间,如果记录时间和当前时间比较大于1分钟,则重新计时,如果在一分钟以内,我们把访问次数加一。
2)临界值问题:
计数器算法(Connter)实现起来非常简单,但却有个非常大的弊端,那就是临界值问题;
我们知道计数器算法等到指定的时间(我们上面是1分钟)结束后会清空Counter,在下一分钟后会重新累计阈值100,那么如果在第1分钟的59s发送了100个请求,紧接着第2分钟的1s发送了100个请求呢?此时后端的访问便在1秒钟接受到了200个请求;我们设定的阈值是100/min,平均约为1.7/s个请求,而临界值在1s钟发送了200个请求!
3)性能浪费
我们规定1min之内可以接受100个请求,我们预期的想法是希望100个请求能够平均分散在这1min,如果在30s时请求满了100个时,那么接下来的30s内访问便处于空闲状态;
8.6.2 漏桶算法
1)算法原理
漏桶(Leaky Bucket)算法思路也很简单,水(请求)先进入到储蓄桶中,储蓄桶有一定的水流频率(接口的响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率;
示意图如下:
我们之前所学的RabbitMQ限流其实就是一种漏桶算法,可以接受大量的Message(水),存储到Queue中(储蓄桶),但是消费频率低(水流频率)
2)弊端
- 1、漏桶算法的实现思路是一种”牺牲自己,保护他人”的理念,假设次数请求很多,而响应速率比较慢,则大量的请求挤压在网关中
- 2、漏桶算法无法应对突发情况的大流量调用,不管网关接受多少请求,响应速率始终一成不变,容易导致网关请求挤压过多;
8.6.3 令牌桶算法
令牌桶算法是基于漏桶算法的一种改进,令牌桶算法能应对一些突发情况的大流量调用。在令牌桶算法中,以一定速率往桶中放令牌,桶中存储了大量的令牌(Token),每次处理请求前需要先获取令牌才可以执行,否则处于等待令牌状态或直接拒绝。如果桶中的令牌达到上限,就丢弃令牌;
算法示意图:
8.6.4 Zuul网关实现流量限流
基于Zuul的filter开发的限流功能,可以结合本地缓存、redis、consul、mysql等做数据存储。
引入限流相关依赖:
<!--Zuul限流的相关依赖-->
<dependency>
<groupId>com.marcosbarbero.cloud</groupId>
<artifactId>spring-cloud-zuul-ratelimit</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<!--Redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
1)全局网关限流
Zuul的全局限流针对于所有的服务
zuul:
ratelimit:
key-prefix: zuul_limit # 缓存key的名称定义前缀。
enabled: true # 开启Zuul网关限流
repository: REDIS # 采用Redis方案
default-policy-list: # 默认的全局配置,如果根据规则查询不到配置则应用这个定义的配置
- limit: 3 # 令牌的个数
refresh-interval: 10 # 刷新令牌的时间(单位:秒)
type: # 限流类型
- origin # 根据客户端ip地址进行区分
- url # 根据请求URL进行区分
访问Item-servier、order-service,10s内生成3个令牌;10s内访问了第4次则触发限流;
查看Redis:
2)根据服务限流
zuul:
ratelimit:
key-prefix: zuul_limit # 缓存key的名称定义前缀。
enabled: true # 开启Zuul网关限流
repository: REDIS # 采用Redis方案
policy-list: # 默认的全局配置,如果根据规则查询不到配置则应用这个定义的配置
item-service:
- limit: 3 # 时间窗口内最多访问次数
refresh-interval: 20 # 默认的刷新时间窗口的间隔。
type: # 限流类型
- origin # 根据客户端ip地址进行区分
- url # 根据请求URL进行区分
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/131745.html