• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Spring Cloud Gateway 微服务网关尚学堂学习笔记

武飞扬头像
IM 胡鹏飞
帮助1

API 网关介绍

1 什么是API网关

API网关作用就是把各个服务对外提供的API汇聚起来,让外界看起来是一个统一的接口。同时也可以在网关中提供额外的功能
总结:网关就是所有项目的一个统一入口

请求响应流程:
nginx --> 前端项目集群 --> 网关 --> 后端项目集群

2 网关组成

网关 = 路由转发 过滤器(编写额外功能)

2.1 路由转发

接收外界请求,通过网关的路由转发,转发到后端的服务上
如果只有这个一个功能看起来和之前学习的Nginx方向代理服务器很像,外界访问nginx,由nginx做负载均衡,后把请求转发到对应服务器上

2.2 过滤器

网关非常重要的功能就是过滤器
过滤器中默认提供了25个内置功能,还支持额外的自定义功能
对于我们来说比较常用的功能包括网关的容错、限流以及请求及相应的额外处理

3 Spring Cloud中提供的网关解决方案

3.1 Spring Cloud Netflix Zuul

属于Spring Cloud Netflix下一个组件,具有灵活、简单的特点。在早期Spring Cloud中使用的比较多
其版本更新都依赖Netflix Zuul

3.2 Spring Cloud Gateway

由Spring自己推出的网关产品,完全依赖Spring自家产品。符合Spring战略意义,其更新版本等都由Spring自己把控

Spring Cloud Gateway介绍

1 简介

Spring Cloud Gateway是Spring Cloud的二级子项目,提供了微服务网关功能,包含:权限安全、监控、指标等功能

2 名词解释

在学习Gateway时里面有一些名词需要提前了解

2.1 Route

路由,一个Gateway项目可以包含多个路由
一个路由包含ID、URI、Predicate集合、Filter集合
在Route中ID是自定义的,URI就是一个地址,剩下的Predicate和Filter

2.2 Predicate

谓词,谓词是学习Gateway比较重要的一点,简单点理解谓词就是一些附加条件和内容,其实就是路由规则,和简单的校验逻辑

2.3 Filter

所有生效的Filter都是GatewayFilter的实例,在Gateway运行过程中Filter负责在代理服务之前或之后去做一些事情

Spring Cloud Gateway入门案例

新建微服务,首先引入依赖

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

添加配置文件,gateway的配置都是在配置文件中实现的

server:
	port: 9999
