微服务 springcloud Ribbon客户端负载均衡

青旅半醒 2023-01-11 13:07 221阅读 0赞

微服务 springcloud Ribbon客户端负载均衡

  • 微服务 springcloud Ribbon客户端负载均衡
    • 一、概述
      • 1、Ribbon是什么
      • 2、Ribbon作用
      • 3、Ribbon与nginx负载均衡原理
      • 4、Ribbon工作模式
      • 5、引入依赖坐标
    • 二、Ribbon核心组件IRule
      • 1、IRule:根据特定算法从服务列表中选取一个要访问的服务
    • 三、Ribbon修改访问策略
      • 1、Ribbon配置注意事项
      • 2、新建配置类
      • 3、指定配置
    • 三、Ribbon负载均衡算法
      • 1、原理
      • 2、RoundRobinRule源码
      • 3、重写负载均衡算法

微服务 springcloud Ribbon客户端负载均衡

一、概述

1、Ribbon是什么

SpringCloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡组件。

简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端负载均衡算法和服务调用的组件。
Ribbon客户端组件提供一系列完善的配置如连接超时,重试等简单地说就是在配置文件中列出LoadBalancer后面所以的机器,Ribbon会自动的帮助你基于某种规则(如简单轮训,随机连接等)去连接这些机器。而且我们很容易使用Ribbon实现自定义的负载均衡算法。

在实际使用中,Ribbon实质就是在客户端实现负载均衡,通过RestTemplate实现远程调用。

官网地址:https://github.com/Netflix/ribbon/wiki/Getting-Started

目前进入维护模式,未来SpringCloud LoadBalancer替代。

2、Ribbon作用

在这里插入图片描述Ribbon=负载均衡+RestTemplate调用

3、Ribbon与nginx负载均衡原理

nginx负载原理
在这里插入图片描述Ribbon负载原理
在这里插入图片描述

4、Ribbon工作模式

在这里插入图片描述

5、引入依赖坐标

在这里插入图片描述
新版的Eureka已经整合了Ribbon
在这里插入图片描述

二、Ribbon核心组件IRule

1、IRule:根据特定算法从服务列表中选取一个要访问的服务

在这里插入图片描述

三、Ribbon修改访问策略

Ribbon默认轮训机制,那么如何修改默认访问机制?由于Ribbon是客户端负载所以需要配置客户端。

1、Ribbon配置注意事项

  1. 官方文档明确给出警告:
  2. 这个自定义配置类不能放在@ComponentScan所扫描的当前包下及其子包下。
  3. 否则我们自定义的这个配置类就会被所以的Ribbon客户端所共享,达不到特殊化定制的目的。
  4. 注意:在springboot@ComponentScan可以扫描到的包默认是主程序Application.java类所在包及其子包。

在这里插入图片描述

2、新建配置类

git地址:https://github.com/zrj-coder/cloudboot3
在这里插入图片描述

  1. /** * 配置ribbon策略 * 注意:不要放在主程序所在宝及其子包等能被ComponentScan扫描到的包下面 * * @author zrj * @date 2021/1/23 * @since V1.0 **/
  2. @Configuration
  3. public class MySelfRule {
  4. /** * 定义为随机 */
  5. @Bean
  6. public IRule myRule() {
  7. return new RandomRule();
  8. }
  9. }

3、指定配置

  1. /** * 订单主程序 * 指定Ribbon配置类 * * @author zrj * @date 2021/1/23 * @since V1.0 **/
  2. @EnableEurekaClient
  3. @SpringBootApplication
  4. @RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class)
  5. public class OrderApplication {
  6. public static void main(String[] args) {
  7. SpringApplication.run( OrderApplication.class, args );
  8. }
  9. }

三、Ribbon负载均衡算法

1、原理

  1. 负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 =实际调用服务器位置小标。
  2. 每次服务器重启后rest接口技术从1开始。

在这里插入图片描述

2、RoundRobinRule源码

