当前位置: 首页 > 知识库问答 >
问题:

Spring Cloud库伯内特斯的负载平衡问题

汝才良
2023-03-14

我们在库伯内特斯运行了Spring Boot服务,并且正在使用Spring Cloud库伯内特斯负载均衡器功能和RestTemboard来调用其他Spring Boot服务。我们这样做的主要原因之一是历史上的——因为之前我们使用Eureka在EC2中运行我们的服务进行服务发现,迁移后我们保持了Spring发现客户端/客户端负载平衡(更新依赖项等,以便它与Spring Cloud库伯内特斯项目一起工作)

我们有一个问题,当其中一个目标POD宕机时,java在一段时间内会多次请求失败。网noroutetohestexception(即spring负载平衡器仍在尝试发送到该pod)。

所以我有几个问题:

>

或者如果没有,我们需要添加一些其他配置来处理这个-例如重试/断路器等?

一个更普遍的问题是,Spring的客户端负载平衡为Kubernetes带来了什么好处?如果没有它,我们的服务仍然可以使用Kubernetes内置的服务/负载平衡功能调用其他服务,这应该可以解决POD自动下降的问题。Spring文档还讨论了如何从POD模式切换到SERVICE模式(https://docs.spring.io/spring-cloud-kubernetes/docs/current/reference/html/index.html#loadbalancer-对于kubernetes)。但这种服务模式不正是Kubernetes自动完成的吗?我想知道这里最简单的解决方案是否不是完全移除Spring负载平衡器?那么我们会失去什么呢?

共有2个答案

柏明亮
2023-03-14

这方面的更新:我们有了spring retry依赖项,但retry不起作用,因为默认情况下它只对get起作用,我们的大多数调用都是POST(但可以再次调用)。添加配置Spring。云负载平衡器。重试。RetryonLoperations:true修复了这一问题,因此,在第二次尝试时,应使用替代实例重试,以避免大多数失败。

我们还添加了一个RetryListener,用于在某些连接异常情况下清除服务的负载平衡器缓存:

@Configuration
public class RetryConfig {

    private static final Logger logger = LoggerFactory.getLogger(RetryConfig.class);
    
    // Need to use bean factory here as can't autowire LoadBalancerCacheManager -
    // - it's set to 'autowireCandidate = false' in LoadBalancerCacheAutoConfiguration
    @Autowired
    private BeanFactory beanFactory;
    
    @Bean 
    public CacheClearingLoadBalancedRetryFactory cacheClearingLoadBalancedRetryFactory(ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory) {
        return new CacheClearingLoadBalancedRetryFactory(loadBalancerFactory);
    }
    
    // Extension of the default bean that defines a retry listener
    public class CacheClearingLoadBalancedRetryFactory extends BlockingLoadBalancedRetryFactory {

        public CacheClearingLoadBalancedRetryFactory(ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory) {
            super(loadBalancerFactory);
        }

        @Override
        public RetryListener[] createRetryListeners(String service) {
            
            RetryListener cacheClearingRetryListener = new RetryListener() {
                
                @Override
                public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) { return true; }
                
                @Override
                public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {}

                @Override
                public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
                    
                    logger.warn("Retry for service {} picked up exception: context {}, throwable class {}", service, context, throwable.getClass());
                    
                    if (throwable instanceof ConnectTimeoutException || throwable instanceof NoRouteToHostException) {
                
                        try {   
                            LoadBalancerCacheManager loadBalancerCacheManager = beanFactory.getBean(LoadBalancerCacheManager.class);                                        
                            Cache loadBalancerCache = loadBalancerCacheManager.getCache(CachingServiceInstanceListSupplier.SERVICE_INSTANCE_CACHE_NAME);            
                            if (loadBalancerCache != null) {                    
                                boolean result = loadBalancerCache.evictIfPresent(service);
                                logger.warn("Load Balancer Cache evictIfPresent result for service {} is {}", service, result);                             
                            }                           
                        } catch(Exception e) {
                            logger.error("Failed to clear load balancer cache", e);
                        }
                    }
                }                               
            };
                
            return new RetryListener[] { cacheClearingRetryListener };              
        }
    }
}

