- 作者:老汪软件技巧
- 发表时间:2024-09-25 11:01
- 浏览量:
点上方蓝字,获取更多Spring干货
你好,我是柳岸花开。
在微服务架构中,负载均衡是确保系统高可用性和可靠性的重要机制之一。然而,随着 Spring Cloud 的升级,默认不再支持同步调用,这给一些依赖同步调用的应用带来了挑战。在本文中,我们将介绍如何通过自定义阻塞负载均衡客户端来解决这一问题。
背景
Spring Cloud 在最新版本中默认使用响应式编程模型,不再支持同步调用。这对于一些依赖同步调用逻辑的应用来说,可能会导致不兼容问题。因此,我们需要自定义一个阻塞负载均衡客户端来实现同步调用。
java.lang.IllegalStateException: block()/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;
}
CompletableFuture> f = 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 项目中实现更高效的负载均衡策略。如果您有任何问题或建议,欢迎在评论区留言讨论。