/** * Dianping.com Inc. * Copyright (c) 2003-2013 All Rights Reserved. */ package com.dianping.pigeon.remoting.invoker.route; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import com.dianping.pigeon.log.Logger; import org.springframework.util.CollectionUtils; import com.dianping.pigeon.config.ConfigManagerLoader; import com.dianping.pigeon.log.LoggerLoader; import com.dianping.pigeon.registry.RegistryManager; import com.dianping.pigeon.registry.listener.RegistryEventListener; import com.dianping.pigeon.registry.listener.ServiceProviderChangeEvent; import com.dianping.pigeon.registry.listener.ServiceProviderChangeListener; import com.dianping.pigeon.remoting.common.domain.Disposable; import com.dianping.pigeon.remoting.common.domain.InvocationRequest; import com.dianping.pigeon.remoting.common.util.Constants; import com.dianping.pigeon.remoting.invoker.Client; import com.dianping.pigeon.remoting.invoker.config.InvokerConfig; import com.dianping.pigeon.remoting.invoker.exception.ServiceUnavailableException; import com.dianping.pigeon.remoting.invoker.listener.ClusterListenerManager; import com.dianping.pigeon.remoting.invoker.route.balance.LoadBalance; import com.dianping.pigeon.remoting.invoker.route.balance.LoadBalanceManager; import com.dianping.pigeon.remoting.invoker.route.balance.RandomLoadBalance; import com.dianping.pigeon.remoting.invoker.route.balance.WeightedAutoawareLoadBalance; import com.dianping.pigeon.remoting.invoker.route.quality.RequestQualityManager; import com.dianping.pigeon.remoting.invoker.route.region.RegionPolicyManager; public class DefaultRouteManager implements RouteManager, Disposable { private static final Logger logger = LoggerLoader.getLogger(DefaultRouteManager.class); public final static DefaultRouteManager INSTANCE = new DefaultRouteManager(); private final RegionPolicyManager regionPolicyManager = RegionPolicyManager.INSTANCE; private final RequestQualityManager requestQualityManager = RequestQualityManager.INSTANCE; private static final ClusterListenerManager clusterListenerManager = ClusterListenerManager.getInstance(); private ServiceProviderChangeListener providerChangeListener = new InnerServiceProviderChangeListener(); private static List<String> preferAddresses = null; private static boolean enablePreferAddresses = ConfigManagerLoader.getConfigManager().getBooleanValue( "pigeon.route.preferaddresses.enable", false); private DefaultRouteManager() { RegistryEventListener.addListener(providerChangeListener); if (enablePreferAddresses) { preferAddresses = new ArrayList<String>(); String preferAddressesConfig = ConfigManagerLoader.getConfigManager().getStringValue( "pigeon.route.preferaddresses", ""); String[] preferAddressesArray = preferAddressesConfig.split(","); for (String addr : preferAddressesArray) { if (StringUtils.isNotBlank(addr)) { preferAddresses.add(addr.trim()); } } } } public Client route(List<Client> clientList, InvokerConfig<?> invokerConfig, InvocationRequest request) { if (logger.isDebugEnabled()) { for (Client client : clientList) { if (client != null) { logger.debug("available service provider:\t" + client.getAddress()); } } } List<Client> availableClients = getAvailableClients(clientList, invokerConfig, request); Client selectedClient = select(availableClients, invokerConfig, request); while (!selectedClient.isActive()) { logger.info("[route] remove client:" + selectedClient); availableClients.remove(selectedClient); if (availableClients.isEmpty()) { break; } selectedClient = select(availableClients, invokerConfig, request); } if (!selectedClient.isActive()) { throw new ServiceUnavailableException("no available server exists for service[" + invokerConfig + "], env:" + ConfigManagerLoader.getConfigManager().getEnv()); } return selectedClient; } /** * 按照权重、分组、region规则过滤客户端选择 加入对oneway调用模式的优化判断 * * @param clientList * @param invokerConfig * @param request * @return */ public List<Client> getAvailableClients(List<Client> clientList, InvokerConfig<?> invokerConfig, InvocationRequest request) { if (regionPolicyManager.isEnableRegionPolicy()) { clientList = regionPolicyManager.getPreferRegionClients(clientList, invokerConfig, request); } List<Client> filteredClients = new ArrayList<Client>(clientList.size()); for (Client client : clientList) { if (client != null) { String address = client.getAddress(); int weight = RegistryManager.getInstance().getServiceWeightFromCache(address); if (client.isActive() && weight > 0) { filteredClients.add(client); } else if (logger.isDebugEnabled()) { logger.debug("provider status:" + client.isActive() + "," + weight); } } } if (filteredClients.isEmpty()) { throw new ServiceUnavailableException("no available server exists for service[" + invokerConfig.getUrl() + "] and group[" + RegistryManager.getInstance().getGroup(invokerConfig.getUrl()) + "]."); } return filteredClients; } private void checkClientNotNull(Client client, InvokerConfig<?> invokerConfig) { if (client == null) { throw new ServiceUnavailableException("no available server exists for service[" + invokerConfig + "], env:" + ConfigManagerLoader.getConfigManager().getEnv()); } } private Client select(List<Client> availableClients, InvokerConfig<?> invokerConfig, InvocationRequest request) { LoadBalance loadBalance = null; if (loadBalance == null) { loadBalance = LoadBalanceManager.getLoadBalance(invokerConfig, request.getCallType()); } if (loadBalance == null) { loadBalance = WeightedAutoawareLoadBalance.instance; if (request.getCallType() == Constants.CALLTYPE_NOREPLY) { loadBalance = RandomLoadBalance.instance; } } List<Client> preferClients = null; if (enablePreferAddresses) { if (availableClients != null && availableClients.size() > 1 && !CollectionUtils.isEmpty(preferAddresses)) { preferClients = new ArrayList<Client>(); for (String addr : preferAddresses) { for (Client client : availableClients) { if (client.getHost().startsWith(addr)) { preferClients.add(client); } } if (preferClients.size() > 0) { break; } } } } if (preferClients == null || preferClients.size() == 0) { preferClients = availableClients; } Client selectedClient = loadBalance.select(preferClients, invokerConfig, request); checkClientNotNull(selectedClient, invokerConfig); return selectedClient; } @Override public void destroy() throws Exception { RegistryEventListener.removeListener(providerChangeListener); } class InnerServiceProviderChangeListener implements ServiceProviderChangeListener { @Override public void hostWeightChanged(ServiceProviderChangeEvent event) { RegistryManager.getInstance().setServiceWeight(event.getConnect(), event.getWeight()); } @Override public void providerAdded(ServiceProviderChangeEvent event) { } @Override public void providerRemoved(ServiceProviderChangeEvent event) { } } }