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加权轮询负载均衡算法,实现推荐产品的算法,代码如下:

 1 public class ProductMessage {
 2     private String productName;
 3     private int weight;
 4
 5     public ProductMessage(String productName, int weight) {
 6         this.productName = productName;
 7         this.weight = weight;
 8     }
 9
10     public String getProductName() {
11         return productName;
12     }
13
14     public void setProductName(String productName) {
15         this.productName = productName;
16     }
17
18     public int getWeight() {
19         return weight;
20     }
21
22     public void setWeight(int weight) {
23         this.weight = weight;
24     }
25 }
 1 import java.util.concurrent.atomic.AtomicLong;
 2
 3 public class WeightedRoundRobin {
 4     private int weight;
 5     private AtomicLong current = new AtomicLong(0);
 6     private long lastUpdate;
 7     public int getWeight() {
 8         return weight;
 9     }
10     public void setWeight(int weight) {
11         this.weight = weight;
12         current.set(0);
13     }
14     public long increaseCurrent() {
15         return current.addAndGet(weight);
16     }
17     public void sel(int total) {
18         current.addAndGet(-1 * total);
19     }
20     public long getLastUpdate() {
21         return lastUpdate;
22     }
23     public void setLastUpdate(long lastUpdate) {
24         this.lastUpdate = lastUpdate;
25     }
26 }
 1 import java.util.Map;
 2 import java.util.List;
 3 import java.util.Iterator;
 4 import java.util.concurrent.ConcurrentMap;
 5 import java.util.concurrent.ConcurrentHashMap;
 6 import java.util.concurrent.atomic.AtomicBoolean;
 7
 8 /**
 9  * 业务场景
10  * 轮询推荐产品,保证各产品按指定权重被推荐
11  *
12  */
13 public class ProductRoundRobin {
14     private static int RECYCLE_PERIOD = 300000;
15     private AtomicBoolean updateLock = new AtomicBoolean();
16
17     private ConcurrentMap<String, WeightedRoundRobin> productMap = new ConcurrentHashMap<String, WeightedRoundRobin>();
18
19     public ProductMessage selectProduct(List<ProductMessage> productMessageList) {
20         int totalWeight = 0;
21         long maxCurrent = Long.MIN_VALUE;
22         long now = System.currentTimeMillis();
23         ProductMessage selectedProduct = null;
24         WeightedRoundRobin selectedWRR = null;
25         for (ProductMessage productMessage : productMessageList) {
26             String identifyString = productMessage.toString();
27             WeightedRoundRobin weightedRoundRobin = productMap.get(identifyString);
28             int weight = productMessage.getWeight();
29             if (weight < 0) {
30                 weight = 0;
31             }
32             if (weightedRoundRobin == null) {
33                 weightedRoundRobin = new WeightedRoundRobin();
34                 weightedRoundRobin.setWeight(weight);
35                 productMap.putIfAbsent(identifyString, weightedRoundRobin);
36                 weightedRoundRobin = productMap.get(identifyString);
37             }
38             if (weight != weightedRoundRobin.getWeight()) {
39                 weightedRoundRobin.setWeight(weight);
40             }
41             long cur = weightedRoundRobin.increaseCurrent();
42             weightedRoundRobin.setLastUpdate(now);
43             if (cur > maxCurrent) {
44                 maxCurrent = cur;
45                 selectedProduct = productMessage;
46                 selectedWRR = weightedRoundRobin;
47             }
48             totalWeight += weight;
49         }
50
51         if (!updateLock.get() && productMessageList.size() != productMap.size()) {
52             if (updateLock.compareAndSet(false, true)) {
53                 try {
54                     // copy -> modify -> update reference
55                     ConcurrentMap<String, WeightedRoundRobin> newMap = new ConcurrentHashMap<String, WeightedRoundRobin>();
56                     newMap.putAll(productMap);
57                     Iterator<Map.Entry<String, WeightedRoundRobin>> it = newMap.entrySet().iterator();
58                     while (it.hasNext()) {
59                         Map.Entry<String, WeightedRoundRobin> item = it.next();
60                         if (now - item.getValue().getLastUpdate() > RECYCLE_PERIOD) {
61                             it.remove();
62                         }
63                     }
64                 } finally {
65                     updateLock.set(false);
66                 }
67             }
68         }
69
70         if (selectedProduct != null) {
71             selectedWRR.sel(totalWeight);
72             return selectedProduct;
73         }
74         return productMessageList.get(0);
75     }
76 }
 1 import java.util.Map;
 2 import java.util.List;
 3 import java.util.HashMap;
 4 import java.util.ArrayList;
 5
 6 public class ProductRoundRobinTest {
 7     public static void main(String[] args) {
 8         /**
 9          * 设定:
10          * 产品A,权重5
11          * 产品B,权重1
12          * 产品C,权重1
13          */
14         ProductMessage product1 = new ProductMessage("产品A", 5);
15         ProductMessage product2 = new ProductMessage("产品B", 1);
16         ProductMessage product3 = new ProductMessage("产品C", 1);
17         List<ProductMessage> productMessageList = new ArrayList<ProductMessage>() {{
18             add(product1);
19             add(product2);
20             add(product3);
21         }};
22
23         ProductRoundRobin productRoundRobin = new ProductRoundRobin();
24
25         // 进行7次推荐
26         for (int i = 0; i < 7; i++) {
27             ProductMessage selectedProduct = productRoundRobin.selectProduct(productMessageList);
28             System.out.println("productName:" + selectedProduct.getProductName());
29         }
30
31         Map<String, Long> countMap = new HashMap<>();
32         for (int i = 0; i < 1000000; i++) {
33             ProductMessage selectedProduct = productRoundRobin.selectProduct(productMessageList);
34             Long count = countMap.get(selectedProduct.getProductName());
35             countMap.put(selectedProduct.getProductName(), count == null ? 1 : ++count);
36         }
37
38         for (Map.Entry<String, Long> entry : countMap.entrySet()) {
39             System.out.println("introduce productName:" + entry.getKey() + "; introduce count:" + entry.getValue());
40         }
41     }
42 }

  运行结果如下:

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

  总结:技术服务于业务,将算法逻辑,应用到实际业务中,让业务更加智能化。即所谓的科技赋能。

