2022-6月更文挑战26-利用SpringCloudGateway进行netty负载均衡

105 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情

利用SpringCloudGateway进行netty负载均衡

前文

本文内容为netty对于springcloud结合过程中遇到的问题。主要问题是项目通过springboot框架进行启动,并将其注册到注册中心上,同时采用单独的线程进行netty框架websocket服务的启动。而我们的问题时,当通过网关请求时,如何将网关中注册的springboot的端口,调整为我们netty服务中的端口,使长连接请求能够通过网关完成。

解决思路及方案

由于我们需要将请求信息的内容进行一定调整,因此很容易想到采用过滤器处理的方案。我们需要做的则是自定义一个处理类,当请求到达时网关时,我们通过过滤器,将端口由服务的注册端口修改为长连接的端口,即可完成通过网关的请求处理。

return choose(lbRequest, serviceId, supportedLifecycleProcessors).doOnNext(response -> {

   if (!response.hasServer()) {
      supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
            .onComplete(new CompletionContext<>(CompletionContext.Status.DISCARD, lbRequest, response)));
      throw NotFoundException.create(properties.isUse404(), "Unable to find instance for " + url.getHost());
   }

   ServiceInstance retrievedInstance = response.getServer();

   URI uri = exchange.getRequest().getURI();

   // if the `lb:<scheme>` mechanism was used, use `<scheme>` as the default,
   // if the loadbalancer doesn't provide one.
   String overrideScheme = retrievedInstance.isSecure() ? "https" : "http";
   if (schemePrefix != null) {
      overrideScheme = url.getScheme();
   }

   DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance(retrievedInstance,
         overrideScheme);

   URI requestUrl = reconstructURI(serviceInstance, uri);

   if (log.isTraceEnabled()) {
      log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
   }
   exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
   exchange.getAttributes().put(GATEWAY_LOADBALANCER_RESPONSE_ATTR, response);
   supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStartRequest(lbRequest, response));
}).then(chain.filter(exchange))
      .doOnError(throwable -> supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
            .onComplete(new CompletionContext<ResponseData, ServiceInstance, RequestDataContext>(
                  CompletionContext.Status.FAILED, throwable, lbRequest,
                  exchange.getAttribute(GATEWAY_LOADBALANCER_RESPONSE_ATTR)))))
      .doOnSuccess(aVoid -> supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
            .onComplete(new CompletionContext<ResponseData, ServiceInstance, RequestDataContext>(
                  CompletionContext.Status.SUCCESS, lbRequest,
                  exchange.getAttribute(GATEWAY_LOADBALANCER_RESPONSE_ATTR), buildResponseData(exchange,
                        loadBalancerProperties.isUseRawStatusCodeInResponseData())))));

如上图所示,实际上在高版本的网关源码中,只有通过响应式处理的负载均衡方式。而我们可以直接采用其中的代码,经过一定的修改作为我们自己使用的过滤器,如上面的代码所示。代码主要内容是按照示例的方式,因此粗暴的直接用端口直接替换的方式即可。如上图就是直接将12999的端口替换为12000的端口。而我们进行一下测试,访问网关端口20001进行长连接,测试结果如下。很明显,已经成功的通过网关进行了netty服务的路由。

image.png

后记

  • 千古兴亡多少事?悠悠。不尽长江滚滚流。