客户端负载均衡组件

Client Side Load Balancer : Ribbon

官网:链接

Ribbon 作为负载均衡,在客户端实现,服务段可以启动两个端口不同但 servername一样的服务
Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将 Netflix 的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出 Load Balancer后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。简单地说,Ribbon是一个客户端负载均衡器

Ribbon工作时分为两步:第一步先选择 Eureka Server, 它优先选择在同一个Zone且负载较少的Server;第二步再根据用户指定的策略,在从Server取到的服务注册列表中选择一个地址。其中Ribbon提供了多种策略,例如轮询、随机、根据响应时间加权等。

ribbon工作流程:

Ribbon 生产使用

在生产环境,Ribbon 与 eureka,feign 一起使用
作为一个微服务应用,我们每个请求都会带服务名访问对应的应用,比如请求一个如下的 url :
http://172.16.56.211:8883/E6-MS-TMS-BUSI-WEB/equip/findEquipTypeList

http://172.16.56.211:8883/ 网关程序;
E6-MS-TMS-BUSI-WEB 微服务名,也是每个应用注册到 Eureka 的服务名称;
/equip/findEquipTypeList 具体的接口 Controller 地址

当一个请求访问网关程序, 验权通过后,请求会到 ribbon, ribbon 维护了一个当前可用的服务列表。(通过定时任务)。ribbon 通过负载均衡策略从当前可用服务列表中,选择某个服务机器,发起调用请求。

微服务服务之间存在相互调用,集成ribbon 后,每个服务内维护有其他服务的信息。在开发调试过程中,我们经常需要指定机器,发起调用。此时我们使用了配置文件,配置文件中配置服务名和机器的 ip 端口映射。在 ribbon 发起请求时,重写 RandomRule, 请求来后,会首先从配置文件中找对应的服务路由配置,如果没有再使用 ribbon 默认的负载均衡策略。这样就解决了微服务调试的问题。

Ribbon 服务选择流程

源码

接口定义了负载均衡器上的操作行为,维护服务list,定义了选择服务的方法;

  1. package com.netflix.loadbalancer;
  2. import java.util.List;
  3. /**
  4. * Interface that defines the operations for a software loadbalancer. A typical
  5. * loadbalancer minimally need a set of servers to loadbalance for, a method to
  6. * mark a particular server to be out of rotation and a call that will choose a
  7. * server from the existing list of server.
  8. *
  9. * @author stonse
  10. *
  11. */
  12. public interface ILoadBalancer {
  13. /**
  14. * Initial list of servers.
  15. * This API also serves to add additional ones at a later time
  16. * The same logical server (host:port) could essentially be added multiple times
  17. * (helpful in cases where you want to give more "weightage" perhaps ..)
  18. *
  19. * @param newServers new servers to add
  20. */
  21. public void addServers(List<Server> newServers);
  22. /**
  23. * Choose a server from load balancer.
  24. *
  25. * @param key An object that the load balancer may use to determine which server to return. null if
  26. * the load balancer does not use this parameter.
  27. * @return server chosen
  28. */
  29. public Server chooseServer(Object key);
  30. /**
  31. * To be called by the clients of the load balancer to notify that a Server is down
  32. * else, the LB will think its still Alive until the next Ping cycle - potentially
  33. * (assuming that the LB Impl does a ping)
  34. *
  35. * @param server Server to mark as down
  36. */
  37. public void markServerDown(Server server);
  38. /**
  39. * @deprecated 2016-01-20 This method is deprecated in favor of the
  40. * cleaner {@link #getReachableServers} (equivalent to availableOnly=true)
  41. * and {@link #getAllServers} API (equivalent to availableOnly=false).
  42. *
  43. * Get the current list of servers.
  44. *
  45. * @param availableOnly if true, only live and available servers should be returned
  46. */
  47. @Deprecated
  48. public List<Server> getServerList(boolean availableOnly);
  49. /**
  50. * @return Only the servers that are up and reachable.
  51. */
  52. public List<Server> getReachableServers();
  53. /**
  54. * @return All known servers, both reachable and unreachable.
  55. */
  56. public List<Server> getAllServers();
  57. }

类图
image.png

baseLoadBalancer 实现了ILoadbalancer 基础接口,维护了一个 serverList ,实现了默认的chooseServer 方法。默认负载均衡策略是轮询 RoundRobinRule;

负载均衡的策略接口

  1. public interface IRule{
  2. /*
  3. * choose one alive server from lb.allServers or
  4. * lb.upServers according to key
  5. *
  6. * @return choosen Server object. NULL is returned if none
  7. * server is available
  8. */
  9. public Server choose(Object key);
  10. public void setLoadBalancer(ILoadBalancer lb);
  11. public ILoadBalancer getLoadBalancer();
  12. }

image.png

具体策略说明:

策略名 策略描述 实现说明
RandomRule 随机选择一个 server 在 index 上随机,选择 index 对应位置的 Server
RoundRobinRule 轮询选择 server 轮询 index,选择 index 对应位置的 server
ZoneAvoidanceRule 复合判断 server 所在区域的性能和 server 的可用性选择 server 使用 ZoneAvoidancePredicate 和 AvailabilityPredicate 来判断是否选择某个 server。ZoneAvoidancePredicate 判断判定一个 zone 的运行性能是否可用,剔除不可用的 zone(的所有 server);AvailabilityPredicate 用于过滤掉连接数过多的 server。
BestAvailableRule 选择一个最小并发请求的 server 逐个考察 server,如果 server 被 tripped 了则忽略,在选择其中activeRequestsCount 最小的 server
AvailabilityFilteringRule 过滤掉那些因为一直连接失败的被标记为 circuit tripped 的后端 server,并过滤掉那些高并发的的后端 server(activeConnections 超过配置的阈值) 使用一个 AvailabilityPredicate 来包含过滤 server 的逻辑,其实就就是检查 status 里记录的各个 server 的运行状态
WeightedResponseTimeRule 根据 server 的响应时间分配一个 weight,响应时间越长,weight 越小,被选中的可能性越低 一个后台线程定期的从 status 里面读取评价响应时间,为每个 server 计算一个 weight。weight 的计算也比较简单,responseTime 减去每个 server 自己平均的 responseTime 是 server 的权重。当刚开始运行,没有形成 status 时,使用 RoundRobinRule 策略选择 server。
RetryRule 对选定的负载均衡策略机上重试机制 在一个配置时间段内当选择 server 不成功,则一直尝试使用 subRule 的方式选择一个可用的 server

经典的负载均衡规则可以整理如下:

  • 轮询(Round Robin) or 加权轮询(Weighted Round Robin)
  • 随机(Random) or 加权随机(Weighted Random)
  • 源地址哈希(Hash) or 一致性哈希(ConsistentHash)
  • 最少连接数(Least Connections)
  • 最小响应时间(ResponseTime)