Commit d8f8f36a by Nepxion

优化和修复随机权重的算法

parent 3461a7a4
......@@ -18,7 +18,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import com.nepxion.discovery.common.entity.WeightFilterEntity;
import com.nepxion.discovery.plugin.framework.adapter.PluginAdapter;
import com.nepxion.discovery.plugin.framework.loadbalance.IWeightRandomLoadBalance;
import com.nepxion.discovery.plugin.framework.loadbalance.weight.ArrayWeightRandomLoadBalance;
import com.nepxion.discovery.plugin.framework.loadbalance.weight.MapWeightRandomLoadBalance;
import com.netflix.loadbalancer.PredicateBasedRule;
import com.netflix.loadbalancer.Server;
......@@ -30,7 +30,7 @@ public abstract class PredicateBasedRuleDecorator extends PredicateBasedRule {
@PostConstruct
private void initialize() {
weightRandomLoadBalance = new ArrayWeightRandomLoadBalance();
weightRandomLoadBalance = new MapWeightRandomLoadBalance();
weightRandomLoadBalance.setPluginAdapter(pluginAdapter);
}
......
......@@ -18,7 +18,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import com.nepxion.discovery.common.entity.WeightFilterEntity;
import com.nepxion.discovery.plugin.framework.adapter.PluginAdapter;
import com.nepxion.discovery.plugin.framework.loadbalance.weight.AbstractWeightRandomLoadBalance;
import com.nepxion.discovery.plugin.framework.loadbalance.weight.ArrayWeightRandomLoadBalance;
import com.nepxion.discovery.plugin.framework.loadbalance.weight.MapWeightRandomLoadBalance;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ZoneAvoidanceRule;
......@@ -30,7 +30,7 @@ public class ZoneAvoidanceRuleDecorator extends ZoneAvoidanceRule {
@PostConstruct
private void initialize() {
weightRandomLoadBalance = new ArrayWeightRandomLoadBalance();
weightRandomLoadBalance = new MapWeightRandomLoadBalance();
weightRandomLoadBalance.setPluginAdapter(pluginAdapter);
}
......
......@@ -27,10 +27,7 @@ public class ArrayWeightRandomLoadBalance extends AbstractWeightRandomLoadBalanc
int[] weights = new int[serverList.size()];
for (int i = 0; i < serverList.size(); i++) {
Server server = serverList.get(i);
int weight = getWeight(server, weightFilterEntity);
if (weight > 0) {
weights[i] = weight;
}
weights[i] = getWeight(server, weightFilterEntity);
}
int index = getIndex(weights);
......
package com.nepxion.discovery.plugin.framework.loadbalance.weight;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import com.nepxion.discovery.common.entity.WeightFilterEntity;
import com.nepxion.discovery.common.exception.DiscoveryException;
import com.netflix.loadbalancer.Server;
public class MapWeightRandomLoadBalance extends AbstractWeightRandomLoadBalance {
@Override
public Server choose(List<Server> serverList, WeightFilterEntity weightFilterEntity) {
if (CollectionUtils.isEmpty(serverList)) {
return null;
}
List<Pair<Server, Integer>> weightPairList = new ArrayList<Pair<Server, Integer>>();
for (Server server : serverList) {
int weight = getWeight(server, weightFilterEntity);
weightPairList.add(new ImmutablePair<Server, Integer>(server, weight));
}
MapWeightRandom<Server, Integer> weightRandom = new MapWeightRandom<Server, Integer>(weightPairList);
return weightRandom.random();
}
public class MapWeightRandom<K, V extends Number> {
private TreeMap<Double, K> weightMap = new TreeMap<Double, K>();
public MapWeightRandom(List<Pair<K, V>> pairlist) {
for (Pair<K, V> pair : pairlist) {
double value = pair.getValue().doubleValue();
if (value <= 0) {
continue;
}
double lastWeight = weightMap.size() == 0 ? 0 : weightMap.lastKey().doubleValue();
weightMap.put(value + lastWeight, pair.getKey());
}
}
public K random() {
if (MapUtils.isEmpty(weightMap)) {
throw new DiscoveryException("No weight value is configed");
}
double randomWeight = weightMap.lastKey() * Math.random();
SortedMap<Double, K> tailMap = weightMap.tailMap(randomWeight, false);
return weightMap.get(tailMap.firstKey());
}
}
}
\ No newline at end of file
package com.nepxion.discovery.plugin.framework.loadbalance;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import org.apache.commons.collections4.CollectionUtils;
public class ArrayWeightRandomLoadBalanceTest {
public static void main(String[] args) {
long t = System.currentTimeMillis();
List<String> serverList = new ArrayList<String>();
serverList.add("1.0");
serverList.add("2.0");
serverList.add("3.0");
serverList.add("1.0");
serverList.add("2.0");
serverList.add("3.0");
serverList.add("4.0");
serverList.add("4.0");
serverList.add("5.0");
serverList.add("5.0");
Map<String, Integer> weightMap = new HashMap<String, Integer>();
weightMap.put("1.0", 0);
weightMap.put("2.0", 90);
weightMap.put("3.0", 10);
weightMap.put("4.0", 0);
weightMap.put("5.0", 0);
int v1Count = 0;
int v2Count = 0;
int v3Count = 0;
int v4Count = 0;
int v5Count = 0;
for (int i = 0; i < 1000000; i++) {
String server = choose(serverList, weightMap);
if (server.startsWith("1.0")) {
v1Count++;
}
if (server.startsWith("2.0")) {
v2Count++;
}
if (server.startsWith("3.0")) {
v3Count++;
}
if (server.startsWith("4.0")) {
v4Count++;
}
if (server.startsWith("5.0")) {
v5Count++;
}
}
System.out.println("1.0版本服务随机权重=" + v1Count);
System.out.println("2.0版本服务随机权重=" + v2Count);
System.out.println("3.0版本服务随机权重=" + v3Count);
System.out.println("4.0版本服务随机权重=" + v4Count);
System.out.println("5.0版本服务随机权重=" + v5Count);
System.out.println("耗时时间:" + (System.currentTimeMillis() - t));
}
public static String choose(List<String> serverList, Map<String, Integer> weightMap) {
if (CollectionUtils.isEmpty(serverList)) {
return null;
}
int[] weights = new int[serverList.size()];
for (int i = 0; i < serverList.size(); i++) {
String server = serverList.get(i);
weights[i] = weightMap.get(server);
}
int index = getIndex(weights);
return serverList.get(index);
}
private static int getIndex(int[] weights) {
// 次序号/权重区间值
int[][] weightHolder = new int[weights.length][2];
// 总权重
int totalWeight = 0;
// 赋值次序号和区间值累加的数组值,从小到大排列
// 例如,对于权重分别为20,40, 60的三个服务,将形成[0, 20),[20, 60),[60, 120]三个区间
for (int i = 0; i < weights.length; i++) {
if (weights[i] <= 0) {
continue;
}
totalWeight += weights[i];
weightHolder[i][0] = i;
weightHolder[i][1] = totalWeight;
}
// 获取介于0(含)和n(不含)伪随机,均匀分布的int值
int hitWeight = ThreadLocalRandom.current().nextInt(totalWeight) + 1; // [1, totalWeight)
for (int i = 0; i < weightHolder.length; i++) {
if (hitWeight <= weightHolder[i][1]) {
return weightHolder[i][0];
}
}
return weightHolder[0][0];
}
}
\ No newline at end of file
package com.nepxion.discovery.plugin.framework.loadbalance;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import com.nepxion.discovery.common.exception.DiscoveryException;
public class MapWeightRandomLoadBalanceTest {
public static class MapWeightRandom<K, V extends Number> {
private TreeMap<Double, K> weightMap = new TreeMap<Double, K>();
public MapWeightRandom(List<Pair<K, V>> pairlist) {
for (Pair<K, V> pair : pairlist) {
double value = pair.getValue().doubleValue();
if (value <= 0) {
continue;
}
double lastWeight = weightMap.size() == 0 ? 0 : weightMap.lastKey().doubleValue();
weightMap.put(value + lastWeight, pair.getKey());
}
}
public K random() {
if (MapUtils.isEmpty(weightMap)) {
throw new DiscoveryException("No weight value is configed");
}
double randomWeight = weightMap.lastKey() * Math.random();
SortedMap<Double, K> tailMap = weightMap.tailMap(randomWeight, false);
return weightMap.get(tailMap.firstKey());
}
}
public static void main(String[] args) {
long t = System.currentTimeMillis();
List<Pair<String, Double>> list = new ArrayList<Pair<String, Double>>();
list.add(new ImmutablePair<String, Double>("1.0", 0D));
list.add(new ImmutablePair<String, Double>("2.0", 90D));
list.add(new ImmutablePair<String, Double>("3.0", 10D));
list.add(new ImmutablePair<String, Double>("1.0", 0D));
list.add(new ImmutablePair<String, Double>("2.0", 90D));
list.add(new ImmutablePair<String, Double>("3.0", 10D));
list.add(new ImmutablePair<String, Double>("4.0", 0D));
list.add(new ImmutablePair<String, Double>("4.0", 0D));
list.add(new ImmutablePair<String, Double>("5.0", 0D));
list.add(new ImmutablePair<String, Double>("5.0", 0D));
int v1Count = 0;
int v2Count = 0;
int v3Count = 0;
int v4Count = 0;
int v5Count = 0;
for (int i = 0; i < 1000000; i++) {
MapWeightRandom<String, Double> weightRandom = new MapWeightRandom<String, Double>(list);
String server = weightRandom.random();
if (server.startsWith("1.0")) {
v1Count++;
}
if (server.startsWith("2.0")) {
v2Count++;
}
if (server.startsWith("3.0")) {
v3Count++;
}
if (server.startsWith("4.0")) {
v4Count++;
}
if (server.startsWith("5.0")) {
v5Count++;
}
}
System.out.println("1.0版本服务随机权重=" + v1Count);
System.out.println("2.0版本服务随机权重=" + v2Count);
System.out.println("3.0版本服务随机权重=" + v3Count);
System.out.println("4.0版本服务随机权重=" + v4Count);
System.out.println("5.0版本服务随机权重=" + v5Count);
System.out.println("耗时时间:" + (System.currentTimeMillis() - t));
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment