关于微服务:vivo-微服务-API-网关架构实践

64次阅读

共计 12454 个字符,预计需要花费 32 分钟才能阅读完成。

一、背景介绍

网关作为微服务生态中的重要一环,因为历史起因,中间件团队没有对立的微服务 API 网关,为此筹备技术预研打造一个功能齐全、可用性高的业务网关。

二、技术选型

常见的开源网关依照语言分类有如下几类:

  • Nginx+Lua:OpenResty、Kong 等;
  • Java:Zuul1/Zuul2、Spring Cloud Gateway、gravitee-gateway、Dromara Soul 等;
  • Go:janus、GoKu API Gateway 等;
  • Node.js:Express Gateway、MicroGateway 等。

因为团队内成员基本上为 Java 技术栈,因而并不打算深入研究非 Java 语言的网关。接下来咱们次要调研了 Zuul1、Zuul2、Spring Cloud Gateway、Dromara Soul。

业界支流的网关基本上能够分为上面三种:

  • Servlet + 线程池
  • NIO(Tomcat / Jetty) + Servlet 3.0 异步
  • NettyServer + NettyClient

在进行技术选型的时候,次要思考功能丰富度、性能、稳定性。在重复比照之后,决定抉择基于 Netty 框架进行网关开发;然而思考到工夫的紧迫性,最终抉择为针对 Zuul2 进行定制化开发,在 Zuul2 的代码骨架之下来欠缺网关的整个体系。

三、Zuul2 介绍

接下来咱们简要介绍一下 Zuul2 要害知识点。

Zuul2 的架构图:

为了解释下面这张图,接下来会别离介绍几个点

  • 如何解析 HTTP 协定
  • Zuul2 的数据流转
  • 两个责任链:Netty ChannelPipeline 责任链 + Filter 责任链

3.1 如何解析 HTTP 协定

学习 Zuul2 须要肯定的铺垫常识,比方:Google Guice、RxJava、Netflix archaius 等,然而更要害的应该是:如何解析 HTTP 协定,会影响到后续 Filter 责任链的原理解析,为此先剖析这个关键点。

首先咱们介绍官网文档中的一段话:

By default Zuul doesn’t buffer body content, meaning it streams the received headers to the origin before the body has been received.

This streaming behavior is very efficient and desirable, as long as your filter logic depends on header data.

翻译成中文:

默认状况下 Zuul2 并不会缓存申请体,也就意味着它可能会先发送接管到的申请 Headers 到后端服务,之后接管到申请体再持续发送到后端服务,发送申请体的时候,也不是组装为一个残缺数据之后才发,而是接管到一部分,就转发一部分。

这个流式行为是高效的,只有 Filter 过滤的时候只依赖 Headers 的数据进行逻辑解决,而不须要解析 RequestBody。

下面这段话映射到 Netty Handler 中,则意味着 Zuul2 并没有应用 HttpObjectAggregator。

咱们先看一下惯例的 Netty Server 解决 HTTP 协定的样例:

NettyServer 样例

@Slf4j
public class ConfigServerBootstrap {public static final int WORKER_THREAD_COUNT = Runtime.getRuntime().availableProcessors();
 
    public void start(){
        int port = 8080;
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup(WORKER_THREAD_COUNT);
 
        final BizServerHandler bizServerHandler = new BizServerHandler();
 
        try {ServerBootstrap serverBootstrap = new ServerBootstrap();
 
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<Channel>() {
                        @Override
                        protected void initChannel(Channel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new IdleStateHandler(10, 10, 0));
                            pipeline.addLast(new HttpServerCodec());
                            pipeline.addLast(new HttpObjectAggregator(500 * 1024 * 1024));
                            pipeline.addLast(bizServerHandler);
                        }
                    });
            log.info("start netty server, port:{}", port);
            serverBootstrap.bind(port).sync();} catch (InterruptedException e) {bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
            log.error(String.format("start netty server error, port:%s", port), e);
        }
    }
}

这个例子中的两个要害类为:HttpServerCodec、HttpObjectAggregator。

HttpServerCodec 是 HttpRequestDecoder、HttpResponseEncoder 的组合器。

  • HttpRequestDecoder 职责: 将输出的 ByteBuf 解析成 HttpRequest、HttpContent 对象。
  • HttpResponseEncoder 职责: 将 HttpResponse、HttpContent 对象转换为 ByteBuf,进行网络二进制流的输入。

HttpObjectAggregator 的作用:组装 HttpMessage、HttpContent 为一个残缺的 FullHttpRequest 或者 FullHttpResponse。

当你不想关怀 chunked 分块传输的时候,应用 HttpObjectAggregator 是十分有用的。

HTTP 协定通常应用 Content-Length 来标识 body 的长度,在服务器端,须要先申请对应长度的 buffer,而后再赋值。如果须要一边生产数据一边发送数据,就须要应用 ”Transfer-Encoding: chunked” 来代替 Content-Length,也就是对数据进行分块传输。

接下来咱们看一下 Zuul2 为了解析 HTTP 协定做了哪些解决。

Zuul 的源码:https://github.com/Netflix/zuul,基于 v2.1.5。

// com.netflix.zuul.netty.server.BaseZuulChannelInitializer#addHttp1Handlers
protected void addHttp1Handlers(ChannelPipeline pipeline) {pipeline.addLast(HTTP_CODEC_HANDLER_NAME, createHttpServerCodec());
 
    pipeline.addLast(new Http1ConnectionCloseHandler(connCloseDelay));
    pipeline.addLast("conn_expiry_handler",
            new Http1ConnectionExpiryHandler(maxRequestsPerConnection, maxRequestsPerConnectionInBrownout, connectionExpiry));
}
// com.netflix.zuul.netty.server.BaseZuulChannelInitializer#createHttpServerCodec
protected HttpServerCodec createHttpServerCodec() {
    return new HttpServerCodec(MAX_INITIAL_LINE_LENGTH.get(),
            MAX_HEADER_SIZE.get(),
            MAX_CHUNK_SIZE.get(),
            false
    );
}

通过比照下面的样例发现,Zuul2 并没有增加 HttpObjectAggregator,也就是须要自行去解决 chunked 分块传输问题、自行组装申请体数据。

为了解决下面说的 chunked 分块传输问题,Zuul2 通过判断是否 LastHttpContent,来判断是否接管实现。

3.2 Zuul2 数据流转

如上图所示,Netty 自带的 HttpServerCodec 会将网络二进制流转换为 Netty 的 HttpRequest 对象,再通过 ClientRequestReceiver 编解码器将 HttpRequest 转换为 Zuul 的申请对象 HttpRequestMessageImpl;

申请体 RequestBody 在 Netty 自带的 HttpServerCodec 中被映射为 HttpContent 对象,ClientRequestReceiver 编解码器顺次接管 HttpContent 对象。

实现了上述数据的转换之后,就流转到了最重要的编解码 ZuulFilterChainHandler,外面会执行 Filter 链,也会发动网络申请到真正的后端服务,这一切都是在 ZuulFilterChainHandler 中实现的。

失去了后端服务的响应后果之后,也通过了 Outbound Filter 的过滤,接下来就是通过 ClientResponseWriter 把 Zuul 自定义的响应对象 HttpResponseMessageImpl 转换为 Netty 的 HttpResponse 对象,而后通过 HttpServerCodec 转换为 ByteBuf 对象,发送网络二进制流,实现响应后果的输入。

这里须要特地阐明的是:因为 Zuul2 默认不组装一个残缺的申请对象 / 响应对象,所以 Zuul2 是别离针对申请头 + 申请 Headers、申请体进行 Filter 过滤拦挡的,也就是说对于申请,会走两遍前置 Filter 链,对于响应后果,也是会走两遍后置 Filter 链拦挡。