idea生成的IRule的UML类图,具体方式参考:idea Diagrams生成UML类图
在这里插入图片描述负载均衡算法源码分析

  1. /** * 负载均衡调用算法 * The most well known and basic load balancing strategy, i.e. Round Robin Rule. * * @author stonse * @author Nikos Michalakis <nikos@netflix.com> * */
  2. public class RoundRobinRule extends AbstractLoadBalancerRule {
  3. private AtomicInteger nextServerCyclicCounter; // 服务器调用次数,默认是0
  4. private static final boolean AVAILABLE_ONLY_SERVERS = true;
  5. private static final boolean ALL_SERVERS = false;
  6. private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);
  7. public RoundRobinRule() { // 服务器调用次数,默认是0
  8. nextServerCyclicCounter = new AtomicInteger(0);
  9. }
  10. public RoundRobinRule(ILoadBalancer lb) {
  11. this();
  12. setLoadBalancer(lb);
  13. }
  14. public Server choose(ILoadBalancer lb, Object key) {
  15. if (lb == null) {
  16. log.warn("no load balancer");
  17. return null;
  18. }
  19. Server server = null;
  20. int count = 0;
  21. while (server == null && count++ < 10) {
  22. List<Server> reachableServers = lb.getReachableServers();
  23. // 所有服务集合
  24. List<Server> allServers = lb.getAllServers();
  25. // 缓存本地服务器数量
  26. int upCount = reachableServers.size();
  27. // 获取当前服务器数量
  28. int serverCount = allServers.size();
  29. if ((upCount == 0) || (serverCount == 0)) {
  30. log.warn("No up servers available from load balancer: " + lb);
  31. return null;
  32. }
  33. // 负载均衡具体调用算法
  34. int nextServerIndex = incrementAndGetModulo(serverCount);
  35. server = allServers.get(nextServerIndex);
  36. if (server == null) {
  37. /* Transient. */
  38. Thread.yield();
  39. continue;
  40. }
  41. if (server.isAlive() && (server.isReadyToServe())) {
  42. return (server);
  43. }
  44. // Next.
  45. server = null;
  46. }
  47. if (count >= 10) {
  48. log.warn("No available alive servers after 10 tries from load balancer: "
  49. + lb);
  50. }
  51. return server;
  52. }
  53. /** * 负载均衡具体调用算法 * Inspired by the implementation of {@link AtomicInteger#incrementAndGet()}. * * @param modulo The modulo to bound the value of the counter. * 调用次数 * * @return The next value. * 下一次调用服务器下标 */
  54. private int incrementAndGetModulo(int modulo) {
  55. for (;;) {
  56. // 获得当前调用算法
  57. int current = nextServerCyclicCounter.get();
  58. // 当前调用次数加1 取余 服务器数量
  59. int next = (current + 1) % modulo;
  60. // CAS 自旋 返回
  61. if (nextServerCyclicCounter.compareAndSet(current, next))
  62. return next;
  63. }
  64. }
  65. @Override
  66. public Server choose(Object key) {
  67. return choose(getLoadBalancer(), key);
  68. }
  69. @Override
  70. public void initWithNiwsConfig(IClientConfig clientConfig) {
  71. }
  72. }

3、重写负载均衡算法

  1. /** * 自定义负载均衡算法 * * @author zrj * @date 2021/1/31 * @since V1.0 **/
  2. public interface LoadBalancer {
  3. /** * 服务实例 * * @param serviceInstances * @return */
  4. ServiceInstance instances(List<ServiceInstance> serviceInstances);
  5. }
  6. /** * 自定义负载均衡算法 * * @author zrj * @date 2021/1/31 * @since V1.0 **/
  7. @Component
  8. public class NewLoadBalancer implements LoadBalancer {
  9. private AtomicInteger atomicInteger = new AtomicInteger( 0 );
  10. /** * 自定义负载均衡算法 * * @return */
  11. public final int getAndIncrement() {
  12. int current;
  13. int next;
  14. do {
  15. current = this.atomicInteger.get();
  16. next = current >= Integer.MAX_VALUE ? 0 : current + 1;
  17. } while (!this.atomicInteger.compareAndSet( current, next ));
  18. System.out.println( "*****第几次访问,次数next: " + next );
  19. return next;
  20. }
  21. /** * 负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标 * 每次服务重启动后rest接口计数从1开始。 * * @param serviceInstances * @return */
  22. @Override
  23. public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
  24. int index = getAndIncrement() % serviceInstances.size();
  25. return serviceInstances.get( index );
  26. }
  27. }

发表评论

表情:
评论列表 (有 0 条评论,221人围观)

还没有评论,来说两句吧...

相关阅读