原文地址:https://www.cnblogs.com/dushenzi/p/12289814.html

时间: 2024-10-04 15:34:36

Dubbo加权轮询负载均衡算法应用之推荐产品的相关文章

Dubbo加权轮询负载均衡的源码和Bug,了解一下?

本文是对于Dubbo负载均衡策略之一的加权随机算法的详细分析.从2.6.4版本聊起,该版本在某些情况下存在着比较严重的性能问题.由问题入手,层层深入,了解该算法在Dubbo中的演变过程,读懂它的前世今生. 之前也写了Dubbo的负载均衡策略: <一文讲透Dubbo负载均衡之最小活跃数算法> <Dubbo一致性哈希负载均衡的源码和Bug,了解一下?> 本文目录 第一节:什么是轮询? 本小节主要是介绍轮询算法和其对应的优缺点.引出加权轮询算法. 第二节:什么是加权轮询? 本小节主要是介

负载均衡算法(二)加权轮询负载均衡算法

/// <summary> /// 加权轮询算法 /// </summary> public static class WeightRoundRobin { private static object obj = new object(); private static int pos = 0; static Dictionary<string, int> dic = new Dictionary<string, int> { { "192.168

说一说负载均衡算法

    负载均衡算法可以分为两类:静态负载均衡算法,基于服务器的容量,就是高配置的服务器比低配置的服务器分配更多的请求:动态负载均衡算法根据服务器的状况,比如通过监控可以得到平均响应时间,或者CPU占用率,内存占用率按照某种方式进行计算,作为权重值 静态负载均衡算法 随机(Random):利用随机数生成算法选取一个服务器,然后把连接发送给他.虽然许多负载产品都支持该算法,但是它的有效性一直受到质疑,除非把服务器的可运行时间看的很重. 轮询(Round Robin):按顺序把每个新的连接请求分配给

负载均衡算法 - 基本实现

? 最近在比赛一个项目 , 是给Dubbo写一个负载均衡接口 , 其实dubbo已经实现了下面四种, 所以他做的不是这个单面负载均衡, 需要做双向负载均衡 , 负载均衡的权重取决于服务端,所以有些时候我们不知道如何计算权重, 权重受到很多因素影响 ,所以就需要动态考虑了. ? Dubbo 提供了4种负载均衡实现,分别是基于权重随机算法的 RandomLoadBalance.基于最少活跃调用数算法的 LeastActiveLoadBalance.基于 hash 一致性的 ConsistentHas

spring-cloud-starter-ribbon提供客户端的软件负载均衡算法

Ribbon是什么? Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起.Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等.简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器.我们也很容易使用Ribbon实现自定义的负载均衡算法. LB方案分类 目前主流的LB方案可分成两类:一种是集中式LB, 即在服

nginx负载均衡算法

nginx负载均衡设置 模块官方介绍: http://wiki.nginx.org/HttpUpstreamModule 说说upstream里的server指令: server 后面可以是域名格式,也可以是socket格式[ip:port],后面还可以带参数. 参数有下面几个:       weight = NUMBER - 设置服务器的权重值,默认为1. 值越大,分配的请求越多.只适用于轮询这种LB策略.       max_fails = NUMBER - 在fail_timeout设置的

Spring Cloud Ribbon 源码分析---负载均衡算法

上一篇分析了Ribbon如何发送出去一个自带负载均衡效果的HTTP请求,本节就重点分析各个算法都是如何实现. 负载均衡整体是从IRule进去的: public interface IRule{ /* * choose one alive server from lb.allServers or * lb.upServers according to key * * @return choosen Server object. NULL is returned if none * server i

Nginx 负载均衡-加权轮询策略剖析

本文介绍的是客户端请求在多个后端服务器之间的均衡,注意与客户端请求在多个nginx进程之间的均衡相区别(Nginx根据每个工作进程的当前压力调整它们获取监听套接口的几率,那些当前比较空闲的工作进程有更多机会获取到监听套接口,从而客户端的请求到达后也就相应地被它捕获并处理).如果Nginx是以反向代理的形式配置运行,那么对请求的实际处理需要转发到后端服务器运行,如果后端服务器有多台,如何选择一台合适的后端服务器来处理当前请求,就是本文要说的负载均衡.这两种均衡互不冲突并且能同时生效. nginx不

【Nginx】负载均衡-加权轮询策略剖析

转自:江南烟雨 本文介绍的是客户端请求在多个后端服务器之间的均衡,注意与客户端请求在多个nginx进程之间的均衡相区别. 如果Nginx是以反向代理的形式配置运行,那么对请求的实际处理需要转发到后端服务器运行,如果后端服务器有多台,如何选择一台合适的后端服务器来处理当前请求,就是本文要说的负载均衡.这两种均衡互不冲突并且能同时生效. nginx不单可以作为强大的web服务器,也可以作为一个反向代理服务器,而且nginx还可以按照调度规则实现动态.静态页面的分离,可以按照轮询.ip哈希.URL哈希