这种方法有什么问题吗?可以将这样的东西添加到内置功能中吗?

李鸿
2023-03-14

发生这种情况时,目标实例不应该自动删除吗?所以它可能会发生一次,但之后目标吊舱列表将被修复?

要解决这个问题,你必须使用库伯内特斯的准备和活力探测。

准备就绪将在间隔期间检查应用程序拥有的endpoint的运行状况。如果应用程序失败,它会将您的播客标记为未准备好接受流量。因此,不会有任何流量流向该POD(副本)。

如果应用程序失败,活跃度将重新启动您的应用程序,因此您的容器或我们可以说POD将再次出现,一旦我们从应用程序K8s收到200个响应,您的POD将标记为准备好接受流量。

您可以在应用程序中创建简单endpoint,根据需要提供200或204的响应。

阅读更多:https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/

确保您的应用程序使用Kubernetes服务相互通信。

Application 1 > Kubernetes service of App 2 > Application 2 PODs

要启用基于库伯内特斯服务名称的负载平衡,请使用以下属性。然后负载均衡器将尝试使用地址调用应用程序,例如service-a.default.svc.cluster.local

spring.cloud.kubernetes.loadbalancer.mode=SERVICE

在Kubernetes上使用Spring云负载平衡器最典型的方法是服务发现。如果类路径上有任何DiscoveryClient,默认的Spring云负载平衡器配置将使用它来检查服务实例。因此,它只能从正在启动和运行的实例中进行选择。只需使用@EnableDiscoveryClients为Spring Boot应用程序添加注释,即可启用K8s本机服务发现。

参考:https://stackoverflow.com/a/68536834/5525824

 类似资料:
  • 我最近开始研究Kubernetes集群。在我们的集群中,对给定Kubernetes服务的网络调用流如下所示: 外部非K8S负载均衡器- 对于给定的服务,有两个副本。通过查看副本中容器的日志,我可以看到调用被路由到不同的pod。据我所知,我们还没有为Kubernetes中的服务明确设置任何负载平衡策略。 我有几个问题: 1)K8S是否有默认的负载平衡策略?我读过库贝-proxy和随机路由。它看起来绝

  • 什么是负载均衡器? 负载平衡改进了跨多个计算资源(如计算机、计算机群集、网络链路、中央处理器或磁盘驱动器)的工作负载分布 NodePort不是负载平衡器。(我知道一旦流量在集群内,kube proxy就会在pod之间进行负载平衡)我的意思是,最终用户点击http://NODEIP:30111(例如)访问应用程序的URL。即使POD之间的流量是负载平衡的,用户仍然会点击一个节点,即“节点”,它是K8

  • 我有一个包含 3 个节点的 Kubernetes 集群。 示例部署 我没有入口,但我有外部负载均衡器,可以轮询 80.11.12.10、80.11.12.11、 的流量。 所以我这样设置我的服务。 问题在于,由于现有的 kubernetes 服务负载均衡器,流量会获得两次负载均衡。除此之外,这是不必要的,它会破坏连接持久性。有没有办法强制 Kubernetes 在每个节点的本地机器 Pod 上转发

  • 我在两个节点上运行 Kubernetes,并在两个节点上部署一个应用程序(两个 pod,每个节点一个)。 这是一个Spring Boot应用程序。它使用OpenFygnd来实现服务可发现性。在应用程序中,我定义了一个一来控制程序,它有几个API和一个从API内部调用的@Autow的@Service。 每当我对其中一个API进行请求时,Kubernetes都会使用某种负载平衡来将流量路由到其中一个p

  • 我在pod中运行了高视频编码任务。这些任务在接收用户请求时运行,并且CPU密集型非常高。我想确保CPU使用率最低的pod应该在传入请求中接收。库伯内特斯有没有办法根据CPU使用率的百分比来平衡我的负载?

  • 在使用Google容器引擎时,人们会推荐GCP的本机负载平衡器还是Kubernetes服务type=负载平衡器选项? 人们推荐哪一种?