3.3  两个责任链

3.3.1 Netty ChannelPipeline 责任链

Netty 的 ChannelPipeline 设计,通过往 ChannelPipeline 中动静增减 Handler 进行定制扩大。

接下来看一下 Zuul2 Netty Server 中的 pipeline 有哪些 Handler?

接着持续看一下 Zuul2 Netty Client 的 Handler 有哪些?

本文不针对具体的 Handler 进行具体解释,次要是给大家一个整体的视图。

3.3.2 Filter 责任链

申请发送到 Netty Server 中,先进行 Inbound Filters 的拦挡解决,接着会调用 Endpoint Filter,这里默认为 ProxyEndPoint(外面封装了 Netty Client),发送申请到实在后端服务,获取到响应后果之后,再执行 Outbound Filters,最终返回响应后果。

三种类型的 Filter 之间是通过 nextStage 属性来连接的。

Zuul2 存在一个定时工作线程 GroovyFilterFileManagerPoller,定期扫描特定的目录,通过比对文件的更新工夫戳,来判断是否发生变化,如果有变动,则从新编译并放入到内存中。

通过定位工作实现了 Filter 的动静加载。

四、性能介绍

下面介绍了 Zuul2 的局部知识点,接下来介绍网关的整体性能。

4.1 服务注册发现

网关承当了申请转发的性能,须要肯定的办法用于动静发现后端服务的机器列表。

这里提供两种形式进行服务的注册发现:

集成网关 SDK

  • 网关 SDK 会在服务启动之后,监听 ContextRefreshedEvent 事件,被动操作 zk 注销信息到 zookeeper 注册核心,这样网关服务、网关治理后盾就能够订阅节点信息。
  • 网关 SDK 增加了 ShutdownHook,在服务下线的时候,会删除注销在 zk 的节点信息,用于告诉网关服务、网关治理后盾,节点已下线。

手工配置服务的机器节点信息

  • 在网关治理后盾,手工增加、删除机器节点。
  • 在网关治理后盾,手工设置节点上线、节点下线操。

为了避免 zookeeper 故障,网关治理后盾已提供 HTTP 接口用于注册、勾销注册作为兜底措施。

4.2 动静路由

动静路由分为:机房就近路由、灰度路由 (相似于 Dubbo 的标签路由性能)。

  • 机房就近路由: 申请最好是不要跨机房,比方申请打到网关服务的 X 机房,那么也应该是将申请转发给 X 机房的后端服务节点,如果后端服务不存在 X 机房的节点,则申请到其余机房的节点。
  • 灰度路由: 相似于 Dubbo 的标签路由性能,如果心愿对后端服务节点进行分组隔离,则须要给后端服务一个标签名,建设 ” 标签名→节点列表 ” 的映射关系,申请方携带这个标签名,申请到相应的后端服务节点。

网关治理后盾反对动静配置路由信息,动静开启 / 敞开路由性能。

4.3 负载平衡

以后反对的负载平衡策略:加权随机算法、加权轮询算法、一致性哈希算法。

能够通过网关治理后盾动静调整负载平衡策略,反对 API 接口级别、利用级别的配置。

负载平衡机制并未采纳 Netflix Ribbon,而是仿造 Dubbo 负载平衡的算法实现的。

4.4 动静配置

API 网关反对一套自洽的动静配置性能,在不依赖第三方配置核心的条件下,依然反对实时调整配置项,并且配置项分为全局配置、利用级别治理配置、API 接口级别治理配置。

在自洽的动静配置性能之外,网关服务也与公司级别的配置核心进行买通,反对公司级配置核心配置相应的配置项。

4.5 API 治理

API 治理反对网关 SDK 主动扫描上报,也反对在治理后盾手工配置。

4.6 协定转换

后端的服务有很多是基于 Dubbo 框架的,网关服务反对 HTTP→HTTP 的申请转发,也反对 HTTP→Dubbo 的协定转换。

