spring cloud kubernetes在pod模式下服务调用源码解析

Posted 水中加点糖

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring cloud kubernetes在pod模式下服务调用源码解析相关的知识,希望对你有一定的参考价值。

之所以只看pod模式下的服务调用链路,是因为在service模式下不会走缓存,效率低,并且负载均衡模式不能由spring cloud框架所控制,不太灵活


需要关注的几个类:

DiscoveryClient

org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient

org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient#choose(java.lang.String, org.springframework.cloud.client.loadbalancer.Request)

    public <T> ServiceInstance choose(String serviceId, Request<T> request) 
        ReactiveLoadBalancer<ServiceInstance> loadBalancer = this.loadBalancerClientFactory.getInstance(serviceId);
        if (loadBalancer == null) 
            return null;
         else 
            Response<ServiceInstance> loadBalancerResponse = (Response)Mono.from(loadBalancer.choose(request)).block();
            return loadBalancerResponse == null ? null : (ServiceInstance)loadBalancerResponse.getServer();
        
    

org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory#getInstance

    public ReactiveLoadBalancer<ServiceInstance> getInstance(String serviceId) 
        return (ReactiveLoadBalancer)this.getInstance(serviceId, ReactorServiceInstanceLoadBalancer.class);
    

feign调用
implements ReactorServiceInstanceLoadBalancer

feign调用时用的org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient中的execute方法调用的。
其中获取服务列表的代码为:ServiceInstance instance = loadBalancerClient.choose(serviceId, lbRequest);
也就是org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient#choose(java.lang.String, org.springframework.cloud.client.loadbalancer.Request)这个方法,其中用的此方法:

ReactiveLoadBalancer<ServiceInstance> loadBalancer = this.loadBalancerClientFactory.getInstance(serviceId);

其中的loadBalancerClientFactory字段是在BlockingLoadBalancerClient初始化时设置的。需要看一下loadBalancerClientFactory传入的地方。
也就是org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient类初始化时LoadBalancerClient注入进去的是哪个类。
这个类的属于commons的包里,看一下其中loadbalancer中关于初始化的地方。

代码在此处:
org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration#blockingLoadBalancerClient

@Bean
	@ConditionalOnBean(LoadBalancerClientFactory.class)
	@ConditionalOnMissingBean
	public LoadBalancerClient blockingLoadBalancerClient(LoadBalancerClientFactory loadBalancerClientFactory) 
		return new BlockingLoadBalancerClient(loadBalancerClientFactory);
	

这里注入了一个LoadBalancerClientFactory,这经的注入代码在此处:org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration#loadBalancerClientFactory

@ConditionalOnMissingBean
	@Bean
	public LoadBalancerClientFactory loadBalancerClientFactory(LoadBalancerClientsProperties properties) 
		LoadBalancerClientFactory clientFactory = new LoadBalancerClientFactory(properties);
		clientFactory.setConfigurations(this.configurations.getIfAvailable(Collections::emptyList));
		return clientFactory;
	

这个factory的代码中的getInstance方法:

@Override
	public ReactiveLoadBalancer<ServiceInstance> getInstance(String serviceId) 
		return getInstance(serviceId, ReactorServiceInstanceLoadBalancer.class);
	

获取的是ReactorServiceInstanceLoadBalancer.class

则需要找到ReactorServiceInstanceLoadBalancer的实现类:
org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration#reactorServiceInstanceLoadBalancer

@Bean
	@ConditionalOnMissingBean
	public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment,
			LoadBalancerClientFactory loadBalancerClientFactory) 
		String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
		return new RoundRobinLoadBalancer(
				loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
	

其中用懒加载获取的ServiceInstanceListSupplier的bean。

那么如果是service模式下,其中的ServiceInstanceListSupplier的实现类为:org.springframework.cloud.kubernetes.client.loadbalancer.KubernetesClientServicesListSupplier,其初始化代码为:

	@Bean
	@ConditionalOnProperty(name = "spring.cloud.kubernetes.loadbalancer.mode", havingValue = "SERVICE")
	KubernetesServicesListSupplier kubernetesServicesListSupplier(Environment environment, CoreV1Api coreV1Api,
			KubernetesClientServiceInstanceMapper mapper, KubernetesDiscoveryProperties discoveryProperties,
			KubernetesNamespaceProvider kubernetesNamespaceProvider) 
		return new KubernetesClientServicesListSupplier(environment, mapper, discoveryProperties, coreV1Api,
				kubernetesNamespaceProvider);
	

如果是pod模式,则使用的默认的初始化代码:org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration.ReactiveSupportConfiguration#discoveryClientServiceInstanceListSupplier
其代码为:

@Bean
		@ConditionalOnBean(ReactiveDiscoveryClient.class)
		@ConditionalOnMissingBean
		@Conditional(DefaultConfigurationCondition.class)
		public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
				ConfigurableApplicationContext context) 
			return ServiceInstanceListSupplier.builder().withDiscoveryClient().withCaching().build(context);
		

其中withDiscoveryClient方法:

/**
	 * Sets a @link ReactiveDiscoveryClient-based
	 * @link DiscoveryClientServiceInstanceListSupplier as a base
	 * @link ServiceInstanceListSupplier in the hierarchy.
	 * @return the @link ServiceInstanceListSupplierBuilder object
	 */
	public ServiceInstanceListSupplierBuilder withDiscoveryClient() 
		if (baseCreator != null && LOG.isWarnEnabled()) 
			LOG.warn("Overriding a previously set baseCreator with a ReactiveDiscoveryClient baseCreator.");
		
		this.baseCreator = context -> 
			ReactiveDiscoveryClient discoveryClient = context.getBean(ReactiveDiscoveryClient.class);

			return new DiscoveryClientServiceInstanceListSupplier(discoveryClient, context.getEnvironment());
		;
		return this;
	

其中ReactiveDiscoveryClient的bean为:

@Bean
	@ConditionalOnMissingBean
	public KubernetesInformerReactiveDiscoveryClient kubernetesReactiveDiscoveryClient(
			KubernetesNamespaceProvider kubernetesNamespaceProvider, SharedInformerFactory sharedInformerFactory,
			Lister<V1Service> serviceLister, Lister<V1Endpoints> endpointsLister,
			SharedInformer<V1Service> serviceInformer, SharedInformer<V1Endpoints> endpointsInformer,
			KubernetesDiscoveryProperties properties) 
		return new KubernetesInformerReactiveDiscoveryClient(kubernetesNamespaceProvider, sharedInformerFactory,
				serviceLister, endpointsLister, serviceInformer, endpointsInformer, properties);
	

public class KubernetesInformerReactiveDiscoveryClient implements ReactiveDiscoveryClient

所以由此可以看出,k8s中pod模式下用的是KubernetesInformerReactiveDiscoveryClient。
所以如果想要到达k8s模式下的个性化定制,可以参考官方文档https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#hints-based-loadbalancing,
参考代码:
org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplierBuilder#withHints

以上是关于spring cloud kubernetes在pod模式下服务调用源码解析的主要内容,如果未能解决你的问题,请参考以下文章

正在使用 Kubernetes Spring Cloud 多个配置映射

Spring Cloud Kubernetes(二)

部署 spring-cloud-kubernetes kubernetes-hello-world-example 失败

#yyds干货盘点#spring-cloud-kubernetes官方demo运行实战

Spring Cloud Kubernetes 支持 Spring Cloud 负载均衡器吗?

在本地禁用 Spring Cloud Kubernetes