springcloud整合nacos实现相同版本实例相互调用

springcloud整合nacos实现相同版本实例相互调用

注: 本文为自己学习研究总结,仅供参考,若有侵权,请及时联系本人

业务场景

有时候一些新的业务或者修改后的功能只开放给部分人访问,那么可以新老版本都部署,对于大多数人访问老版本,部分人访问新版本。部分人请求的时候,http请求header添加特定的version值,结合nacos的服务元数据进行塞选服务实例,从而实现不同人访问相同的功能,对应不同的版本。

基础理论

(1)基于feign进行远程方法调用,首先FeignBlockingLoadBalancerClient会根据url中的serviceId,交给LoadBalancerClient#choose()方法拉取服务列表并且基于负载均衡算法选择一个服务实例,最后重构Uri发起请求

(2)RoundRobinLoadbalancer(轮询,springcloudloadbalance默认负载均衡实现,还有一个是随机负载均衡)为例,ServiceInstanceListSupplier#get()用于拉取服务实例,getInstanceResponse()用于负载均衡选择某个实例

coding

demo如下:

java 复制代码
import com.google.common.collect.Lists;
import com.test.server.util.GreyThreadLocalUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.DelegatingServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import reactor.core.publisher.Flux;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Slf4j
public class SameVersionServiceInstanceListSupplier extends DelegatingServiceInstanceListSupplier {
    private final String VERSION = "version";

    public SameVersionServiceInstanceListSupplier(ServiceInstanceListSupplier delegate) {
        super(delegate);
    }

    @Override
    public Flux<List<ServiceInstance>> get() {
        ServiceInstanceListSupplier delegate1 = getDelegate();
        Flux<List<ServiceInstance>> listFlux = delegate1.get();
        Flux<List<ServiceInstance>> map = listFlux.map(this::filteredByVersion);
        return map;
    }

    /**
     * 根据version进行过滤
     * @param serviceInstances
     * @return
     */
    private List<ServiceInstance> filteredByVersion(List<ServiceInstance> serviceInstances) {
        List<ServiceInstance> filteredInstances = new ArrayList<>();
        for (ServiceInstance serviceInstance : serviceInstances) {
            String instanceVersion = getVersion(serviceInstance);
            if (GreyThreadLocalUtils.getVersion().equalsIgnoreCase(instanceVersion)) {
                filteredInstances.add(serviceInstance);
            }
        }
        if (filteredInstances.size() > 0) {
            return filteredInstances;
        }
        return Lists.newArrayList();
    }

    /**
     * 从元数据获取version值
     * @param serviceInstance
     * @return
     */
    private String getVersion(ServiceInstance serviceInstance) {
        Map<String, String> metadata = serviceInstance.getMetadata();
        if (metadata != null) {
            return metadata.get(VERSION);
        }
        return null;
    }
}
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.cloud.loadbalancer.support.SimpleObjectProvider;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

@Component
@Configuration(proxyBeanMethods = false)
public class LoadBalanceConfig {

    /**
     * 支持的服务实例
     * @param context
     * @return
     */
    @Bean
    public ServiceInstanceListSupplier serviceInstanceListSupplier(ConfigurableApplicationContext context) {
        ServiceInstanceListSupplier supplier = ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient().withCaching().build(context);
        return new SameVersionServiceInstanceListSupplier(supplier);
    }

    /**
     * 负载均衡方式
     * @param environment
     * @param serviceInstanceListSupplier
     * @return
     */
    @Bean
    public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment, ServiceInstanceListSupplier serviceInstanceListSupplier) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RoundRobinLoadBalancer(new SimpleObjectProvider<>(serviceInstanceListSupplier), name);
    }
}
/**
 * 注入了spring容器
 */
@Configuration(proxyBeanMethods = false)
@LoadBalancerClients(defaultConfiguration = LoadBalanceConfig.class)
@AutoConfigureBefore({ ReactorLoadBalancerClientAutoConfiguration.class,
        LoadBalancerBeanPostProcessorAutoConfiguration.class })
public class LoadBalanceAutoConfiguration {
}

参考资料

(1) https://mp.weixin.qq.com/s/rsRGMRiRb0atKclPl2K1zg

(2) 黑马程序员 java黑马商城项目微服务实战开发视频讲解

相关推荐
code_slave(码畜)5 小时前
微服务架构落地:基础服务 —— 报表服务(中篇:元数据、查询引擎、缓存与权限落地)
spring boot·spring cloud·缓存·微服务·架构
code_slave(码畜)6 小时前
微服务架构落地:基础服务 —— 报表服务(AI 集成篇:AI 增强报表能力)
人工智能·spring boot·spring cloud·微服务·架构
code_slave(码畜)7 小时前
微服务架构落地:公共中间件层总览——不承载业务,只承载稳定性
spring boot·spring cloud·微服务·中间件·架构
Thomas.Sir15 小时前
第13课:Spring Cloud LoadBalancer 新版负载均衡核心原理
spring cloud·负载均衡
code_slave(码畜)15 小时前
微服务架构落地:基础服务 —— 报表服务(上篇:定位、边界与整体架构)
java·spring boot·spring cloud·微服务·架构
Thomas.Sir1 天前
第12课:Nacos 配置加密、版本回溯、配置监听 & 生产风控方案
spring cloud·nacos
贾斯汀frank2 天前
Spring Boot + K8s + Istio 与 Spring Cloud:微服务治理能力对比
spring cloud·微服务·istio
Thomas.Sir2 天前
第11课:Nacos 多环境、多服务配置隔离 & 配置优先级详解
spring cloud·微服务·nacos
Thomas.Sir4 天前
第8课:Nacos健康检测、权重配置、环境隔离实战
spring cloud·微服务
SL_staff5 天前
JVS-Rules vs Drools:金融风控团队为何转向业务可编辑的决策平台
java·spring cloud·github