SpringCloud 系列列表:
文章名 | 文章地址 |
---|---|
01、Eureka - 集群、服务发现 | https://blog.csdn.net/qq_46023503/article/details/128319023 |
02、Ribbon - 负载均衡 | https://blog.csdn.net/qq_46023503/article/details/128332288 |
03、OpenFeign - 远程调用 | https://blog.csdn.net/qq_46023503/article/details/128387961 |
04、Hystrix - 断路器 | https://blog.csdn.net/qq_46023503/article/details/128408601 |
05、Sleuth - 链路追踪 | https://blog.csdn.net/qq_46023503/article/details/128409339 |
06、Gateway - 网关 | https://blog.csdn.net/qq_46023503/article/details/128430842 |
07、Alibaba - 介绍 | https://blog.csdn.net/qq_46023503/article/details/128434080 |
08、Nacos - 安装、启动 | https://blog.csdn.net/qq_46023503/article/details/128460411 |
09、Nacos - 配置文件中心 | https://blog.csdn.net/qq_46023503/article/details/128460649 |
10、Nacos - 注册中心 | https://blog.csdn.net/qq_46023503/article/details/128460494 |
Gateway - 网关
1 网关概述
网关是微服务最边缘的服务,直接暴露给用户,用来做用户和微服务的桥梁
- 没有网关:客户端直接访问微服务,会需要在客户端配置很多的 ip:port,如果 user-service 并发比较大,则无法完成负载均衡
- 有网关:客户端访问网关,网关来访问微服务,(网关可以和注册中心整合,通过服务名称找到目标的 ip:prot)这样只需要使用服务名称即可访问微服务,可以实现负载均衡,可以实现 token 拦截,权限验证,限流等操作
2 Spring Cloud Gateway 简介
- 它是 Spring Cloud 官方提供的用来取代 zuul(netflix)的新一代网关组件
- zuul:1.0 , 2.0 ,zuul 的本质,一组过滤器,根据自定义的过滤器顺序来执行,本质就是 web 组件,web 三大组件(监听器 过滤器 servlet) 拦截 springmvc
- zuul1.0 使用的是 BIO(Blocking IO),tomcat7.0 以前都是 BIO,性能一般 zuul2.0 性能好,NIO
- 它的目地是让路由更加简单,灵活,还提供了一些强大的过滤器功能,例如:熔断、限流、重 试,自义定过滤器等 token 校验 ip 黑名单等 SpringCloud Gateway作为Spring Cloud生态的网关,目标是替代Zuul,在SpringCloud2.0 以上的版本中,没有对新版本的 zuul2.0 以上的最新高性能版本进行集成,仍然还是使用的 zuul1.x[可以看项目依赖找到]非 Reactor 模式的老版本。而为了提升网关的性能, SpringCloud Gateway 是基于 webFlux 框架实现的,而 webFlux 框架底层则使用了高性能 的 Reactor 模式通信框架的 Netty NIO(非阻塞式 io) BIO
3 特征
4 Spring Cloud Gateway 工作流程
- 客户端向 springcloud Gateway 发出请求,然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。 Handler 再通过指定的过滤器来将请求发送到实际的服务的业务逻辑,然后返回
- 过滤器之间用虚线分开是因为过滤器可能会在发送请求之前【pre】或之后【post】执行业务逻辑,对其进行加强或处理
- Filter 在 【pre】 类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转 换等;在【post】 类型的过滤器中可以做响应内容、响应头的修改、日志的输出,流量监控等有着 非常重要的作用
- 总结:Gateway 的核心逻辑也就是路由转发 + 执行过滤器链
5 Spring Cloud Gateway 三大核心概念
5.1 Route(路由)(重点)
和 eureka 结合做动态路由,路由信息的组成: 由一个 ID、一个目的 URL、一组断言工厂、一组 Filter 组成。 如果路由断言为真,说明请求 URL 和配置路由匹配
5.2 Predicate(断言)
就是一个返回 bool 的表达式,Java 8 中的断言函数。 lambda 四大接口:供给形,消费性,函数型,断言型。Spring Cloud Gateway 中的断言函数输入类型 是 Spring 5.0 框架中的 ServerWebExchange。Spring Cloud Gateway 的断言函数允许开发者去定义匹配来自于 Http Request 中的任何信息比如请求头和参数
5.3 Filter(过滤) (重点)
一个标准的 Spring WebFilter。 Web 三大组件、(servlet listener filter) mvc interceptor。Spring Cloud Gateway 中的 Filter 分为两种类型的 Filter,分别是 Gateway Filter 和 Global Filter。过滤器 Filter 将会对请求和响应进行修改处理。 一个是针对某一个路由(路径)的 filter 对某一个接口做限流,一个是针对全局的 filter
6 Nginx 和 Gateway 的区别
- Nginx 在做路由,负载均衡,限流之前,都有修改 nginx.conf 的配置文件,把需要负载均衡,路由,限流的规则加在里面。Eg:使用 nginx 做 tomcat 的负载均衡
- 但是 gateway 不同,gateway 自动的负载均衡和路由,gateway 和 eureka 高度集成,实现自动的路由,和 Ribbon 结合,实现了负载均衡(lb),gateway 也能轻易的实现限流和权限验证
- Nginx(c)比 gateway(java)的性能高一点
- Nginx 是更大的,服务器级别的;Gateway 是项目级别的
7 Gateway 快速入门
7.1 本次访问流程
7.2 实现步骤
1、创建 user-service 项目
- 只选择一个 spring web 依赖
- 在 yml 文件中配置端口为 8081
- 创建控制层方便测试
@RestController
public class LoginController {
@GetMapping("/login")
public String login(){
return "登陆成功!";
}
}
2、创建 gateway 项目
- 只选择 gateway 依赖(此依赖使用 jetty 服务器,而 web 使用的是 tomcat)
- 修改 springboot 版本号为 2.3.12.RELEASE,修改 springcloud 版本号为 Hoxton.SR12
- yml 文件中配置
server:
port: 80
spring:
application:
name: gateway80
cloud:
gateway:
enabled: true #开启网关,默认是开启的
routes: #设置路由,注意是数组,可以设置多个,按照 id 做隔离
- id: login #路由 id,没有要求,保持唯一即可
uri: http://localhost:8081 #设置真正的服务 ip:port
predicates: #断言匹配
- Path=/login #和服务中的路径匹配,是正则匹配的模式,匹配成功就会访问到指定的uri下面
- id: provider-service-router
uri: http://localhost:8082
predicates:
- Path=/info/** #如果匹配到第一个路由,则第二个就不会走了,注意这不是负载均衡
3、启动项目测试
访问 localhost:8081/login 和 loclhost:80/login 都可以访问到 user-service 中的控制层方法
8 Gateway 集群
基础服务设施 (eureka,gateway configserver auth-server) 这里使用虚拟机实现
1、创建两个 gateway,端口分别为 80 和 81
2、Nginx 的配置文件修改
3、访问测试
9 Gateway 微服务名动态路由,负载均衡
9.1 概述
- 从之前的配置里面可以看到 URL 都是写死的,这不符合微服务的要求,微服务是只要知道服务的名字,根据名字去找,而直接写死就没有负载均衡的效果了
- 默认情况下 Gateway 会根据注册中心的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能
- 需要注意的是 uri 的协议为 lb(load Balance),表示启用 Gateway 的负载均衡功能。lb://serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri 协议:就是双方约定的一个接头暗号
9.2 案例
springboot 版本为 2.3.12.RELEASE,springcloud 版本为 Hoxton.SR12
1、创建一个 eureka 服务端
参考 eureka
2、创建 user-service 服务
- 选择依赖 eureka-client、spring-web
- 启动类上添加上 @EnableEurekaClient
- yml 文件
server:
port: 8081
spring:
application: #服务名字
name: gatewayuserservice
eureka:
client:
service-url: #注册到 eureka 服务器端
defaultZone: http://localhost:8761/eureka
- 控制层测试方法
@RestController
public class LoginController {
@GetMapping("/login")
public String login(){
return "登陆成功!";
}
}
3、创建 gateway 服务
- 选择依赖 gateway、eureka-client
- 启动类上添加上 @EnableEurekaClient
- yml 文件
server:
port: 80
spring:
application:
name: gateway80
cloud:
gateway:
enabled: true
routes: #可以不写
- id: login
uri: lb://gatewayuserservice #使用 lb 协议 微服务名称做负均
predicates:
- Path=/login
discovery:
locator:
enabled: true #开启动态路由
lower-case-service-id: true #动态路由小驼峰规则
eureka:
client:
service-url: # 注册到 eureka 服务上
defaultZone: http://localhost:8761/eureka
4、测试
访问 localhost:8081/login、localhost:80/login、localhost:80/gatewayuserservice/login 都可以访问到 user-service 中控制层的方法
10 Filter 过滤器工厂
10.1 概述
gateway 里面的过滤器和 Servlet 里面的过滤器,功能差不多,路由过滤器可以用于修改进入 Http 请求和返回 Http 响应
10.2 分类
按生命周期分两种
- pre:在业务逻辑之前
- post:在业务逻辑之后
按种类分也是两种
- GatewayFilter:需要配置某个路由,才能过滤。如果需要使用全局路由,需要配置 DefaultFilters
- GlobalFilter:全局过滤器,不需要配置路由,系统初始化作用到所有路由上
10.3 自定义网关过滤器(重点)
自定义全局过滤器
全局过滤器的优点的初始化时默认挂到所有路由上,可以使用它来完成 IP 过滤,限流等功能
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("--------------------------进入了我自定义的拦截器");
String token = exchange.getRequest().getQueryParams().getFirst("token");
if (token==null){
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);//返回错误状态码
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);//放行
}
//order 越小,越先执行
@Override
public int getOrder() {
return 0;
}
}
访问测试:http://localhost/gatewayuserservice/login?token=1
11 限流
11.1 什么是限流
通俗的说,限流就是限制一段时间内,用户访问资源的次数,减轻服务器压力,限流大致分为两种
- IP 限流(5s 内同一个 ip 访问超过 3 次,则限制不让访问,过一段时间才可继续访问)
- 请求量限流(只要在一段时间内(窗口期),请求次数达到阀值,就直接拒绝后面来的访问了, 过一段时间才可以继续访问)(粒度可以细化到一个api(url),一个服务)
11.2 本次限流模型
限流模型:漏斗算法 ,令牌桶算法,窗口滑动算法 计数器算法
- 所有的请求在处理之前都需要拿到一个可用的令牌才会被处理
- 根据限流大小,设置按照一定的速率往桶里添加令牌
- 桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝
- 请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完业务逻辑之后,将令牌直接删除
- 令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令牌,以此保证足够的限流
11.3 Gateway 结合 Redis 实现请求量限流
Spring Cloud Gateway 已经内置了一个 RequestRateLimiterGatewayFilterFactory,可以直接使用。 目前 RequestRateLimiterGatewayFilterFactory 的实现依赖于 Redis,所以要引入 spring-boot-starter-data-redis-reactive
在前面项目的基础上
1、添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
2、修改 yml 文件
server:
port: 80
spring:
application:
name: gateway80
cloud:
gateway:
enabled: true
routes:
- id: login
uri: lb://gatewayuserservice
predicates:
- Path=/login
filters: #限流的设定
- name: RequestRateLimiter #名字固定
args:
key-resolver: '#{@hostAddrKeyResolver}' #里面的名字必须和配置类的 bean 名字一样
redis-rate-limiter.replenishRate: 1 # 每秒钟产生的令牌数
redis-rate-limiter.burstCapacity: 3 # 令牌的最大数量
discovery:
locator:
enabled: true
lower-case-service-id: true
redis: #redis 的配置
host: 127.0.0.1
port: 6379
database: 0
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
3、创建配置类
@Configuration
public class RequestRateLimiterConfig {
/**
* IP 限流
* 把用户的 IP 作为限流的 Key
*/
@Bean
@Primary
public KeyResolver hostAddrKeyResolver() {
return (exchange) -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
/**
* 用户 id 限流
* 把用户 ID 作为限流的 key
*/
@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
}
/**
* 请求接口限流
* 把请求的路径作为限流 key
*/
@Bean
public KeyResolver apiKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getPath().value());
}
}
4、访问测试
快速访问多次,出现 429 状态码
12 跨域配置
因为网关是微服务的边缘 所有的请求都要走网关 跨域的配置只需要写在网关即可
12.1 配置类配置
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
12.2 yml 文件配置
spring:
cloud:
gateway:
globalcors:
corsConfigurations:
'[/**]': // 针对哪些路径
allowCredentials: true // 这个是可以携带 cookie
allowedHeaders: '*'
allowedMethods: '*'
allowedOrigins: '*'