实现Spring Cloud Gateway路由动态加载及持久化
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现Spring Cloud Gateway路由动态加载及持久化相关的知识,希望对你有一定的参考价值。
参考技术A Spring Cloud Gateway提供了添加、删除和查询路由的 API ,通过API添加的路由默认存储在内存之中。应用重启时,通过API添加的路由会丢失,进而导致应用的功能受损。如果应用有多个实例,Spring Cloud Gateway也没有提供路由同步机制,多个实例之间的路由信息不一致,影响正常的业务。由于Spring Cloud Gateway默认实现在可靠性和一致性方面存在不足,进而无法直接部署在生产环境,为此需要自定义实现路由的存储和同步机制。在Spring Cloud Gateway中一个RouteDefinition对象定义一个路由。Spring Cloud Gateway启动时首先加载所有的RouteDefinition,然后生成路由并讲路由加载到内中(有缓存机制,主要目的是提供路由匹配的效率)。Spring Cloud Gateway可以从四个数据源加载RouteDefinition:配置文件,Fluent Route API,RouteDefinitionRepository和DiscoveryClient(Spring Cloud定义的服务发现接口)。从路由的加载机制可以看出,能够实现动态添加、删除、修改路由的方式就是自定义实现RouteDefinitionRepository,从而可以保证在Spring Cloud Gateway启动时加载之前已经添加过的路由。
Spring Cloud Gateway定义了一个RouteRefreshListener用来监听路由变化事件RefreshRoutesEvent,因此在添加、删除、更新路由后只需要发布一个RefreshRoutesEvent事件以让所有存储路由的组件更新路由即可。
实现步骤:
基于mysql的实现源码参考 Spring Cloud Gateway Example
Spring Cloud Gateway——实现路由动态修改
动态路由修改
当我们看了Spring Cloud Gateway的示例代码,和一些网上的入门教程之后,会发现大多是Spring Cloud Gateway — 网关基本功能API暴露说道的三种方法:1.本地配置文件;2.java代码builder.routes().route().build(); 3.服务自动发现。
服务自动发现方法能够做到后端服务ip变化时自动更新,能够做到上游服务的动态。另外两种方式都是纯静态,需要重新启动网关服务修改才能生效。
上述方式都不能完全满足生产需要,一般来说作为生产上的通用网关要求有路由动态修改能力,不重启网关服务即可即使生效。无论是新增路由、或者是修改路由的过滤规则,添加过滤器都可以不重启网关生效。
内置的动态路由
Spring Cloud Gateway内置了一个动态路由类InMemoryRouteDefinitionRepository
。这是一个使用内存存储路由的类,支持acurator接口对路由进行增删改查,但是当网关重启之后所有的内存路由都会消失,也就是说它没有持久化能力。
虽然InMemoryRouteDefinitionRepository
没有达到生产级动态路由修改的需求,但是它提供了一种思路,起到了示例作用。如果需要实现自己的可持久化动态路由,可以仿照InMemoryRouteDefinitionRepository
的路由解析加载能力,以及更新方式实现在即的动态路由。
基于分布式配置的动态路由
基于分布式配置可能是一种最简单便捷的路由动态修改能力了,这里展示基于spring cloud config实现Spring Cloud Gateway动态路由修改。
/**
* a route definition locator, that locate route definition from remote config server or local properties file.
* route definition is json value, not yaml value, e.g.
* "route-definitions=[\\"id\\": \\"websocket_test\\",\\"uri\\": \\"ws://localhost:9000\\",\\"order\\": 9000,\\"predicates\\":[\\"Path=/echo\\"],\\"filters\\":[\\"AddRequestHeader=x-tt-token, 123456\\"]]"
* or
* "route-definitions=[\\"id\\": \\"websocket_test\\",\\"uri\\": \\"ws://localhost:9000\\",\\"order\\": 9000,\\"predicates\\":[\\"name\\":\\"Path\\", \\"args\\":\\"_genkey_0\\":\\"/echo\\"],\\"filters\\":[\\"name\\":\\"AddRequestHeader\\", \\"args\\":\\"_genkey_0\\":\\"x-tt-token\\",\\"_genkey_1\\":\\"123456\\"]]"
*
* compare to spring cloud gateway's default InMemoryRouteDefinitionRepository, route definitions could be loaded when program's startup.
*
* to do this, there is another way. define a bean and load remote route definitions to InMemoryRouteDefinitionRepository when program's startup.
* otherwise, you should implement ApplicationListener<ApplicationEvent>. when refresh event emited, remote route definitions should be reloaded
* into InMemoryRouteDefinitionRepository.
*/
public class ConfigServerRouteDefinitionLocator implements RouteDefinitionLocator
@Value("$route-definitions")
private String routeDefinitions;//a json string, contains route definition lists
@Override
public Flux<RouteDefinition> getRouteDefinitions()
ObjectMapper mapper = new ObjectMapper();
List<RouteDefinition> rdList = null;
try
System.out.println(routeDefinitions);
rdList = mapper.readValue(routeDefinitions, new TypeReference<List<RouteDefinition>>() );
return Flux.fromArray(rdList.toArray(new RouteDefinition[]));
catch (JsonProcessingException e)
e.printStackTrace();
return Flux.empty();
方法很简单,只需要在config server里增加一个路由的配置项即可。config server可以调用Spring Cloud Gateway的路由更新接口/refresh
,路由配置就会自动更新。
如果要实现更复杂的控制逻辑,比如路由配置的路由校验、版本控制、灰度发布等其他功能,可以在定义自己的refresh接口和管理后台进行控制。
其他方式
如果时间允许,可以使用其他存储方式实现路由动态修改能力。可以参考以下文章:
基于Redis实现动态路由修改
基于Redis实现动态路由修改-其中的金丝雀是对上游的金丝雀发布,不是对网关自身的金丝雀控制,这种用法一般不太常见
以上是关于实现Spring Cloud Gateway路由动态加载及持久化的主要内容,如果未能解决你的问题,请参考以下文章
实现Spring Cloud Gateway路由动态加载及持久化
spring cloud gateway 某些路由中跳过全局过滤器
Spring Cloud Gateway——实现路由动态修改