/* * Copyright 2017 eagle.jfaster.org. * <p> * 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. * </p> */ package eagle.jfaster.org.cluster.loadbalance; import eagle.jfaster.org.config.ConfigEnum; import eagle.jfaster.org.rpc.Refer; import eagle.jfaster.org.rpc.Request; import eagle.jfaster.org.spi.SpiInfo; import java.util.concurrent.ThreadLocalRandom; import static eagle.jfaster.org.constant.EagleConstants.WARMUP; /** * 基于权重的负载算法 * * Created by fangyanpeng on 2017/8/20. */ @SpiInfo(name = "weight") public class RandomWeightLoadBalance<T> extends AbstractLoadBalance<T> { @Override public Refer<T> doSelect(Request request) { int length = refers.size(); // 总个数 int totalWeight = 0; // 总权重 boolean sameWeight = true; // 权重是否都一样 for (int i = 0; i < length; i++) { int weight = getWeight(refers.get(i)); totalWeight += weight; // 累计总权重 if (sameWeight && i > 0 && weight != getWeight(refers.get(i - 1))) { sameWeight = false; // 计算所有权重是否一样 } } if (totalWeight > 0 && !sameWeight) { // 如果权重不相同且权重大于0则按总权重数随机 int offset = ThreadLocalRandom.current().nextInt(totalWeight); // 并确定随机值落在哪个片断上 for (int i = 0; i < length; i++) { Refer<T> refer = refers.get(i); offset -= getWeight(refer); if (offset < 0 && refer.isAlive()) { return refer; } } } // 如果权重相同或权重为0则均等随机 int idx = ThreadLocalRandom.current().nextInt(length); for (int i = 0; i < refers.size(); i++) { Refer<T> ref = refers.get((i + idx) % refers.size()); if (ref.isAlive()) { return ref; } } return null; } protected int getWeight(Refer<T> refer) { int weight = refer.getConfig().getExtInt(ConfigEnum.weight.getName(), ConfigEnum.weight.getIntValue()); if (weight > 0) { long timestamp = refer.getConfig().getExtLong(ConfigEnum.refreshTimestamp.getName(), ConfigEnum.refreshTimestamp.getIntValue()); if (timestamp > 0L) { int uptime = (int) (System.currentTimeMillis() - timestamp); if (uptime > 0 && uptime < WARMUP) { weight = calculateWarmupWeight(uptime, weight); } } } return weight; } static int calculateWarmupWeight(int uptime, int weight) { int ww = (int) ((float) uptime / ((float) WARMUP / (float) weight)); return ww < 1 ? 1 : (ww > weight ? weight : ww); } }