Java RPC中的权重轮询
定义接口
public interface RoundRobin<T> {
T nextData();
}
实现
算法来自nginx
public class WeightedRoundRobin<T> implements RoundRobin<T> {
private List<Item<T>> items = new ArrayList<>();
public WeightedRoundRobin(Map<T, Integer> datas) {
List<Item<T>> initItems = datas.entrySet()
.stream()
.map(e -> new Item<>(e.getKey(), e.getValue()))
.collect(Collectors.toList());
items.addAll(initItems);
}
public T nextData() {
Item<T> bestItem = null;
int total = 0;
for (Item<T> currentItem : items) {
currentItem.currentWeight += currentItem.effectiveWeight;
total += currentItem.effectiveWeight;
if (currentItem.effectiveWeight < currentItem.weight) {
currentItem.effectiveWeight++;
}
if (bestItem == null || currentItem.currentWeight > bestItem.currentWeight) {
bestItem = currentItem;
}
}
if (bestItem == null) {
return null;
}
bestItem.currentWeight -= total;
return bestItem.getData();
}
public List<Item<T>> getItems() {
return items;
}
public void setItems(List<Item<T>> items) {
this.items = items;
}
public static final class Item<T> {
private T data;
private int weight;
private int effectiveWeight;
private int currentWeight;
public Item(T data, int weight) {
this.data = data;
this.weight = weight;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public int getEffectiveWeight() {
return effectiveWeight;
}
public void setEffectiveWeight(int effectiveWeight) {
this.effectiveWeight = effectiveWeight;
}
public int getCurrentWeight() {
return currentWeight;
}
public void setCurrentWeight(int currentWeight) {
this.currentWeight = currentWeight;
}
@Override
public String toString() {
return "Item{" +
"data=" + data +
", weight=" + weight +
", effectiveWeight=" + effectiveWeight +
", currentWeight=" + currentWeight +
'}';
}
}
}
使用
Map<Integer, Integer> testDatas = new HashMap<Integer, Integer>() {{
put(1, 3); // 权重3
put(2, 5); // 权重5
put(3, 8); // 权重8
}};
WeightedRoundRobin<Integer> roundRobin = new WeightedRoundRobin<>(testDatas);
for (int i = 0; i < 20; i++) {
LOGGER.info("id: {}", roundRobin.nextData());
}