/** * Dianping.com Inc. * Copyright (c) 2003-2013 All Rights Reserved. */ package com.dianping.pigeon.remoting.invoker.route.balance; import java.util.Arrays; import java.util.List; import java.util.Random; import com.dianping.pigeon.remoting.invoker.route.quality.RequestQualityManager; import org.apache.commons.lang.StringUtils; import com.dianping.pigeon.log.Logger; import com.dianping.pigeon.config.ConfigManager; import com.dianping.pigeon.config.ConfigManagerLoader; import com.dianping.pigeon.log.LoggerLoader; import com.dianping.pigeon.remoting.common.domain.InvocationRequest; 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.route.statistics.ServiceStatisticsHolder; import com.dianping.pigeon.remoting.invoker.util.InvokerHelper; public abstract class AbstractLoadBalance implements LoadBalance { private static final Logger logger = LoggerLoader.getLogger(AbstractLoadBalance.class); protected Random random = new Random(); private static final ConfigManager configManager = ConfigManagerLoader.getConfigManager(); @Override public Client select(List<Client> clients, InvokerConfig<?> invokerConfig, InvocationRequest request) { if (clients == null || clients.isEmpty()) { return null; } Client selectedClient = null; String forceAddress = InvokerHelper.getAddress(); if (StringUtils.isNotBlank(forceAddress)) { // 客户端强制路由 if (forceAddress.startsWith("localhost") || forceAddress.startsWith("127.0.0.1")) { if (forceAddress.lastIndexOf(":") != -1) { forceAddress = configManager.getLocalIp() + forceAddress.substring(forceAddress.lastIndexOf(":")); } } for (Client client : clients) { if (forceAddress.equals(client.getAddress())) { selectedClient = client; break; } } if (selectedClient == null) { throw new ServiceUnavailableException("address[" + forceAddress + "] is not in available providers of service:" + request.getServiceName() + ", available providers:" + clients); } } else { try { selectedClient = doSelect(clients, invokerConfig, request, getWeights(clients, request)); } catch (Throwable e) { logger.error("failed to do load balance[" + getClass().getName() + "], detail: " + e.getMessage() + ", use random instead.", e); selectedClient = clients.get(random.nextInt(clients.size())); } } if (logger.isDebugEnabled()) { if (ServiceStatisticsHolder.checkRequestNeedStat(request)) { logger.debug("total requests to " + selectedClient.getAddress() + " in last second:" + ServiceStatisticsHolder.getCapacityBucket(selectedClient.getAddress()).getLastSecondRequest()); } } return selectedClient; } /** * [w1, w2, w3, maxWeightIndex] * * @param clients * @param request * @return */ private int[] getWeights(List<Client> clients, InvocationRequest request) { int clientSize = clients.size(); int[] weights = new int[clientSize + 1]; int maxWeightIdx = 0; int maxWeight = Integer.MIN_VALUE; for (int i = 0; i < clientSize; i++) { int effectiveWeight = LoadBalanceManager.getEffectiveWeight(clients.get(i).getAddress()); weights[i] = RequestQualityManager.INSTANCE.adjustWeightWithQuality(effectiveWeight, clients.get(i).getAddress(), request); if (weights[i] > maxWeight) { maxWeight = weights[i]; maxWeightIdx = i; } } weights[clientSize] = maxWeightIdx; if (logger.isDebugEnabled()) { logger.debug("effective weights: " + Arrays.toString(weights)); } return weights; } protected abstract Client doSelect(List<Client> clients, InvokerConfig<?> invokerConfig, InvocationRequest request, int[] weights); }