同时 C ++ 技术栈,采纳了 tars 框架,网关服务也反对 HTTP → tras 协定转换。

4.7 平安机制

API 网关提供了 IP 黑白名单、OAuth 认证受权、appKey&appSecret 验签、矛盾加解密、vivo 登录态校验的性能。

4.8 监控 / 告警

API 网关通过对接通用监控上报申请访问信息,对 API 接口的 QPS、申请响应吗、申请响应工夫等进行监控与告警;

通过对接根底监控,对网关服务本身节点进行 CPU、IO、内存、网络连接等数据进行监控。

4.9 限流 / 熔断

API 网关与限流熔断零碎进行买通,能够在限流熔断零碎进行 API 接口级别的配置,比方熔断配置、限流配置,而无需业务零碎再次对接限流熔断组件。

限流熔断零碎提供了对 Netflix Hystrix、Alibaba Sentinel 组件的封装。

4.10 无损公布

业务零碎的无损公布,这里分为两种场景介绍:

  • 集成了网关 SDK: 网关 SDK 增加了 ShutdownHook,会被动从 zookeeper 删除注销的节点信息,从而防止申请打到行将下线的节点。
  • 未集成网关 SDK: 如果什么都不做,则只能依赖网关服务的心跳检测性能,会有 15s 的流量损失。庆幸的是治理后盾提供了流量摘除、流量复原的操作按钮,反对动静的上线、下线机器节点。

网关集群的无损公布:咱们思考了后端服务的无损公布,然而也须要思考网关节点本身的无损公布,这里咱们不再反复造轮子,间接应用的是 CICD 零碎的 HTTP 无损公布性能(Nginx 动静摘除 / 上线节点)。

4.11 网关集群分组隔离

网关集群的分组隔离指的是业务与业务之间的申请应该是隔离的,不应该被局部业务申请打垮了网关服务,从而导致了别的业务申请无奈解决。

这里咱们会对接入网关的业务进行分组归类,不同的业务应用不同的分组,不同的网关分组,会部署独立的网关集群,从而隔离了危险,不必再放心业务之间的相互影响。

五、零碎架构

5.1 模块交互图

5.2 网关治理后盾

模块划分

5.3 通信机制

因为须要动静的下发配置,比方全局开关、利用级别的治理配置、接口级别的治理配置,就须要网关治理后盾能够与网关服务进行通信,比方推拉模式。

两种设计方案

  • 基于注册核心的订阅告诉机制
  • 基于 HTTP 的推模式 + 定时拉取

这里并未采纳第一种计划,次要是因为以下毛病:

  • 重大依赖 zk 集群的稳定性
  • 信息不私密 (zk 集群权限管控能力较弱、放心被误删)
  • 无奈灰度下发配置,比方只对其中的一台网关服务节点配置失效

5.3.1 基于 HTTP 的推模式

因为 Zuul2 自身就自带了 Netty Server,同理也能够再多启动一个 Netty Server 提供 HTTP 服务,让治理后盾发送 HTTP 申请到网关服务,进而发送配置数据到网关服务了。

所以图上的蓝色标记 Netty Server 用于接管客户端申请转发到后端节点,紫色标记 Netty Server 用于提供 HTTP 服务,接管配置数据。

5.3.2 全量配置拉取

网关服务在启动之初,须要发送 HTTP 申请到治理后盾拉取全副的配置数据,并且也须要拉取归属以后节点的灰度配置 (只对这个节点失效的试验性配置)。

5.3.3 增量配置定时拉取

下面提到了 ” 基于 HTTP 的推模式 ” 进行配置的动静推送,也介绍了全局配置拉取,为了保险起见,网关服务还是新增了一个定时工作,用于定时拉取增量配置。

能够了解为兜底操作,就好比配置核心反对长轮询获取数据实时变更 + 定时工作获取全副数据。

