All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareClusterInvoker Maven / Gradle / Ivy

There is a newer version: 3.3.0-beta.4
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.dubbo.rpc.cluster.support.registry;

import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.ZoneDetector;
import org.apache.dubbo.rpc.cluster.ClusterInvoker;
import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.LoadBalance;
import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;

import java.util.List;
import java.util.stream.Collectors;

import static org.apache.dubbo.common.constants.CommonConstants.PREFERRED_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_ZONE;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_ZONE_FORCE;
import static org.apache.dubbo.common.constants.RegistryConstants.ZONE_KEY;

/**
 * When there are more than one registry for subscription.
 * 

* This extension provides a strategy to decide how to distribute traffics among them: * 1. registry marked as 'preferred=true' has the highest priority. * 2. check the zone the current request belongs, pick the registry that has the same zone first. * 3. Evenly balance traffic between all registries based on each registry's weight. * 4. Pick anyone that's available. */ public class ZoneAwareClusterInvoker extends AbstractClusterInvoker { private static final Logger logger = LoggerFactory.getLogger(ZoneAwareClusterInvoker.class); private ZoneDetector zoneDetector; public ZoneAwareClusterInvoker(Directory directory) { super(directory); ExtensionLoader loader = directory.getConsumerUrl().getOrDefaultApplicationModel().getExtensionLoader(ZoneDetector.class); if (loader.hasExtension("default")) { zoneDetector = loader.getExtension("default"); } } @Override @SuppressWarnings({"unchecked", "rawtypes"}) public Result doInvoke(Invocation invocation, final List> invokers, LoadBalance loadbalance) throws RpcException { // First, pick the invoker (XXXClusterInvoker) that comes from the local registry, distinguish by a 'preferred' key. for (Invoker invoker : invokers) { ClusterInvoker clusterInvoker = (ClusterInvoker) invoker; if (clusterInvoker.isAvailable() && clusterInvoker.getRegistryUrl() .getParameter(PREFERRED_KEY, false)) { return clusterInvoker.invoke(invocation); } } RpcContext rpcContext = RpcContext.getClientAttachment(); String zone = rpcContext.getAttachment(REGISTRY_ZONE); String force = rpcContext.getAttachment(REGISTRY_ZONE_FORCE); if (StringUtils.isEmpty(zone) && zoneDetector != null) { zone = zoneDetector.getZoneOfCurrentRequest(invocation); force = zoneDetector.isZoneForcingEnabled(invocation, zone); } // providers in the registry with the same zone if (StringUtils.isNotEmpty(zone)) { for (Invoker invoker : invokers) { ClusterInvoker clusterInvoker = (ClusterInvoker) invoker; if (clusterInvoker.isAvailable() && zone.equals(clusterInvoker.getRegistryUrl().getParameter(ZONE_KEY))) { return clusterInvoker.invoke(invocation); } } if (StringUtils.isNotEmpty(force) && "true".equalsIgnoreCase(force)) { throw new IllegalStateException("No registry instance in zone or no available providers in the registry, zone: " + zone + ", registries: " + invokers.stream().map(invoker -> ((ClusterInvoker) invoker).getRegistryUrl().toString()).collect(Collectors.joining(","))); } } // load balance among all registries, with registry weight count in. Invoker balancedInvoker = select(loadbalance, invocation, invokers, null); if (balancedInvoker!=null && balancedInvoker.isAvailable()) { return balancedInvoker.invoke(invocation); } // If none of the invokers has a preferred signal or is picked by the loadbalancer, pick the first one available. for (Invoker invoker : invokers) { ClusterInvoker clusterInvoker = (ClusterInvoker) invoker; if (clusterInvoker.isAvailable()) { return clusterInvoker.invoke(invocation); } } //if none available,just pick one return invokers.get(0).invoke(invocation); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy