前文分析了DividePlugin插件中负载均衡的总体结构以及Random的具体实现。今天来探索剩下两种负载均衡是如何实现的。

准备工作

见Soul网关源码探秘《八》 - 负载均衡初探

Hash

找到具体实现类HashLoadBalance直接查看

public DivideUpstream doSelect(final List<DivideUpstream> upstreamList, final String ip) {// 1. 遍历服务列表,为每个服务在生成 VIRTUAL_NODE_NUM 条(默认为5条)的 hash-服务 记录,放入一个有序 treemap 存放for (DivideUpstream address : upstreamList) {for (int i = 0; i < VIRTUAL_NODE_NUM; i++) {long addressHash = hash("SOUL-" + address.getUpstreamUrl() + "-HASH-" + i);treeMap.put(addressHash, address);}}// 2. 使用参数 ip 生成一个 hash 值long hash = hash(String.valueOf(ip));// 3. 在 treemap 中找出 key 比 hash 大的所有记录SortedMap<Long, DivideUpstream> lastRing = treeMap.tailMap(hash);if (!lastRing.isEmpty()) {// 4. 返回符合条件的第一条记录return lastRing.get(lastRing.firstKey());}// 5. 如果没有 key 比 hash 大的记录,则返回 treemap 中的第一条记录return treeMap.firstEntry().getValue();}

可以看到,在 hash 算法中,并没有使用到权重值参与到计算中。

看完还有以下两个问题有点懵:

  1. 没有看懂这样实现负载均衡有啥优势?
  2. 怎么保证转发更加平均?

RoundRobin

找到RoundRobinLoadBalance查看具体实现:

public DivideUpstream doSelect(final List<DivideUpstream> upstreamList, final String ip) {// ...// 1. 每次接收到请求的总权重int totalWeight = 0;long maxCurrent = Long.MIN_VALUE;// ...for (DivideUpstream upstream : upstreamList) {// ...// 2. 每一个服务中维护一个积累值,积累值每次增加的值为该服务的权重值long cur = weightedRoundRobin.increaseCurrent();// ...// 3. 如果当前服务积累值大于 maxCurrent,则选择该服务;继续下一次循环if (cur > maxCurrent) {maxCurrent = cur;selectedInvoker = upstream;selectedWRR = weightedRoundRobin;}// 4. 总权重增加totalWeight += weight;}// 5. 没搞懂这一部分是会在什么情况下触发;以及有什么用处?if (!updateLock.get() && upstreamList.size() != map.size() && updateLock.compareAndSet(false, true)) {try {// copy -> modify -> update referenceConcurrentMap<String, WeightedRoundRobin> newMap = new ConcurrentHashMap<>(map);newMap.entrySet().removeIf(item -> now - item.getValue().getLastUpdate() > recyclePeriod);methodWeightMap.put(key, newMap);} finally {updateLock.set(false);}}if (selectedInvoker != null) {// 6. 如果选中某个服务,那么这个服务对应的 cur 减去总权重进入负值阶段,重新开始积累怒气值selectedWRR.sel(totalWeight);return selectedInvoker;}// should not happen herereturn upstreamList.get(0);}

可以看到对应于每一个服务会维护一个该服务的怒气值,RoundRobin算法会经历这两个阶段:

  1. 每当接收到请求后,每一个服务都会增加相当于自身权重值的怒气值。
  2. 最终怒气值最高的服务在这一轮胜出,执行转发请求的任务。同时,该服务的怒气值会减去总权重进入负值阶段重新开始积攒怒气值。

例如,现有权重分别为50,100的两个服务。

第一轮的 cur 依次为 50,100。100权重的服务胜出并将 cur 减去总权重。最终得到 cur 为 50,-50(100-150)
第二轮的 cur 依次为 100,50(-50+100)。50权重的服务胜出并将 cur 减去总权重。最终得到 cur 为 -50(100-150),50
第二轮的 cur 依次为 0,150。100权重的服务胜出并将 cur 减去总权重。最终得到 cur 为 0,0(150-150)。如此往复。。。


总结

Random 是每次接收请求都是独立按照各自权重进行计算;
而 RoundRobin 是把过往的每一次都算数。

Soul网关源码探秘《十》 - 负载均衡 - Hash/RoundRobin相关推荐

  1. Soul网关源码阅读(十)自定义简单插件编写

    Soul网关源码阅读(十)自定义简单插件编写 简介     综合前面所分析的插件处理流程相关知识,此次我们来编写自定义的插件:统计请求在插件链中的经历时长 编写准备     首先我们先探究一下,一个P ...

  2. Soul网关源码解析目录

    Soul网关源码解析目录 Soul网关源码解析文章列表     对用Java写的高性能网关:Soul,进行一波学习和研究,下面是相关的文章记录 掘金 了解与初步运行 Soul网关源码解析(一) 概览 ...

  3. Soul网关源码阅读(九)插件配置加载初探

    Soul网关源码阅读(九)插件配置加载初探 简介     今日来探索一下插件的初始化,及相关的配置的加载 源码Debug 插件初始化     首先来到我们非常熟悉的插件链调用的类: SoulWebHa ...

  4. Soul网关源码阅读(八)路由匹配初探

    Soul网关源码阅读(八)路由匹配初探 简介      今日看看路由的匹配相关代码,查看HTTP的DividePlugin匹配 示例运行      使用HTTP的示例,运行Soul-Admin,Sou ...

  5. Soul网关源码阅读(七)限流插件初探

    Soul网关源码阅读(七)限流插件初探 简介     前面的文章中对处理流程探索的差不多了,今天来探索下限流插件:resilience4j 示例运行 环境配置     启动下MySQL和redis d ...

  6. Soul网关源码阅读番外篇(一) HTTP参数请求错误

    Soul网关源码阅读番外篇(一) HTTP参数请求错误 共同作者:石立 萧 * 简介     在Soul网关2.2.1版本源码阅读中,遇到了HTTP请求加上参数返回404的错误,此篇文章基于此进行探索 ...

  7. Soul 网关源码阅读(六)Sofa请求处理概览

    Soul 网关源码阅读(六)Sofa请求处理概览 简介     今天来探索一下Sofa请求处理流程,看看和前面的HTTP.Dubbo有什么异同 Sofa示例运行 PS:如果请求加上参数运行不成功,请更 ...

  8. Soul网关源码阅读(六)请求类型探索

    Soul网关源码阅读(六)请求类型探索 简介     在上几篇文章中分析了请求的处理流程,HTTP和RPC请求处理是互斥的,通过请求类型来判断,这篇文章来探索下请求类型的前世今生 源码分析     通 ...

  9. Soul 网关源码阅读(四)Dubbo请求概览

    Soul 网关源码阅读(四)Dubbo请求概览 简介     本次启动一个dubbo服务示例,初步探索Soul网关源码的Dubbo请求处理流程 示例运行 环境配置     在Soul源码clone下来 ...

最新文章

  1. Enda 的 2015 下半年读书计划
  2. 全球及中国汽车空调冷凝器行业发展前景规模及投资战略决策报告2022-2027年
  3. 剑指offer(21):栈的压入、弹出序列
  4. ubuntu查看版本
  5. 【OS学习笔记】二十九 保护模式八:任务切换对应的汇编代码之用户程序代码
  6. Serverless爆发,前端又一大利好消息
  7. 文件自动备份和同步bypy和syncthing
  8. VAX Patch VA_X.DLL 安装位置的问题 for VS2008 , VS2010 , VS2011
  9. C#经纬度坐标算距离
  10. POI Excel列宽设置
  11. CalBioreagents 绵羊抗α-2-HS糖蛋白 亲和纯化说明
  12. 12 款适用于开发人员的最佳 Web 开发软件
  13. 用计算机运算符编写检索式,在计算机检索中,常用的布尔逻辑算符有哪几种
  14. ESP32 开发笔记(三)源码示例 10_IIC_ADXL345 使用IIC总线实现读取ADXL345角度加速度传感器
  15. cocos 躲避球游戏(1) --创建项目和场景切换
  16. layui镜像网站分享
  17. 什么是DBMS以及DBMS的分类
  18. 软件开发专业需要学习多少年
  19. elasticsearch搭建遇到的问题整理合集1
  20. 为什么越来越多明星开始关注加密货币?

热门文章

  1. HTML表格中包多个CApTion,Html中的table包括 caption、col、colgroup、thead、tfoot 以及 tbody...
  2. 怎么把位域合成一个字节_C51中位域在字节中的位置关系
  3. Android 应用访问权限设置
  4. elementui 隐藏输入框_vue+element-ui实现显示隐藏密码
  5. C语言的整型和长整型的字节长
  6. Idea 无法创建Servlet问题
  7. 431金融带计算机,金融硕士考研:考研金融431能带计算器吗?
  8. 修改注册表消除应用软件乱码显示(转)
  9. 使用scrollTop回到顶部时间
  10. 机会成本---你到底是赚了,还是赔了?