在拉取到增量配置之后,会比对内存中的配置数据是否统一,如果统一,则不操作间接抛弃。

5.3.4 灰度配置下发

下面也提到了 ” 灰度配置 ” 这个词,这里具体解释一下什么是灰度配置?

比方当编辑了某个接口的限流信息,心愿在某个网关节点运行一段时间,如果没有问题,则调整配置让全副的网关服务节点失效,如果有问题,则也只是其中一个网关节点的申请流量出问题。

这样能够升高出错的概率,当某个比拟大的改变或者版本上线的时候,能够管制灰度部署一台机器,同时配置也只灰度到这台机器,这样危险就升高了很多。

灰度配置:能够了解为只在某些网关节点失效的配置。

灰度配置下发其实也是通过 ”5.3.1 基于 HTTP 的推模式 ” 来进行下发的。

5.4 网关 SDK

网关 SDK 旨在实现后端服务节点的注册与下线、API 接口列表数据上报,通过接入网关 SDK 即可缩小手工操作。网关 SDK 通过 ZooKeeper client 操作节点的注册与下线,通过发动 HTTP 申请进行 API 接口数据的上报。

反对 SpringMVC、SpringBoot 的 web 接口主动扫描、Dubbo 新老版本的 Service 接口扫描。

Dubbo 接口上报:

  • 旧版 Dubbo: 自定义 BeanPostProcessor,用于提取到 ServiceBean,放入线程池异步上报到网关后盾。
  • 新版 Dubbo: 自定义 ApplicationListener,用于监听 ServiceBeanExportedEvent 事件,提取 event 信息,上报到网关后盾。

HTTP 接口上报:

  • 自定义 BeanPostProcessor,用于提取到 Controller、RestController 的 RequestMapping 注解,放入线程池异步上报 API 信息。

六、革新之路

6.1 动静配置

关联知识点:

  • https://github.com/apache/commons-configuration
  • https://github.com/Netflix/archaius

Zuul2 依赖的动静配置为 archaius,通过扩大 ConcurrentMapConfiguration 增加到 ConcurrentCompositeConfiguration 中。

新增 GatewayConfigConfiguration,用于存储全局配置、治理配置、节点信息、API 数据等。

@Singleton
public class GatewayConfigConfiguration extends ConcurrentMapConfiguration {public GatewayConfigConfiguration() {
        /**
         * 设置这个值为 true,才能够防止 archaius 强行去除 value 的类型,导致获取报错
         * see com.netflix.config.ConcurrentMapConfiguration#setPropertyImpl(java.lang.String, java.lang.Object)
         */
        this.setDelimiterParsingDisabled(Boolean.TRUE);
    }
 
}

通过 Google Guice 管制 Bean 的加载程序,在较早的机会,执行 ConfigurationManager.getConfigInstance(),获取到 ConcurrentCompositeConfiguration,实现 GatewayConfigConfiguration 的初始化,而后再插入到第一个地位。

后续只须要对 GatewayConfigConfiguration 进行配置的增删查改操作即可。

6.2 路由机制

路由机制也是仿造的 Dubbo 路由机制,灰度路由是仿造的 Dubbo 的标签路由,就近路由能够了解为同机房路由。

申请处理过程:

客户端申请过去的时候,网关服务会通过 path 前缀提取到对应的后端服务名或者在申请 Header 中指定传递对应的 serviceName,而后只在匹配到的后端服务中,持续 API 匹配操作,如果匹配到 API,则筛选出对应的后端机器列表,而后进行路由、负载平衡,最终选中一台机器,将申请转发过来。

这里会有个疑难,如果不心愿只在某个后端服务中进行申请路由匹配,是心愿在一堆后端服务中进行匹配,须要怎么操作?

在前面的第七章节会解答这个疑难,请急躁浏览。

6.2.1 就近路由

