擴展Ribbon支持基於元數據的版本管理

一個微服務在線上可能多版本共存,例如:

  • 服務提供者有兩個版本:v1、v2
  • 服務消費者也有兩個版本:v1、v2

v1/v2是不兼容的。

1、服務消費者v1只能調用服務提供者v1;消費者v2只能調用提供者v2。

2、優先調用同集羣下的實例。

3、實現基於權重配置的負載均衡。

如何實現呢?

下面圍繞該場景,實現微服務之間的版本控制。

元數據

元數據就是一堆的描述信息,以map存儲。舉個例子:

spring:
  cloud:
    nacos:
        metadata: 
          # 自己這個實例的版本
          version: v1
          # 允許調用的提供者版本
          target-version: v1

需求分析

我們需要實現的有兩點:

  • 優先選擇同集羣下,符合metadata的實例
  • 如果同集羣加沒有符合metadata的實例,就選擇所有集羣下,符合metadata的實例

寫代碼

@Slf4j
public class NacosFinalRule extends AbstractLoadBalancerRule {
    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties;

    @Override
    public Server choose(Object key) {
        // 負載均衡規則:優先選擇同集羣下,符合metadata的實例
        // 如果沒有,就選擇所有集羣下,符合metadata的實例

        // 1. 查詢所有實例 A
        // 2. 篩選元數據匹配的實例 B
        // 3. 篩選出同cluster下元數據匹配的實例 C
        // 4. 如果C爲空,就用B
        // 5. 隨機選擇實例
        try {
            String clusterName = this.nacosDiscoveryProperties.getClusterName();
            String targetVersion = this.nacosDiscoveryProperties.getMetadata().get("target-version");

            DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
            String name = loadBalancer.getName();

            NamingService namingService = this.nacosDiscoveryProperties.namingServiceInstance();

            // 所有實例
            List<Instance> instances = namingService.selectInstances(name, true);

            List<Instance> metadataMatchInstances = instances;
            // 如果配置了版本映射,那麼只調用元數據匹配的實例
            if (StringUtils.isNotBlank(targetVersion)) {
                metadataMatchInstances = instances.stream()
                        .filter(instance -> Objects.equals(targetVersion, instance.getMetadata().get("version")))
                        .collect(Collectors.toList());
                if (CollectionUtils.isEmpty(metadataMatchInstances)) {
                    log.warn("未找到元數據匹配的目標實例!請檢查配置。targetVersion = {}, instance = {}", targetVersion, instances);
                    return null;
                }
            }

            List<Instance> clusterMetadataMatchInstances = metadataMatchInstances;
            // 如果配置了集羣名稱,需篩選同集羣下元數據匹配的實例
            if (StringUtils.isNotBlank(clusterName)) {
                clusterMetadataMatchInstances = metadataMatchInstances.stream()
                        .filter(instance -> Objects.equals(clusterName, instance.getClusterName()))
                        .collect(Collectors.toList());
                if (CollectionUtils.isEmpty(clusterMetadataMatchInstances)) {
                    clusterMetadataMatchInstances = metadataMatchInstances;
                    log.warn("發生跨集羣調用。clusterName = {}, targetVersion = {}, clusterMetadataMatchInstances = {}", clusterName, targetVersion, clusterMetadataMatchInstances);
                }
            }

            Instance instance = ExtendBalancer.getHostByRandomWeight2(clusterMetadataMatchInstances);
            return new NacosServer(instance);
        } catch (Exception e) {
            log.warn("發生異常", e);
            return null;
        }
    }

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {
    }
}

負載均衡算法:

public class ExtendBalancer extends Balancer {
    /**
     * 根據權重,隨機選擇實例
     *
     * @param instances 實例列表
     * @return 選擇的實例
     */
    public static Instance getHostByRandomWeight2(List<Instance> instances) {
        return getHostByRandomWeight(instances);
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章