“有一天晚上,梦一场,你白发苍苍,说带我流浪,我还是没犹豫,就随你去天堂”
网关在微服务体系中有这非常的重要的地位,有了网关,外部直接与网关通信,我们不需要暴露太多微服务的信息,而且访问也方便
搭建
- 依赖
'org.springframework.cloud:spring-cloud-starter-gateway:2.1.1.RELEASE'
如果引用了web的依赖,需要删掉,spring cloud gateway 使用webflux,和web会冲突
- 主类加注解,添加eureka的注解
@SpringBootApplication
@EnableDiscoveryClient
public class GetawayApplication {
public static void main(String[] args) {
SpringApplication.run(GetawayApplication.class, args);
}
}
- 修改配置
server:
port: 9000
spring:
application:
name: ADMIN-GETAWAY
cloud:
gateway:
discovery:
locator:
# 开启服务发现
enabled: true
# 忽略注册中心服务的大小写
lower-case-service-id: true
eureka:
instance:
# ip-address: ${server.address}
# hostname: ${server.address}
non-secure-port: ${server.port}
prefer-ip-address: true
# instance-id: ${server.address}:${server.port}
lease-renewal-interval-in-seconds: 10
client:
serviceUrl:
defaultZone: http://192.168.1.137:38001/eureka/
fetch-registry: true
register-with-eureka: true
在注册中心,即可看见我们的网关微服务
现在我什么也没有配置,我们访问网关的IP:端口/指定微服务的名称/接口,即可访问我们的微服务
这样我们的网关就搭建成功了,网关还可以集成swagger,需要的可以看我的这篇博客
https://blog.csdn.net/zlhmeng/article/details/100521118
路由转发
现在配置文件里面什么也没有配置,默认的转发机制,我们访问网关的ip:port/微服务名/接口即可访问相应的微服务
比如我的注册中心有这几个微服务
- 其中conmuser通过openfign调用了provider1和provider2
访问
默认就实现了动态路由,但这暴露了我们的微服务名称和接口,安全性不太好,有些时候我们也有需求不想暴露我们的api,所以就有配置路由转发,或者对路由进行过滤。
添加配置:
spring:
application:
name: ADMIN-GETAWAY
cloud:
gateway:
discovery:
locator:
#开启服务注册和发现功能
enabled: true
#将服务名称转换为小写
lower-case-service-id: true
routes:
- id: byb-provide1
uri: lb://TS-PROVIDER1
predicates:
- Path=/demo/**
filters:
- StripPrefix=1
前面的配置之前就有,为了直观的看出层级关系都附上了,重点在routes配置
- id:标识此路由的唯一id,就给这个路由取一个不会重复的好理解的名字
- uri:顾名思义,路由的uri,你可以写成ip:port的形式,因为我们使用了注册中心,所有使用lb://微服务名,即可定位到指定微服务
- predicates:这里就是配置断言,也就是路由的规则,这里配置了path,表示我要根据路径过滤路由,会将/demo开头的路由转发到我们上面配置的微服务,基本上http请求的参数都可以断言,可以参考下面的官方文档。
- filters:过滤器,我配置了StripPrefix=1也就是截取url前面的一位,截取过后的后面一位才是真正的api,比如说我么的断言不是一个/demo而是两个/demo/demo/**,并且截取一位,那么路由到微服务的时候就会多出一个/demo(一个demo会变成ip:port/test1,两个只截取了一个,接口就会变成ip:port/demo/test1),除非有/demo/…的接口,否者访问不到
结果和上面一样,当然routes还有很多的参数,比如断言的权重,可能相对比较重要,官方文档都有,可以了解一下,根据自己的需求觉得使用什么参数
https://cloud.spring.io/spring-cloud-gateway/reference/html/#gateway-request-predicates-factories
上面的配置也可以使用代码进行配置,个人建议使用yaml配置文件的方式,这样比代码更直观,而且搭配spring cloud config非常方便,更改时修改配置文件就行,不用修改代码。
熔断
我们之前使用openfign可以实现熔断,但这是服务间调用,我们的请求都会经过网关,当有大量的请求访问时,我们都不敢保证不会因为各种原因而请求失败,但我们不能让请求一直堆积在网关,如果网关死了,整个体系就断了,所以我们需要使用熔断,失败时直接给客服端返回失败,不要堆积。
添加配置
spring:
application:
name: ADMIN-GETAWAY
cloud:
gateway:
discovery:
locator:
#开启服务注册和发现功能
enabled: true
#将服务名称转换为小写
lower-case-service-id: true
routes:
- id: byb-provide1
uri: lb://TS-PROVIDER1
predicates:
- Path=/demo/**
filters:
- StripPrefix=1
- name: Hystrix
args:
name: hystest
fallbackUri: forward:/hysTest
# 熔断时间
hystrix:
command:
fallbackcmd:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
在filter下面我们添加了名为Hystrix的过滤器实现熔断,下面是参数,name表示过滤器的名称此处必须为Hystrix,fallbackuri表示熔断定位,大概就是发生熔断后要干嘛,我这里配置了forward表示转发,所以我们需要配置hsyTest的接口
@RestController
public class HysFallback {
@GetMapping("/hysTest")
public String fallback(){
return "网关熔断测试成功";
}
}
上面的配置我们的熔断超时时间是3秒,我们让他让问的接口睡眠4秒即可测试是否熔断成功,修改provider1中的代码
@GetMapping("/test1")
public String test1() {
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String info = "uri=test1,我是服务提供者一。欢迎光临。";
logger.info(info);
return info;
}
访问
完美
限流
系统高并发的时候,系统可能过载,也有可能有人就估计攻击服务器,为了保证系统的正常运行我们需要做一下限流,spring cloud gateway使用redis实现限流
添加配置
spring:
application:
name: ADMIN-GETAWAY
cloud:
gateway:
discovery:
locator:
#开启服务注册和发现功能
enabled: true
#将服务名称转换为小写
lower-case-service-id: true
routes:
- id: byb-provide1
uri: lb://TS-PROVIDER1
predicates:
- Path=/demo/**
filters:
- StripPrefix=1
- name: Hystrix
args:
name: hystest
fallbackUri: forward:/hysTest
- name: RequestRateLimiter
args:
# 使用SpEL名称引用Bean,与上面新建的RateLimiterConfig类中的bean的name相同
key-resolver: '#{@KeyResolverTest}'
# 每秒最大访问次数
redis-rate-limiter.replenishRate: 2
# 令牌桶最大容量
redis-rate-limiter.burstCapacity: 10
redis:
host: 192.168.1.137
port: 6379
database: 0
- name: RequestRateLimiter为过滤器名称,这是spring cloud gateway官方提供的过滤器
- key-resolver:使用 SpEL查找bean,我们下面会定义一个bean,用来定义通过什么方式限流
- redis-rate-limiter.replenishRate:允许用户每秒处理多少个请求
- redis-rate-limiter.burstCapacity:令牌桶的容量
后面两个解释可以参考:https://www.cnblogs.com/forezp/p/10140316.html
定义bean
@Configuration
public class keyResolverConfig {
@Bean(value = "KeyResolverTest")
public KeyResolver KeyResolverTest() {
// 根据ip限流
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
// 根据接口限流
// return exchange -> Mono.just(exchange.getRequest().getPath().value());
// 根据用户限流
// return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}
}
这个bean通过过滤器筛选请求,不难发现他是通过gateway的过滤器去过滤的,没有了解过spring cloud gateway过滤机制的看完可以去了解一下。
把之前provider中的睡眠去掉,使用测试工具测试一下,我这里使用jmeter
完毕