Spring Cloud Gateway网关的使用和Nacos下发路由配置实现Spring Cloud Gateway的动态路由
一、微服务网关概述
1.1 微服务网关诞生背景
不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:
-
客户端会多次请求不同的微服务,增加了客户端的复杂性
-
存在跨域请求,在一定场景下处理相对复杂
-
认证复杂,每个服务都需要独立认证
-
难以重构,随着项目的迭代,可能需要重新划分微服务。
例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施某些微服务可能使用了防火墙 / 浏览器不友好的协议,直接访问会有一定的困难
以上这些问题可以借助网关解决
1.2 微服务网关是什么?
又名:API网关
网关是介于客户端和服务器端之间的中间层,所有的外部请求都统一发到网关服务(base-gateway),网关再根据路由规则转发到相应服务,所以尽管我们的微服务可能会有成百上千个子服务,我们只需配置好路由规则将网关对外就可以了,服务器防火墙也只要开放网关服务的端口(9999)。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由网关来做,这样既提高业务灵活性又不缺安全性
1.3 微服务网关的特点
【服务器、中间层】API网关是一个服务器,介于客户端和服务器端之间的中间层,
【系统入口,请求先到它】API网关是系统的唯一入口。所有的外部请求都会先经过它这一层
【网关就是门卫】网关就好比一个公司的门卫。屏蔽内部细节,统一对外服务接口。
【设计模式-外观模式】从面向对象设计的角度看,它与外观模式类似。
【核心功能】API网关封装了系统内部架构,为每个客户端提供一个定制的API。
【多职能】API网关可能还具有其它职责,如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理。
【核心要点】所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。
通常,网关也是提供REST/HTTP的访问API。服务端通过API-GW注册和管理服务。
API网关 所有的客户端请求通过这个网关访问后台的服务。
可以使用一定的路由配置来判断某一个URL由哪个服务来处理。并从Eureka获取注册的服务来转发请求。
1.4 微服务网关架构图
如图所示:
1.5 微服务网关的优点
-
安全
只有网关系统对外进行暴露,微服务可以隐藏在内网,通过防火墙保护。 -
易于监控。
可以在网关收集监控数据并将其推送到外部系统进行分析。 -
易于认证
可以在网关上进行认证,再将请求转发到后端的微服务,而无须在每个微服务中进行认证。减少了客户端与各个微服务之间的交互次数,易于统一鉴权。
二 、SpringCloud Gateway介绍
2.1 SpringCloud Gateway 是什么?
SpringCloud的网关路由更新迭代如下
技术名称 | 说明 |
---|---|
zuul1.x | Zuul 是 Netflix 开源的微服务网关 |
zuul2.x | Netflix 公司不再维护了 |
Spring Cloud Gateway | 根据zuul2.x,Spring团队自己实现了一套,叫Spring Cloud Gateway,SpringCloud本身的网关服务 |
2.2 微服务网关的核心
网关中有两个重要的概念,那就是路由配置和路由规则,
- 路由配置 (路由转发)
是指配置某请求路径路由到指定的目的地址。
接收一切外界请求,转发到后端的微服务上去。
- 路由规则(过滤器)
指匹配到路由配置之后,再根据路由规则进行转发处理。
在服务网关中,可以完成一系列的横切功能(见:服务网关基本功能),都可通过过滤器完成
(其实路由转发也是通过过滤器实现的)
三、动态路由实现
Spring Cloud Gateway作为所有请求流量的入口,在实际生产环境中为了保证高可靠和高可用,尽量避免重启,需要实现Spring Cloud Gateway动态路由配置。
2.1 路由模块(base-gateway)启动时加载路由配置并开启监听实现动态(DynamicRouteInit.java)
//初始化网关路由
@Slf4j
@Configuration
@AllArgsConstructor
public class DynamicRouteInit {
private RouteDefinitionWriter routeDefinitionWriter;
private NacosConfigUtils nacosConfigUtils;
@PostConstruct
public void initRoute() {
try {
ConfigService configService = nacosConfigUtils.getConfigService();
String content = configService.getConfig(CommonConstants.CONFIG_DATA_ID_DYNAMIC_ROUTES, CommonConstants.CONFIG_GROUP, CommonConstants.CONFIG_TIMEOUT_MS);
log.info("初始化网关路由开始");
updateRoute(content);
log.info("初始化网关路由完成");
//开户监听,实现动态
configService.addListener(CommonConstants.CONFIG_DATA_ID_DYNAMIC_ROUTES, CommonConstants.CONFIG_GROUP, new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
log.info("更新网关路由开始");
updateRoute(configInfo);
log.info("更新网关路由完成");
}
@Override
public Executor getExecutor() {
return null;
}
});
} catch (NacosException e) {
log.error("加载路由出错:{}", e.getErrMsg());
}
}
public void updateRoute(String content){
Yaml yaml = new Yaml();
GatewayRouteList gatewayRouteList = yaml.loadAs(content,GatewayRouteList.class);
gatewayRouteList.getRoutes().forEach(route -> {
log.info("加载路由:{},{}", route.getId(), route);
routeDefinitionWriter.save(Mono.just(route)).subscribe();
});
}
}
2.2 Nacos中配置路由信息(dynamic_routes)
动态路由就是这么简单,更新路由配置不再需要重启服务