Dubbo加权轮询负载均衡算法应用之推荐产品
Dubbo加权轮询负载均衡算法,核心点:weight(固定的权重),currentWeight(当前权重,动态变化的),算法逻辑:轮询服务提供者(每个服务提供者都有weight和currentWeight),currentWeight增加weight,取最大的currentWeight,然后取对应的服务提供者,最后将取到的服务提供者的currentWeight减去总的权重(所有服务提供者的weight之和)。示例如下:
服务器 [A, B, C] 对应权重 [5, 1, 1] ,现在有7个请求依次进入负载均衡逻辑,选择过程如下:
| 请求编号 | currentWeight 数组 | 选择结果 | 减去权重总和后的 currentWeight 数组 |
|---|---|---|---|
| 1 | [5, 1, 1] | A | [-2, 1, 1] |
| 2 | [3, 2, 2] | A | [-4, 2, 2] |
| 3 | [1, 3, 3] | B | [1, -4, 3] |
| 4 | [6, -3, 4] | A | [-1, -3, 4] |
| 5 | [4, -2, 5] | C | [4, -2, -2] |
| 6 | [9, -1, -1] | A | [2, -1, -1] |
| 7 | [7, 0, 0] | A | [0, 0, 0] |
如上,经过平滑性处理后,得到的服务器序列为 [A, A, B, A, C, A, A]。初始情况下 currentWeight = [0, 0, 0],第7个请求处理完后,currentWeight 再次变为 [0, 0, 0]。
业务实践应用:推荐产品(公司开发了同类型的多种产品,对接的是不同的合作商,现要求按一定的比例,向不同的客户推荐不同合作商的产品,保证各合作商的流量。比如合作商A的产品A:合作商B的产品B:合作商C的产品C=5:1:1,那么如果有7个客户想了解该类型的产品,就向其中5人推荐A,向其中1人推荐B,向其中1人推荐C)。
仿照Dubbo加权轮询负载均衡算法,实现推荐产品的算法,代码如下:
public class ProductMessage {
private String productName;
private int weight;
public ProductMessage(String productName, int weight) {
this.productName = productName;
this.weight = weight;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}import java.util.concurrent.atomic.AtomicLong;
public class WeightedRoundRobin {
private int weight;
private AtomicLong current = new AtomicLong(0);
private long lastUpdate;
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
current.set(0);
}
public long increaseCurrent() {
return current.addAndGet(weight);
}
public void sel(int total) {
current.addAndGet(-1 * total);
}
public long getLastUpdate() {
return lastUpdate;
}
public void setLastUpdate(long lastUpdate) {
this.lastUpdate = lastUpdate;
}
}import java.util.Map;
import java.util.List;
import java.util.Iterator;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* 业务场景
* 轮询推荐产品,保证各产品按指定权重被推荐
*
*/
public class ProductRoundRobin {
private static int RECYCLE_PERIOD = 300000;
private AtomicBoolean updateLock = new AtomicBoolean();
private ConcurrentMap<String, WeightedRoundRobin> productMap = new ConcurrentHashMap<String, WeightedRoundRobin>();
public ProductMessage selectProduct(List<ProductMessage> productMessageList) {
int totalWeight = 0;
long maxCurrent = Long.MIN_VALUE;
long now = System.currentTimeMillis();
ProductMessage selectedProduct = null;
WeightedRoundRobin selectedWRR = null;
for (ProductMessage productMessage : productMessageList) {
String identifyString = productMessage.toString();
WeightedRoundRobin weightedRoundRobin = productMap.get(identifyString);
int weight = productMessage.getWeight();
if (weight < 0) {
weight = 0;
}
if (weightedRoundRobin == null) {
weightedRoundRobin = new WeightedRoundRobin();
weightedRoundRobin.setWeight(weight);
productMap.putIfAbsent(identifyString, weightedRoundRobin);
weightedRoundRobin = productMap.get(identifyString);
}
if (weight != weightedRoundRobin.getWeight()) {
weightedRoundRobin.setWeight(weight);
}
long cur = weightedRoundRobin.increaseCurrent();
weightedRoundRobin.setLastUpdate(now);
if (cur > maxCurrent) {
maxCurrent = cur;
selectedProduct = productMessage;
selectedWRR = weightedRoundRobin;
}
totalWeight += weight;
}
if (!updateLock.get() && productMessageList.size() != productMap.size()) {
if (updateLock.compareAndSet(false, true)) {
try {
// copy -> modify -> update reference
ConcurrentMap<String, WeightedRoundRobin> newMap = new ConcurrentHashMap<String, WeightedRoundRobin>();
newMap.putAll(productMap);
Iterator<Map.Entry<String, WeightedRoundRobin>> it = newMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, WeightedRoundRobin> item = it.next();
if (now - item.getValue().getLastUpdate() > RECYCLE_PERIOD) {
it.remove();
}
}
} finally {
updateLock.set(false);
}
}
}
if (selectedProduct != null) {
selectedWRR.sel(totalWeight);
return selectedProduct;
}
return productMessageList.get(0);
}
}import java.util.Map;
import java.util.List;
import java.util.HashMap;
import java.util.ArrayList;
public class ProductRoundRobinTest {
public static void main(String[] args) {
/**
* 设定:
* 产品A,权重5
* 产品B,权重1
* 产品C,权重1
*/
ProductMessage product1 = new ProductMessage("产品A", 5);
ProductMessage product2 = new ProductMessage("产品B", 1);
ProductMessage product3 = new ProductMessage("产品C", 1);
List<ProductMessage> productMessageList = new ArrayList<ProductMessage>() {{
add(product1);
add(product2);
add(product3);
}};
ProductRoundRobin productRoundRobin = new ProductRoundRobin();
// 进行7次推荐
for (int i = 0; i < 7; i++) {
ProductMessage selectedProduct = productRoundRobin.selectProduct(productMessageList);
System.out.println("productName:" + selectedProduct.getProductName());
}
Map<String, Long> countMap = new HashMap<>();
for (int i = 0; i < 1000000; i++) {
ProductMessage selectedProduct = productRoundRobin.selectProduct(productMessageList);
Long count = countMap.get(selectedProduct.getProductName());
countMap.put(selectedProduct.getProductName(), count == null ? 1 : ++count);
}
for (Map.Entry<String, Long> entry : countMap.entrySet()) {
System.out.println("introduce productName:" + entry.getKey() + "; introduce count:" + entry.getValue());
}
}
}运行结果如下:
productName:产品A productName:产品A productName:产品B productName:产品A productName:产品C productName:产品A productName:产品A introduce productName:产品A; introduce count:714286 introduce productName:产品C; introduce count:142857 introduce productName:产品B; introduce count:142857
总结:技术服务于业务,将算法逻辑,应用到实际业务中,让业务更加智能化。即所谓的科技赋能。
相关推荐
YzhilongY 2020-08-31
crazyjingling 2020-08-16
swtIrene 2020-08-14
slovyz 2020-08-14
tinydu 2020-08-09
tinydu 2020-08-03
Studynutlee 2020-08-03
快乐de馒头 2020-07-29
yungame 2020-07-27
buaichidoufu 2020-07-28
wanjichun 2020-07-26
极地雪狼 2020-07-26
yungame 2020-07-04
畅聊架构 2020-06-28
极地雪狼 2020-06-27
廖先贵 2020-06-23