当申请到网关服务,会提取网关服务本身的机房 loc 属性值,读取全局、利用级别的开关,如果就近路由开关关上,则筛选服务列表的时候,会过滤雷同 loc 的后端机器,负载平衡的时候,在雷同 loc 的机器列表中筛选一台进行申请。

如果没有雷同 loc 的后端机器,则降级从其余 loc 的后端机器中进行筛选。

 

其中 loc 信息就是机房信息 ,每个后端服务节点在 SDK 上报或者手工录入的时候,都会携带这个值。

6.2.2 灰度路由

灰度路由须要用户传递 Header 属性值,比方 gray=canary_gray。

网关治理后盾配置灰度路由的时候,会建设 grayName -> List<Server> 映射关系,当网关治理后盾增量推送到网关服务之后,网关服务就能够通过 grayName 来提取配置下的后端机器列表,而后再进行负载平衡筛选机器。

如下图所示:

6.3 API 映射匹配

网关在进行申请转发的时候,须要明确晓得申请哪一个服务的哪一个 API,这个过程就是 API 匹配。

因为不同的后端服务可能会领有雷同门路的 API,所以网关要求申请传递 serviceName,serviceName 能够搁置于申请 Header 或者申请参数中。

携带了 serviceName 之后,就能够在后端服务的 API 中去匹配了,有一些是相等匹配,有些是正则匹配,因为 RESTFul 协定,须要反对 /* 通配符匹配。

这里会有人疑难了,难道申请肯定须要显式传递 serviceName 吗?

为了解决这个问题,创立了一个 gateway\_origin\_mapping 表,用于 path 前缀或者域名前缀 映射到 serviceName,通过在治理后盾建设这个映射关系,而后推送到网关服务,即可解决显式传递 serviceName 的问题,会主动提取申请的 path 前缀、域名前缀,找到对应的 serviceName。

如果不心愿是在一个后端服务中进行 API 匹配,则需浏览前面的第七章节。

6.4 负载平衡

替换 ribbon 组件,改为仿造 Dubbo 的负载平衡机制。

public interface ILoadBalance {
 
    /**
     * 从服务列表中筛选一台机器进行调用
     * @param serverList
     * @param originName
     * @param requestMessage
     * @return
     */
    DynamicServer select(List<DynamicServer> serverList, String originName, HttpRequestMessage requestMessage);
 
}

替换的理由:ribbon 的服务列表更新只是定期更新,如果不思考简单的筛选过滤,是满足要求的,然而如果想要灵便的依据申请头、申请参数进行筛选,ribbon 则不太适宜。

6.5 心跳检测

外围思路:当网络申请失常返回的时候,心跳检测是不须要,此时后端服务节点必定是失常的,只须要定期检测未被申请的后端节点,超过肯定的谬误阈值,则标记为不可用,从机器列表中剔除。

第一期先实现简略版本:通过定时工作定期去异步调用心跳检测 Url,如果超过失败阈值,则从从负载平衡列表中剔除。

异步申请采纳 httpasyncclient 组件解决。

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpasyncclient</artifactId>
    <version>4.1.4</version>
</dependency>

计划为:HealthCheckScheduledExecutor + HealthCheckTask + HttpAsyncClient。

6.6 日志异步化革新

Zuul2 默认采纳的 log4j 进行日志打印,是同步阻塞操作,须要批改为异步化操作,改为应用 logback 的 AsyncAppender。

日志打印也是影响性能的一个关键点,须要特地留神,后续会掂量是否切换为 log4j2。

6.7 协定转换

HTTP -> HTTP

Zuul2 采纳的是 ProxyEndpoint 用于反对 HTTP -> HTTP 协定转发。

通过 Netty Client 的形式发动网络申请到实在的后端服务。

HTTP -> Dubbo

采纳 Dubbo 的泛化调用实现 HTTP -> Dubbo 协定转发,能够采纳 $invokeAsync。

HTTP → Tars

基于 tars-java 采纳相似于 Dubbo 的泛化调用的形式实现协定转发,基于 https://github.com/TarsCloud/TarsGateway 革新而来的。

