• 作者:老汪软件技巧
  • 发表时间:2024-09-25 11:01
  • 浏览量:

点上方蓝字,获取更多Spring干货

你好,我是柳岸花开。

在微服务架构中,负载均衡是确保系统高可用性和可靠性的重要机制之一。然而,随着 Spring Cloud 的升级,默认不再支持同步调用,这给一些依赖同步调用的应用带来了挑战。在本文中,我们将介绍如何通过自定义阻塞负载均衡客户端来解决这一问题。

背景

Spring Cloud 在最新版本中默认使用响应式编程模型,不再支持同步调用。这对于一些依赖同步调用逻辑的应用来说,可能会导致不兼容问题。因此,我们需要自定义一个阻塞负载均衡客户端来实现同步调用。

java.lang.IllegalStateExceptionblock()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-epoll-35
        at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:83)
        at reactor.core.publisher.Mono.block(Mono.java:1742)
        at org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient.choose(BlockingLoadBalancerClient.java:155)
        at org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient.execute(FeignBlockingLoadBalancerClient.java:97)
        at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:119)
        at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:89)
        at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:100)
        at org.springframework.cloud.openfeign.FeignCachingInvocationHandlerFactory$1.proceed(FeignCachingInvocationHandlerFactory.java:66)
        at org.springframework.cache.interceptor.CacheInterceptor.lambda$invoke$0(CacheInterceptor.java:54)
        at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:351)
        at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:64)
        at org.springframework.cloud.openfeign.FeignCachingInvocationHandlerFactory.lambda$create$1(FeignCachingInvocationHandlerFactory.java:53)
        at com.sun.proxy.$Proxy126.getPublicKey(Unknown Source)

自定义阻塞负载均衡客户端代码实现

负载均衡数据同步__负载均衡文件同步

首先,我们来看一下自定义阻塞负载均衡客户端的完整代码:


import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer;
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
import reactor.core.publisher.Mono;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@Slf4j
public class CustomBlockingLoadBalancerClient extends BlockingLoadBalancerClient {
    private final ReactiveLoadBalancer.Factory loadBalancerClientFactory;
    public CustomBlockingLoadBalancerClient(ReactiveLoadBalancer.Factory loadBalancerClientFactory) {
        super(loadBalancerClientFactory);
        this.loadBalancerClientFactory = loadBalancerClientFactory;
    }
    @Override
    public  ServiceInstance choose(String serviceId, Request request) {
        ReactiveLoadBalancer loadBalancer = loadBalancerClientFactory.getInstance(serviceId);
        if (loadBalancer == null) {
            return null;
        }
        CompletableFuturef = CompletableFuture.supplyAsync(() -> {
            Response loadBalancerResponse = Mono.from(loadBalancer.choose(request)).block();
            return loadBalancerResponse;
        });
        Response loadBalancerResponse = null;
        try {
            loadBalancerResponse = f.get();
        } catch (InterruptedException e) {
            log.warn("LoadBalancerClient.choose error", e);
        } catch (ExecutionException e) {
            log.warn("LoadBalancerClient.choose error", e);
        }
        if (loadBalancerResponse == null) {
            return null;
        }
        return loadBalancerResponse.getServer();
    }
}

代码解读类定义与继承构造方法choose 方法配置自定义负载均衡客户端

接下来,我们需要在 Spring 配置类中注册这个自定义的负载均衡客户端:


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class LoadBalancerConfig {
    @Autowired
    private LoadBalancerClientFactory loadBalancerClientFactory;
    @Bean
    public LoadBalancerClient blockingLoadBalancerClient() {
        return new CustomBlockingLoadBalancerClient(loadBalancerClientFactory);
    }
}

配置解读类注解自动注入Bean 定义结论

通过自定义阻塞负载均衡客户端,我们可以解决 Spring Cloud 升级后不再支持同步调用的问题。这种方法不仅能保持现有业务逻辑的稳定性,还能利用 Spring Cloud 的新特性提升系统的灵活性和可维护性。如果您在升级 Spring Cloud 时遇到类似问题,不妨尝试这种解决方案。

希望这篇文章能帮助您在 Spring Cloud 项目中实现更高效的负载均衡策略。如果您有任何问题或建议,欢迎在评论区留言讨论。