spring:
	application:
		name: my-spring-cloud-gateway
	cloud: #配置Spring Cloud相关属性
		gateway: #配置Spring Cloud Gateway相关属性
			discovery: #配置网关发现机制
				locator: #配置处理机制
					enable: true #开启网关自动映射处理逻辑,
					#只要请求地址符合规则:http://gatewayIP:gatewayPort/微服务名称/微服务请求地址
					#网关自动映射,把请求转发到http://微服务名称/微服务请求地址
					#如:有微服务,命名是ribbon-app-service
					#请求地址是:http://localhost:9999/ribbon-app-service/getArgs?name=admin&age=20
					#自动转发到:http://ribbon-app-service/getArgs?name=admin&age=20
					#商业开发中,enable一般不设置,使用默认值false。避免不必要的自动转发规则
					lower-case-service-id: true #开启服务名称小写转换。Eureka对服务名管理默认全是大写
			routes: #配置网关中的一个完整路由,包括命名,地址,谓词集合(规则),过滤器集合
				- id: first #路由定义的命名,唯一即可。命名规则符合Java中的变量符合命名规则
					# lb - 代表loadbalance
					uri: lb://ribbon-app-service #当前路由定义对应的微服务转发地址
					#谓词,命名是有规则的。是GatewayPredicate接口实现的命名前缀,XxxRoutePredicataFactory
					predicates: #配置谓词集合
						- Path=/api/** #定义一个谓词。格式:谓词名字=参数  或者  name:名字 args:参数
					#过滤器命名,有规则。GatewayFilterFactory接口实现的命名前缀
					filters: #配置过滤器集合
						#过滤转发地址前缀,过滤一节
						#如:请求地址:http://localhost:9999/api/getArgs?name=admin&age=20
						#对应的谓词,规则是/api,符合
						#对应的uri是 lb:ribbon-app-service  转换成http://ribbon-app-service且包含负载均衡
						#转发地址是:http://ribbon-app-service/getArgs?name=admin&age=20
						#过滤器是 过滤转发地址前缀,过滤一节,即删除/api
						- StripPrefix=1 #定义一个过滤器。格式:过滤器名字=参数  或者  name:名字 args:参数
				- id:
					uri:
					predicates:
						- name: Path
						  args:
						  	- patterns=/api/**,/a/**
					filters:
eureka:
	client:
		service-url:
			defaultZone: http://localhost:8761/eureka/

谓词(规则)


# 检查请求头中是否有指定数据,key是my,值是bjsxt(正则表达式)
routes:
	- id: first
	  uri: lb://ribbon-api-service
		predicates:
			- Path=/api/**,/a/**,/b/**
				name: Header
				args: #map类型,键值对
					header: my
					regexp: bjsxt.* #正则表达式
		filters:

# 校验请求中的参数,key是name,值是一个正则表达式
routes:
	- id: first
	  uri: lb://ribbon-api-service
		predicates:
			- Query=name,admin.* #谓词判断请求参数,值判断请求头传递的参数,请求体参数不判断
		filters:

# 检查请求类型
routes:
	- id: first
	  uri: lb://ribbon-api-service
		predicates:
			- Method=GET,POST
		filters:

# 检查客户端ip地址是否符合要求
routes:
	- id: first
	  uri: lb://ribbon-api-service
		predicates:
			- sources=192.168.0.1,192.168.0.2,192.168.0.*
		filters:

# 检查请求中指定的cookie值
routes:
	- id: first
	  uri: lb://ribbon-api-service
		predicates:
			- name=cookieName
			  regexp=aa*
		filters:

# 检查请求在什么时间范围内
routes:
	- id: first
	  uri: lb://ribbon-api-service
		predicates:
			- Path=/api/**
			- Between=2020-01-31T18:00:00.000 08:00[Asia/Shanghai],2020-01-31T20:00:00.000 08:00[Asia/Shanghai]
		filters:

# 检查请求头
routes:
	- id: first
	  uri: lb://ribbon-api-service
		predicates:
			- Path=/api/**
			- pattern=*
		filters:

# 权重实现负载均衡(通常不会使用,只有在多版本服务发布的时候偶尔使用,新版本权重2,接受少量的请求,如果没有问题,就可以替换旧版本)
routes:
	- id: first
	  uri: lb://ribbon-api-service-1
		predicates:
			- Path=/api/**
			- Weight=group,2 #group表示分组名称,分组名称一样,表示同一组
		filters: SpripPrefix=1
	- id: two
	  uri: lb://ribbon-api-service-2
		predicates:
			- Path=/api/**
			- Weight=group,8 #按照权重比例分配请求
		filters: SpripPrefix=1

Filter

Filter作用:在路由转发到代理服务器之前和代理服务器返回结果之后额外做的事情。
Filter执行了,那就说明谓词条件通过了

在Spring Cloud Gateway的路由中Filter分为:
内置Filter,都是GatewayFilter实现类
自定义GlobalFilter


# 添加一个请求头信息
routes:
	- id: first
	  uri: lb://ribbon-api-service
		predicates:
			- Path=/api/**
			- pattern=*
		filters:
			- AddRequestHeader=a,b

# 完整写法
routes:
	- id: first
	  uri: lb://ribbon-api-service
		predicates:
		filters:
			- name: AddRequestHeader
				args:
					name: newHeader
					value: newValue

查看源码,XXXGatewayFilterFactory,这些都是过滤器,对应配置类就可以配置属性参数

常用的:
AddRequestHeader
AddResponseHander
DedupeResponseHander
StripPrefix

使用Gateway实现限流

可以利用Gateway中RequestRateLimiter实现限流

1 常见的限流算法

1.1 计数器算法

以QPS每秒查询率为100举例子

从第一个请求开始计时,每个请求让计数器加一,到达到100以后,其他的请求都拒绝
如果1秒内前200毫秒请求数量已经到达了100,后面800毫秒中500次请求都被拒绝了,这种情况称为‘突刺现象’

1.2 漏桶算法

漏桶算法可以解决突刺现象
和生活中漏桶一样,有一个水桶,下面有一个漏眼往出漏水,不管桶里有多少水,漏水的速率都是一样的。但是既然是一个桶,桶里装的谁都是有上限的。当达到了上限新进来的水就装不了(主要出现在突然倒进来大量水的情况)

1.3 令牌桶算法

令牌桶算法可以说是对漏桶算法的一种改进
在桶中放令牌,请求获取令牌后才能继续执,如果桶中没有令牌,请求可以选择进行等待或者直接拒绝
由于桶中令牌是按照一定速率放置的,所以可以一定程度解决突发访问,如果桶中令牌最多100个,qps最大为100

学新通

2 Gateway中的限流

RequestRateLimiter 基于Redis和lua脚本实现令牌桶算法

2.1 添加依赖



2.2 修改配置


# 完整写法
routes:
	- id: first
	  uri: lb://ribbon-api-service
		predicates:
		filters:
			- name: RequestRateLimiter
			  args:
			  	keyResolver: '#{@myKeyResolver}' #使用SpringEL表达式,从Spring容器中找对象,并赋值 ‘#{@beanName}’
			  	redis-rate-limiter.replenishRate: 1 #每秒产生的令牌数量
			  	redis-rate-limiter.burstCapacity: 5 #桶的容量上限
			  	
2.3 算法

@Component
public class MyKeyResolver implements KeyResolver{

	@Override
	public Mono<String> resolve(ServerWebExchange exchange){
		String remoteAddr = exchange.getRequest().getRempteAddress().getAddress.getHostAddress();
		return Mono.just(remoteAddr);
	}
}

使用Gateway实现服务降级

gateway可以利用Hystrix实现服务降级等功能
当gateway进行路由转发时,如果发现下游服务连接超时允许进行服务降级
实现原理:当连接超时时,使用gateway自己的一个降级接口返回托底数据,保证程序继续运行

配置


# 完整写法
routes:
	- id: first
	  uri: lb://ribbon-api-service
		predicates:
		filters:
			- name: Hystrix
			  args:
			  	name: fallbackcmd #名字分组
			  	fallbackUri: forward:/downgrade #远程服务错误的时候,Gateway工程中的哪一个控制器逻辑,返回结果
			  	

Gateway工程中的控制器


@RestController
public class DowngradeController{
	@RequestMapping(value="/downgrade",produces="text/html;charset=UTF-8")
	public String downgrade(){
		return "<html><body><div style='width:80px;margin:auto;text-align:center'>Gateway返回服务器忙,请稍候重试</div></body><html>";
	}
}

GlobalFilter

全局过滤器不需要工厂,也不需要配置,直接对所有的路由都生效
可以使用GlobalFilter实现统一的权限验证、日志记录等希望对所有代理的项目都生效的内容都可以配置在全局过滤器中
且在项目中可以配置多个GlobalFilter的实现类,都可以自动执行

@Component
public class MyGlobalFilter implements GlobalFilter{
	@Override
	public Mono<Void> filter(ServerWebExchange exchange,GatewayFilterChain chain){
		// 前置过滤
		System.out.prinln("全局过滤器执行,当前时刻是:" new Date());
		// 执行后续逻辑
		Mono<Void> result = chain.filter(exchange);
		return result;
	}
}

Gateway自定义路由过滤器


@Component
public class RequestPathGatewayFilterFactory extends AbstractGatewayFilterFactory<RequestPathGatewayFilterFactory.Config>{
	// 当前过滤器需要使用的配置内容
	class Config{
		private String name;
		private String path;
		// get set 方法
	}
	// 过滤逻辑
	@Override
	public GatewayFilter apply(Config config){
		return new GatewayFilter(){
			@Override
			public Mono<Void> filter(ServerWebExchange exchange,GatewayFilterChain chain){
				// 执行后续逻辑
				Mono<Void> result = chain.filter(exchange);
				return result;
			}
		}
	}
	// 如果可以简化配置方案,当前方法返回简化配置参数
	// RequestPath=nameValue,pathValue
	@Override
	public List<String> showtcutFieldOrder(){
		return Arrays.asList("name","path");
	}
}

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgebcgf
系列文章
更多 icon
同类精品
更多 icon
继续加载