微服务网关的概述:
不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:
以上这些问题可以借助网关解决。
网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过 网关这一层。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由 网关来做,这样既提高业务灵活性又不缺安全性,典型的架构图如图所示:
优点如下:
总结:微服务网关就是一个系统,通过暴露该微服务网关系统,方便我们进行相关的鉴权,安全控制,日志统一处理,易于监控的相关功能。
跨域配置:
有时候,我们需要对所有微服务跨域请求进行处理,则可以在gateway中进行跨域支持。修改application.yml,添加如下代码:
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]': # 匹配所有请求
allowedOrigins: "*" #跨域处理 允许所有的域
allowedMethods: # 支持的方法
- GET
- POST
- PUT
- DELETE
最终文件如下:
spring:
application:
name: gateway-web
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]': # 匹配所有请求
allowedOrigins: "*" #跨域处理 允许所有的域
allowedMethods: # 支持的方法
- GET
- POST
- PUT
- DELETE
routes:
- id: goods_route
uri: http://localhost:18081
predicates:
# - Host=cloud.miracle.com**
- Path=/brand/**
server:
port: 8001
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:7001/eureka
instance:
prefer-ip-address: true
management:
endpoint:
gateway:
enabled: true
web:
exposure:
include: true
官网描述:
字段解析:
routes:
- id: goods_route
uri: http://localhost:18081
predicates:
- Host=cloud.miracle.com**
字段解析:
routes:
- id: goods_route
uri: http://localhost:18081
predicates:
- Path=/brand/**
字段解析:
routes:
- id: goods_route
uri: http://localhost:18081
predicates:
# - Host=cloud.miracle.com**
- Path=/**
filters:
- PrefixPath=/brand
routes:
- id: goods_route
uri: http://localhost:18081
predicates:
# - Host=cloud.miracle.com**
- Path=/**
filters:
- StripPrefix=1
routes:
- id: goods_route
uri: lb://goods
predicates:
# - Host=cloud.miracle.com**
- Path=/**
filters:
- PrefixPath=/brand
- StripPrefix=1
网关可以做很多的事情,比如,限流,当我们的系统 被频繁的请求的时候,就有可能 将系统压垮,所以 为了解决这个问题,需要在每一个微服务中做限流操作,但是如果有了网关,那么就可以在网关系统做限流,因为所有的请求都需要先通过网关系统才能路由到微服务中。
令牌桶算法是比较常见的限流算法之一,大概描述如下:
1)所有的请求在处理之前都需要拿到一个可用的令牌才会被处理;
2)根据限流大小,设置按照一定的速率往桶里添加令牌;
3)桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝;
4)请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完业务逻辑之后,将令牌直接删除;
5)令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令牌,以此保证足够的限流
如下图:
这个算法的实现,有很多技术,Guaua是其中之一,redis客户端也有其实现。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redis-reactiveartifactId>
<version>2.1.3.RELEASEversion>
dependency>
官方文档的使用说明,找到官方文档中的RateLimiter,也就是速率限制,文档描述是这样的:
The Redis implementation is based off of work done at Stripe. It requires the use of the spring-boot-starter-data-redis-reactive Spring Boot starter.
The algorithm used is the Token Bucket Algorithm.
The redis-rate-limiter.replenishRate property is how many requests per second you want a user to be allowed to do, without any dropped requests. This is the rate at which the token bucket is filled.
The redis-rate-limiter.burstCapacity property is the maximum number of requests a user is allowed to do in a single second. This is the number of tokens the token bucket can hold. Setting this value to zero blocks all requests.
The redis-rate-limiter.requestedTokens property is how many tokens a request costs. This is the number of tokens taken from the bucket for each request and defaults to 1.
A steady rate is accomplished by setting the same value in replenishRate and burstCapacity. Temporary bursts can be allowed by setting burstCapacity higher than replenishRate. In this case, the rate limiter needs to be allowed some time between bursts (according to replenishRate), as two consecutive bursts will result in dropped requests (HTTP 429 - Too Many Requests). The following listing configures a redis-rate-limiter:
Rate limits bellow 1 request/s are accomplished by setting replenishRate to the wanted number of requests, requestedTokens to the timespan in seconds and burstCapacity to the product of replenishRate and requestedTokens, e.g. setting replenishRate=1, requestedTokens=60 and burstCapacity=60 will result in a limit of 1 request/min.
谷歌翻译是这样的,其中可以看见也是使用的我们的令牌桶算法,里面的属性就是我们配置文件中指的属性
Redis 实现基于在Stripe完成的工作。它需要使用spring-boot-starter-data-redis-reactiveSpring Boot starter。
使用的算法是令牌桶算法。
该redis-rate-limiter.replenishRate属性是您希望允许用户每秒执行多少请求,而没有任何丢弃的请求。这是令牌桶填充的速率。
该redis-rate-limiter.burstCapacity属性是允许用户在一秒内执行的最大请求数。这是令牌桶可以容纳的令牌数量。将此值设置为零会阻止所有请求。
该redis-rate-limiter.requestedTokens属性是请求花费多少令牌。这是每个请求从存储桶中获取的令牌数量,默认为1。
通过在replenishRate和 中设置相同的值来实现稳定的速率burstCapacity。通过设置burstCapacity高于可以允许临时突发replenishRate。在这种情况下,需要允许速率限制器在突发之间有一段时间(根据replenishRate),因为两个连续的突发将导致请求丢失(HTTP 429 - Too Many Requests)。
官网文档中的使用方式:
(1) 在配置文件中编写:
(2) 自定义类型编写
(3)项目中的运用
目的:我们根据id限制,1s产生一个令牌,1s中只完成一个请求
KeyResolver编写:
@Bean(name = "ipKeyResolver")
public KeyResolver keyResolver(){
return new KeyResolver() {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
String hostAddress = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
return Mono.just(hostAddress);
}
};
}
配置:
- id: user_route
uri: lb://user
predicates:
- Path=/api/user/**,/api/address/**,/api/areas/**,/api/cities/**,/api/provinces/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
key-resolver: "#{@ipKeyResolver}"
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 1
解释:
redis-rate-limiter.replenishRate
是您希望允许用户每秒执行多少请求,而不会丢弃任何请求。这是令牌桶填充的速率
redis-rate-limiter.burstCapacity
是指令牌桶的容量,允许在一秒钟内完成的最大请求数,将此值设置为零将阻止所有请求。
key-resolver: “#{@ipKeyResolver}” 用于通过SPEL表达式来指定使用哪一个KeyResolver.
如上配置:
表示 一秒内,允许 一个请求通过,令牌桶的填充速率也是一秒钟添加一个令牌。
最大突发状况 也只允许 一秒内有一次请求,可以根据业务来调整 。
(4)测试:
按照官方文档所说,如果用户请求超过速率就会爆出429的错误
测试: