虽然我不会,但是偶然之间看到了Motan远程调用框架的一些内容,然后直接copy过来了,想着以后自己可能看看
集群中的loadbalance负载均衡策略
ActiveWeightLoadBalance===="低并发优化" 负载均衡
/** Copyright 2009-2016 Weibo, Inc.** Licensed 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 com.weibo.api.motan.cluster.loadbalance;import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;import com.weibo.api.motan.core.extension.SpiMeta;
import com.weibo.api.motan.rpc.Referer;
import com.weibo.api.motan.rpc.Request;/*** "低并发优化" 负载均衡* * <pre>* 1) 低并发度优先: referer的某时刻的call数越小优先级越高 * * 2) 低并发referer获取策略:* 由于Referer List可能很多,比如上百台,如果每次都要从这上百个Referer或者最低并发的几个,性能有些损耗,* 因此 random.nextInt(list.size()) 获取一个起始的index,然后获取最多不超过MAX_REFERER_COUNT的* 状态是isAvailable的referer进行判断activeCount.* </pre>* * @author maijunsheng* @version 创建时间:2013-6-14* */
@SpiMeta(name = "activeWeight")
public class ActiveWeightLoadBalance<T> extends AbstractLoadBalance<T> {@Overrideprotected Referer<T> doSelect(Request request) {List<Referer<T>> referers = getReferers();int refererSize = referers.size();int startIndex = ThreadLocalRandom.current().nextInt(refererSize);int currentCursor = 0;int currentAvailableCursor = 0;Referer<T> referer = null;while (currentAvailableCursor < MAX_REFERER_COUNT && currentCursor < refererSize) {Referer<T> temp = referers.get((startIndex + currentCursor) % refererSize);currentCursor++;if (!temp.isAvailable()) {continue;}currentAvailableCursor++;if (referer == null) {referer = temp;} else {if (compare(referer, temp) > 0) {referer = temp;}}}return referer;}@Overrideprotected void doSelectToHolder(Request request, List<Referer<T>> refersHolder) {List<Referer<T>> referers = getReferers();int refererSize = referers.size();int startIndex = ThreadLocalRandom.current().nextInt(refererSize);int currentCursor = 0;int currentAvailableCursor = 0;while (currentAvailableCursor < MAX_REFERER_COUNT && currentCursor < refererSize) {Referer<T> temp = referers.get((startIndex + currentCursor) % refererSize);currentCursor++;if (!temp.isAvailable()) {continue;}currentAvailableCursor++;refersHolder.add(temp);}Collections.sort(refersHolder, new LowActivePriorityComparator<T>());}private int compare(Referer<T> referer1, Referer<T> referer2) {return referer1.activeRefererCount() - referer2.activeRefererCount();}static class LowActivePriorityComparator<T> implements Comparator<Referer<T>> {@Overridepublic int compare(Referer<T> referer1, Referer<T> referer2) {return referer1.activeRefererCount() - referer2.activeRefererCount();}}}
ConfigurableWeightLoadBalance=======权重可配置的负载均衡器
/** Copyright 2009-2016 Weibo, Inc.** Licensed 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 com.weibo.api.motan.cluster.loadbalance;import com.weibo.api.motan.core.extension.SpiMeta;
import com.weibo.api.motan.rpc.Referer;
import com.weibo.api.motan.rpc.Request;
import com.weibo.api.motan.util.CollectionUtil;
import com.weibo.api.motan.util.LoggerUtil;
import com.weibo.api.motan.util.MathUtil;import org.apache.commons.lang3.StringUtils;import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;/*** 权重可配置的负载均衡器** @author chengya1*/
@SpiMeta(name = "configurableWeight")
public class ConfigurableWeightLoadBalance<T> extends ActiveWeightLoadBalance<T> {@SuppressWarnings("rawtypes")private static final RefererListCacheHolder emptyHolder = new EmptyHolder();@SuppressWarnings("unchecked")private volatile RefererListCacheHolder<T> holder = emptyHolder;private String weightString;@SuppressWarnings("unchecked")@Overridepublic void onRefresh(List<Referer<T>> referers) {super.onRefresh(referers);if (CollectionUtil.isEmpty(referers)) {holder = emptyHolder;} else if (StringUtils.isEmpty(weightString)) {holder = new SingleGroupHolder<T>(referers);} else {holder = new MultiGroupHolder<T>(weightString, referers);}}@Overrideprotected Referer<T> doSelect(Request request) {if (holder == emptyHolder) {return null;}RefererListCacheHolder<T> h = this.holder;Referer<T> r = h.next();if (!r.isAvailable()) {int retryTimes = getReferers().size() - 1;for (int i = 0; i < retryTimes; i++) {r = h.next();if (r.isAvailable()) {break;}}}if (r.isAvailable()) {return r;} else {noAvailableReferer();return null;}}@Overrideprotected void doSelectToHolder(Request request, List<Referer<T>> refersHolder) {if (holder == emptyHolder) {return;}RefererListCacheHolder<T> h = this.holder;int i = 0, j = 0;while (i++ < getReferers().size()) {Referer<T> r = h.next();if (r.isAvailable()) {refersHolder.add(r);if (++j == MAX_REFERER_COUNT) {return;}}}if (refersHolder.isEmpty()) {noAvailableReferer();}}private void noAvailableReferer() {LoggerUtil.error(this.getClass().getSimpleName() + " 当前没有可用连接, pool.size=" + getReferers().size());}@Overridepublic void setWeightString(String weightString) {this.weightString = weightString;}/****************************************************************************************** ************************************************************************************* ******************************************************************************************/static abstract class RefererListCacheHolder<T> {abstract Referer<T> next();}static class EmptyHolder<T> extends RefererListCacheHolder<T> {@OverrideReferer<T> next() {return null;}}@SuppressWarnings("hiding")class SingleGroupHolder<T> extends RefererListCacheHolder<T> {private int size;private List<Referer<T>> cache;SingleGroupHolder(List<Referer<T>> list) {cache = list;size = list.size();LoggerUtil.info("ConfigurableWeightLoadBalance build new SingleGroupHolder.");}@OverrideReferer<T> next() {return cache.get(ThreadLocalRandom.current().nextInt(size));}}@SuppressWarnings("hiding")class MultiGroupHolder<T> extends RefererListCacheHolder<T> {private int randomKeySize = 0;private List<String> randomKeyList = new ArrayList<String>();private Map<String, AtomicInteger> cursors = new HashMap<String, AtomicInteger>();private Map<String, List<Referer<T>>> groupReferers = new HashMap<String, List<Referer<T>>>();MultiGroupHolder(String weights, List<Referer<T>> list) {LoggerUtil.info("ConfigurableWeightLoadBalance build new MultiGroupHolder. weights:" + weights);String[] groupsAndWeights = weights.split(",");int[] weightsArr = new int[groupsAndWeights.length];Map<String, Integer> weightsMap = new HashMap<String, Integer>(groupsAndWeights.length);int i = 0;for (String groupAndWeight : groupsAndWeights) {String[] gw = groupAndWeight.split(":");if (gw.length == 2) {Integer w = Integer.valueOf(gw[1]);weightsMap.put(gw[0], w);groupReferers.put(gw[0], new ArrayList<Referer<T>>());weightsArr[i++] = w;}}// 求出最大公约数,若不为1,对权重做除法int weightGcd = findGcd(weightsArr);if (weightGcd != 1) {for(Map.Entry<String,Integer> entry: weightsMap.entrySet()) {weightsMap.put(entry.getKey(),entry.getValue()/weightGcd);}}for (Map.Entry<String, Integer> entry : weightsMap.entrySet()) {for (int j = 0; j < entry.getValue(); j++) {randomKeyList.add(entry.getKey());}}Collections.shuffle(randomKeyList);randomKeySize = randomKeyList.size();for (String key : weightsMap.keySet()) {cursors.put(key, new AtomicInteger(0));}for (Referer<T> referer : list) {groupReferers.get(referer.getServiceUrl().getGroup()).add(referer);}}@OverrideReferer<T> next() {String group = randomKeyList.get(ThreadLocalRandom.current().nextInt(randomKeySize));AtomicInteger ai = cursors.get(group);List<Referer<T>> referers = groupReferers.get(group);return referers.get(MathUtil.getPositive(ai.getAndIncrement()) % referers.size());}// 求最大公约数private int findGcd(int n, int m) {return (n == 0 || m == 0) ? n + m : findGcd(m, n % m);}// 求最大公约数private int findGcd(int[] arr) {int i = 0;for (; i < arr.length - 1; i++) {arr[i + 1] = findGcd(arr[i], arr[i + 1]);}return findGcd(arr[i], arr[i - 1]);}}}
consistent======一致性Hash
/** Copyright 2009-2016 Weibo, Inc.** Licensed 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 com.weibo.api.motan.cluster.loadbalance;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;import com.weibo.api.motan.common.MotanConstants;
import com.weibo.api.motan.core.extension.SpiMeta;
import com.weibo.api.motan.rpc.Referer;
import com.weibo.api.motan.rpc.Request;
import com.weibo.api.motan.util.MathUtil;/*** * Use consistent hash to choose referer** @author fishermen* @version V1.0 created at: 2013-5-21*/
@SpiMeta(name = "consistent")
public class ConsistentHashLoadBalance<T> extends AbstractLoadBalance<T> {private List<Referer<T>> consistentHashReferers;@Overridepublic void onRefresh(List<Referer<T>> referers) {super.onRefresh(referers);List<Referer<T>> copyReferers = new ArrayList<Referer<T>>(referers);List<Referer<T>> tempRefers = new ArrayList<Referer<T>>();for (int i = 0; i < MotanConstants.DEFAULT_CONSISTENT_HASH_BASE_LOOP; i++) {Collections.shuffle(copyReferers);for (Referer<T> ref : copyReferers) {tempRefers.add(ref);}}consistentHashReferers = tempRefers;}@Overrideprotected Referer<T> doSelect(Request request) {int hash = getHash(request);Referer<T> ref;for (int i = 0; i < getReferers().size(); i++) {ref = consistentHashReferers.get((hash + i) % consistentHashReferers.size());if (ref.isAvailable()) {return ref;}}return null;}@Overrideprotected void doSelectToHolder(Request request, List<Referer<T>> refersHolder) {List<Referer<T>> referers = getReferers();int hash = getHash(request);for (int i = 0; i < referers.size(); i++) {Referer<T> ref = consistentHashReferers.get((hash + i) % consistentHashReferers.size());if (ref.isAvailable()) {refersHolder.add(ref);}}}private int getHash(Request request) {int hashcode;if (request.getArguments() == null || request.getArguments().length == 0) {hashcode = request.hashCode();} else {hashcode = Arrays.hashCode(request.getArguments());}return MathUtil.getPositive(hashcode);}}
localFirst===="本地服务优先" 负载均衡
/** Copyright 2009-2016 Weibo, Inc.** Licensed 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 com.weibo.api.motan.cluster.loadbalance;import com.weibo.api.motan.core.extension.SpiMeta;
import com.weibo.api.motan.rpc.Referer;
import com.weibo.api.motan.rpc.Request;
import com.weibo.api.motan.util.LoggerUtil;
import com.weibo.api.motan.util.NetUtils;import java.util.*;
import java.util.concurrent.ThreadLocalRandom;/*** "本地服务优先" 负载均衡* <p>* <pre>* 1) 本地服务优先:* 当referers里面包含本地暴露的服务时,并此服务为available的情况下,优先使用此服务。* 当不存在本地暴露的服务时,默认使用低并发ActiveWeight负载均衡策略** 2) 本地服务优先获取策略:* 对referers根据ip顺序查找本地服务,多存在多个本地服务,获取Active最小的本地服务进行服务。* 当不存在本地服务,但是存在远程RPC服务,则根据ActivWeight获取远程RPC服务* 当两者都存在,所有本地服务都应优先于远程服务,本地RPC服务与远程RPC服务内部则根据ActiveWeight进行** </pre>*/
@SpiMeta(name = "localFirst")
public class LocalFirstLoadBalance<T> extends AbstractLoadBalance<T> {public static final int MAX_REFERER_COUNT = 10;public static long ipToLong(final String addr) {final String[] addressBytes = addr.split("\\.");int length = addressBytes.length;if (length < 3) {return 0;}long ip = 0;try {for (int i = 0; i < 4; i++) {ip <<= 8;ip |= Integer.parseInt(addressBytes[i]);}} catch (Exception e) {LoggerUtil.warn("Warn ipToInt addr is wrong: addr=" + addr);}return ip;}@Overrideprotected Referer<T> doSelect(Request request) {List<Referer<T>> referers = getReferers();List<Referer<T>> localReferers = searchLocalReferer(referers, NetUtils.getLocalAddress().getHostAddress());if (!localReferers.isEmpty()) {referers = localReferers;}int refererSize = referers.size();Referer<T> referer = null;for (int i = 0; i < refererSize; i++) {Referer<T> temp = referers.get(i % refererSize);if (!temp.isAvailable()) {continue;}if (referer == null) {referer = temp;} else {if (compare(referer, temp) > 0) {referer = temp;}}}return referer;}@Overrideprotected void doSelectToHolder(Request request, List<Referer<T>> refersHolder) {List<Referer<T>> referers = getReferers();List<Referer<T>> localReferers = searchLocalReferer(referers, NetUtils.getLocalAddress().getHostAddress());if (!localReferers.isEmpty()) {Collections.sort(localReferers, new LowActivePriorityComparator<T>());refersHolder.addAll(localReferers);}int refererSize = referers.size();int startIndex = ThreadLocalRandom.current().nextInt(refererSize);int currentCursor = 0;int currentAvailableCursor = 0;List<Referer<T>> remoteReferers = new ArrayList<Referer<T>>();while (currentAvailableCursor < MAX_REFERER_COUNT && currentCursor < refererSize) {Referer<T> temp = referers.get((startIndex + currentCursor) % refererSize);currentCursor++;if (!temp.isAvailable() || localReferers.contains(temp)) {continue;}currentAvailableCursor++;remoteReferers.add(temp);}Collections.sort(remoteReferers, new LowActivePriorityComparator<T>());refersHolder.addAll(remoteReferers);}private List<Referer<T>> searchLocalReferer(List<Referer<T>> referers, String localhost) {List<Referer<T>> localReferers = new ArrayList<Referer<T>>();long local = ipToLong(localhost);for (Referer<T> referer : referers) {long tmp = ipToLong(referer.getUrl().getHost());if (local != 0 && local == tmp) {if (referer.isAvailable()) {localReferers.add(referer);}}}return localReferers;}private int compare(Referer<T> referer1, Referer<T> referer2) {return referer1.activeRefererCount() - referer2.activeRefererCount();}static class LowActivePriorityComparator<T> implements Comparator<Referer<T>> {@Overridepublic int compare(Referer<T> referer1, Referer<T> referer2) {return referer1.activeRefererCount() - referer2.activeRefererCount();}}
}
RandomLoadBalance=====随机
/** Copyright 2009-2016 Weibo, Inc.** Licensed 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 com.weibo.api.motan.cluster.loadbalance;import java.util.List;
import java.util.concurrent.ThreadLocalRandom;import com.weibo.api.motan.core.extension.SpiMeta;
import com.weibo.api.motan.rpc.Referer;
import com.weibo.api.motan.rpc.Request;/*** * random load balance.** @author fishermen* @version V1.0 created at: 2013-5-21*/
@SpiMeta(name = "random")
public class RandomLoadBalance<T> extends AbstractLoadBalance<T> {@Overrideprotected Referer<T> doSelect(Request request) {List<Referer<T>> referers = getReferers();int idx = (int) (ThreadLocalRandom.current().nextDouble() * referers.size());for (int i = 0; i < referers.size(); i++) {Referer<T> ref = referers.get((i + idx) % referers.size());if (ref.isAvailable()) {return ref;}}return null;}@Overrideprotected void doSelectToHolder(Request request, List<Referer<T>> refersHolder) {List<Referer<T>> referers = getReferers();int idx = (int) (ThreadLocalRandom.current().nextDouble() * referers.size());for (int i = 0; i < referers.size(); i++) {Referer<T> referer = referers.get((i + idx) % referers.size());if (referer.isAvailable()) {refersHolder.add(referer);}}}
}
RoundRobinLoadBalance======轮询
/** Copyright 2009-2016 Weibo, Inc.** Licensed 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 com.weibo.api.motan.cluster.loadbalance;import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;import com.weibo.api.motan.core.extension.SpiMeta;
import com.weibo.api.motan.rpc.Referer;
import com.weibo.api.motan.rpc.Request;
import com.weibo.api.motan.util.MathUtil;/*** * Round robin loadbalance.* * @author fishermen* @version V1.0 created at: 2013-6-13*/
@SpiMeta(name = "roundrobin")
public class RoundRobinLoadBalance<T> extends AbstractLoadBalance<T> {private AtomicInteger idx = new AtomicInteger(0);@Overrideprotected Referer<T> doSelect(Request request) {List<Referer<T>> referers = getReferers();int index = getNextPositive();for (int i = 0; i < referers.size(); i++) {Referer<T> ref = referers.get((i + index) % referers.size());if (ref.isAvailable()) {return ref;}}return null;}@Overrideprotected void doSelectToHolder(Request request, List<Referer<T>> refersHolder) {List<Referer<T>> referers = getReferers();int index = getNextPositive();for (int i = 0, count = 0; i < referers.size() && count < MAX_REFERER_COUNT; i++) {Referer<T> referer = referers.get((i + index) % referers.size());if (referer.isAvailable()) {refersHolder.add(referer);count++;}}}// get positive intprivate int getNextPositive() {return MathUtil.getPositive(idx.incrementAndGet());}
}
父类--虚负载均衡class===AbstractLoadBalance
/** Copyright 2009-2016 Weibo, Inc.** Licensed 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 com.weibo.api.motan.cluster.loadbalance;import com.weibo.api.motan.cluster.LoadBalance;
import com.weibo.api.motan.exception.MotanServiceException;
import com.weibo.api.motan.rpc.Referer;
import com.weibo.api.motan.rpc.Request;
import com.weibo.api.motan.util.LoggerUtil;
import com.weibo.api.motan.util.MotanFrameworkUtil;import java.util.List;/*** * loadbalance* * @author fishermen* @version V1.0 created at: 2013-5-22*/public abstract class AbstractLoadBalance<T> implements LoadBalance<T> {public static final int MAX_REFERER_COUNT = 10;private List<Referer<T>> referers;@Overridepublic void onRefresh(List<Referer<T>> referers) {// 只能引用替换,不能进行referers update。this.referers = referers;}@Overridepublic Referer<T> select(Request request) {List<Referer<T>> referers = this.referers;if (referers == null) {throw new MotanServiceException(this.getClass().getSimpleName() + " No available referers for call request:" + request);}Referer<T> ref = null;if (referers.size() > 1) {ref = doSelect(request);} else if (referers.size() == 1) {ref = referers.get(0).isAvailable() ? referers.get(0) : null;}if (ref != null) {return ref;}throw new MotanServiceException(this.getClass().getSimpleName() + " No available referers for call request:" + request);}@Overridepublic void selectToHolder(Request request, List<Referer<T>> refersHolder) {List<Referer<T>> referers = this.referers;if (referers == null) {throw new MotanServiceException(this.getClass().getSimpleName() + " No available referers for call : referers_size= 0 "+ MotanFrameworkUtil.toString(request));}if (referers.size() > 1) {doSelectToHolder(request, refersHolder);} else if (referers.size() == 1 && referers.get(0).isAvailable()) {refersHolder.add(referers.get(0));}if (refersHolder.isEmpty()) {throw new MotanServiceException(this.getClass().getSimpleName() + " No available referers for call : referers_size="+ referers.size() + " " + MotanFrameworkUtil.toString(request));}}protected List<Referer<T>> getReferers() {return referers;}@Overridepublic void setWeightString(String weightString) {LoggerUtil.info("ignore weightString:" + weightString);}protected abstract Referer<T> doSelect(Request request);protected abstract void doSelectToHolder(Request request, List<Referer<T>> refersHolder);
}