6.8 无损公布

网关作为申请转发,当然心愿在业务后端机器部署的期间,不应该把申请转发到还未部署实现的节点。

业务后端机器节点的无损公布,这里分为两种场景介绍:

  • 集成了网关 SDK 网关 SDK 增加了 ShutdownHook,会被动从 zookeeper 删除注销的节点信息,从而防止申请打到行将下线的节点。
  • 未集成网关 SDK  如果什么都不做,则只能依赖网关服务的心跳检测性能,会有 15s 的流量损失。庆幸的是治理后盾提供了流量摘除、流量复原的操作按钮,反对动静的上线、下线机器节点。

设计方案

咱们给后端机器节点 dynamic\_forward\_server 表新增了一个字段 online,如果 online=1,则代表在线,接管流量,反之,则代表下线,不接管流量。

网关服务 gateway-server 新增一个路由:OnlineRouter,从后端机器列表中筛选 online= 1 的机器,过滤掉不在线的机器,则实现了无损公布的性能。

public interface IRouter {
 
    /**
     * 过滤
     * @param serverList
     * @param originName
     * @param requestMessage
     * @return
     */
    List<DynamicServer> route(List<DynamicServer> serverList, String originName, HttpRequestMessage requestMessage);
 
}

6.9 网关集群分组隔离

网关集群的分组隔离指的是业务与业务之间的申请应该是隔离的,不应该被局部业务申请打垮了网关服务,从而导致了别的业务申请无奈解决。

这里咱们会对接接入网关的业务进行分组归类,不同的业务应用不同的分组,不同的网关分组,会部署独立的网关集群,从而隔离了危险,不必再放心业务之间的相互影响。

举例:

金融业务在生产环境存在一个灰度点检环境,为了配合金融业务的迁徙,这边也必须有一套独立的环境为之服务,那是否重新部署一套全新的零碎呢 (独立的前端 + 独立的治理后盾 + 独立的网关集群)

其实不用这么操作,咱们只须要部署一套独立的网关集群即可,因为网关治理后盾,能够同时配置多个网关分组的数据。

创立一个新的网关分组 finance-gray,而新的网关集群只须要拉取 finance-gray 分组的配置数据即可,不会对其余网关集群造成任何影响。

七、. 如何疾速迁徙业务

在业务接入的时候,现有的网关呈现了一个难堪的问题,当某些业务方自行搭建了一套 Spring Cloud Gateway 网关,外面的服务没有清晰的 path 前缀、独立的域名拆分,尽管是微服务体系,然而大家共用一个域名,接口前缀也没有良好的划分,混用在一起。

这个时候如果再依照原有的申请解决流程,则须要业务方进行 Nginx 的大量批改,须要在 location 的中央都显式传递 serviceName 参数,然而业务方不违心进行这一个调整。

针对这个问题,其实实质起因在于申请匹配逻辑的不一致性,现有的网关是先匹配服务利用,再进行 API 匹配,这样效率高一些,而 Spring Cloud Gateway 则是先 API 匹配,命中了才晓得是哪个后端服务。

为了解决这个问题,网关再次建设了一个 “ 微服务集 ” → “ 微服务利用列表 ” 的映射关系,治理后盾反对这个映射关系的推送。

一个网关分组上面会有很多应用服务,这里能够拆分为子集合,能够了解为微服务集就是外面的子集合。

客户端申请传递过去的时候,须要在申请 Header 传递 scTag 参数 ,scTag 用来标记是哪个微服务集,而后提取到 scTag 对应的所有后端服务利用列表,顺次去对应的应用服务列表中进行 API 匹配,如果命中了,则代表申请转发到以后利用的后端节点,而对原有的架构革新很小。

如果不想改变客户端申请,则须要在业务域名的 Nginx 上进行调整,传递 scTag 申请 Header。

作者:Lin Chengjun

正文完
 0