2.1 RandomLoadBalance

RandomLoadBalance 是加权随机算法的具体实现,它的算法思想很简单。假设我们有一组服务器 servers = [A, B, C],他们对应的权重为 weights = [5, 3, 2],权重总和为10。现在把这些权重值平铺在一维坐标值上,[0, 5) 区间属于服务器 A,[5, 8) 区间属于服务器 B,[8, 10) 区间属于服务器 C。接下来通过随机数生成器生成一个范围在 [0, 10) 之间的随机数,然后计算这个随机数会落到哪个区间上。比如数字3会落到服务器 A 对应的区间上,此时返回服务器 A 即可。权重越大的机器,在坐标轴上对应的区间范围就越大,因此随机数生成器生成的数字就会有更大的概率落到此区间内。只要随机数生成器产生的随机数分布性很好,在经过多次选择后,每个服务器被选中的次数比例接近其权重比例。比如,经过一万次选择后,服务器 A 被选中的次数大约为5000次,服务器 B 被选中的次数约为3000次,服务器 C 被选中的次数约为2000次。

以上就是 RandomLoadBalance 背后的算法思想,比较简单。下面开始分析源码。

  1. public class RandomLoadBalance extends AbstractLoadBalance {
  2. public static final String NAME = "random";
  3. private final Random random = new Random();
  4. @Override
  5. protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
  6. int length = invokers.size();
  7. int totalWeight = 0;
  8. boolean sameWeight = true;
  9. // 下面这个循环有两个作用,第一是计算总权重 totalWeight,
  10. // 第二是检测每个服务提供者的权重是否相同
  11. for (int i = 0; i < length; i++) {
  12. int weight = getWeight(invokers.get(i), invocation);
  13. // 累加权重
  14. totalWeight += weight;
  15. // 检测当前服务提供者的权重与上一个服务提供者的权重是否相同,
  16. // 不相同的话,则将 sameWeight 置为 false。
  17. if (sameWeight && i > 0
  18. && weight != getWeight(invokers.get(i - 1), invocation)) {
  19. sameWeight = false;
  20. }
  21. }
  22. // 下面的 if 分支主要用于获取随机数,并计算随机数落在哪个区间上
  23. if (totalWeight > 0 && !sameWeight) {
  24. // 随机获取一个 [0, totalWeight) 区间内的数字
  25. int offset = random.nextInt(totalWeight);
  26. // 循环让 offset 数减去服务提供者权重值,当 offset 小于0时,返回相应的 Invoker。
  27. // 举例说明一下,我们有 servers = [A, B, C],weights = [5, 3, 2],offset = 7。
  28. // 第一次循环,offset - 5 = 2 > 0,即 offset > 5,
  29. // 表明其不会落在服务器 A 对应的区间上。
  30. // 第二次循环,offset - 3 = -1 < 0,即 5 < offset < 8,
  31. // 表明其会落在服务器 B 对应的区间上
  32. for (int i = 0; i < length; i++) {
  33. // 让随机值 offset 减去权重值
  34. offset -= getWeight(invokers.get(i), invocation);
  35. if (offset < 0) {
  36. // 返回相应的 Invoker
  37. return invokers.get(i);
  38. }
  39. }
  40. }
  41. // 如果所有服务提供者权重值相同,此时直接随机返回一个即可
  42. return invokers.get(random.nextInt(length));
  43. }
  44. }

RandomLoadBalance 的算法思想比较简单,在经过多次请求后,能够将调用请求按照权重值进行“均匀”分配。当然 RandomLoadBalance 也存在一定的缺点,当调用次数比较少时,Random 产生的随机数可能会比较集中,此时多数请求会落到同一台服务器上。这个缺点并不是很严重,多数情况下可以忽略。RandomLoadBalance 是一个简单,高效的负载均衡实现,因此 Dubbo 选择它作为缺省实现。

关于 RandomLoadBalance 就先到这了,接下来分析 LeastActiveLoadBalance。