zoukankan      html  css  js  c++  java
  • springcloud-Ribbon负载均衡服务调用(四)

    Ribbon入门介绍

    • 是什么
    1. Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具.
    2. Ribbon主要功能是提供客户端的软件负载均衡算法和服务调用. 
    3. Ribbon客户端组件提供一系列完整的配置项如连接超时, 重试等. 简单的说, 就是在配置文件中列出Load Balancer后所有的机器, Ribbon会自动帮我们基于某种规则(如简单轮询, 随机连接)去链接这些机器, 我们很容易使用Ribbon实现自定义的负载均衡算法.
    • 负载均衡
    1. 简单的说就是将用户的请求平摊到多个服务上, 从而达到系统的高可用, 常见的负载均衡有软件Nginx, LVS, 硬件F5等.
    2. Ribbon负载均衡 VS Nginx负载均衡
      • Nginx是服务器负载均衡, 客户端所有请求都会交给nginx, 然后由nginx实现转发请求, 即负载均衡是由服务端实现的.
      • Ribbon是客户端负载均衡, 在调用微服务接口的时候, 会在注册中心上获取注册信息服务列表之后缓存到JVM本地, 从而在本地实现RPC远程服务调用技术.
    3. 集中式LB
      • 在服务的消费方和提供方之间使用独立的LB设施(如Nginx), 由该设施负责把访问请求通过某种策略转发至服务的提供方.
    4. 进程内LB
      • 将LB逻辑集成到消费方, 消费方从服务注册中心获知哪些地址可用, 然后自己再从这些地址中选出一个合适的服务器.
      • Ribbon就属于进程内LB, 它只是一个类库, 集成于消费方进程, 消费方通过它来获取到服务提供方的地址.

    Ribbon负载均衡演示

    • 所谓Ribbon, 简单的说就是负载均衡 + RestTemplate
    • 架构说明

    1. Ribbon在工作时分两步
      • 第一步先选择Eureka Server, 它优先选择在同一个区域内负载较少的server.
      • 第二步再根据用户指定的策略, 在从server取到的服务注册列表中选择一个地址.
        • 策略有多种可选, 如轮询, 随机, 根据响应时间加权.
    2. 这里需要注意, Ribbon其实就是一个软负载均衡的客户端组件, 它可以和其他所需请求的客户端结合使用, 这里仅用Eureka举例.
    • POM分析
    1. 我们只加入了eureka的依赖
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
          </dependency>
    2. 而在Eureka中是有Ribbon的依赖的
          <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            <version>2.2.1.RELEASE</version>
            <scope>compile</scope>
          </dependency>
    • 详细讲解RestTemplate

    Ribbon核心组件IRule

    • IRule接口: 根据特定算法从服务列表中选取一个要访问的服务
    1. 有7种负载均衡策略
    • 切换负载均衡策略
    1. 我们要写的自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下, 否则我们自定义的配置类就会被所有的Ribbon客户端共享, 达不到特殊化定制的目的了.
    2. 我们新建package及配置类
    3. 配置类代码
      @Configuration
      public class MySelfRule {
      
          @Bean
          public IRule myRule() {
              //将负载均衡策略改为随机
              return new RandomRule();
          }
      }
    4. 主启动类上要加@RibbonClient注解
      • name属性: 服务提供者(负载均衡请求的接收方)
      • configuration属性: 指明我们的配置类
        @RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class)
        @EnableEurekaClient
        @SpringBootApplication
        public class OrderMain80 {
        
            public static void main(String[] args) {
                SpringApplication.run(OrderMain80.class, args);
            }
        }
    5. 测试: http://localhost/consumer/payment/get/1

    Ribbon负载均衡算法

    • 负载轮询算法原理
    1. rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标.
      • 集群总数量: 2台. (List = 2 instance)
      • 第一次: 1 % 2 = 1
      • 第二次: 2 % 2 = 0
      • 第三次: 3 % 2 = 1
      • ......
      • 如果重启了, 那么会从1重新开始.
    • 手写一个负载轮询算法
    1. 在8001/8002微服务的controller添加如下方法
          @GetMapping("/payment/lb")
          public String getPaymentLB() {
              return serverPort;
          }
    2. 80订单微服务改造
      • 去掉@LoadBalanced注解
      • LoadBalancer接口
        public interface LoadBalancer {
        
            ServiceInstance instances(List<ServiceInstance> serviceInstances);
        }
      • MyLB
        @Component
        public class MyLB implements LoadBalancer {
        
            private AtomicInteger atomicInteger = new AtomicInteger(0);
        
            public final int getAndIncrement() {
                int current;
                int next;
                do {
                    current = this.atomicInteger.get();
                    next = current >= 2147483000 ? 0 : current+1;
                } while(!this.atomicInteger.compareAndSet(current, next));
                return next;
            }
        
            @Override
            public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
        
                int index = getAndIncrement() % serviceInstances.size();
        
                return serviceInstances.get(index);
            }
        }
      • controller方法
            @Resource
            private RestTemplate restTemplate;
        
            @Resource
            private LoadBalancer loadBalancer;
        
            @Resource
            private DiscoveryClient discoveryClient;
        
            @GetMapping("/consumer/payment/lb")
            public String getPaymentLB() {
                List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
                if(instances == null || instances.size() <= 0) {
                    return null;
                }
                ServiceInstance serviceInstance = loadBalancer.instances(instances);
                URI uri = serviceInstance.getUri();
                return restTemplate.getForObject(uri+"/payment/lb", String.class);
            }
    3. 测试: http://localhost/consumer/payment/lb
  • 相关阅读:
    多进程多线程的选择
    MessageBox常用用法
    Ioc 控制反转 实例
    解决 MVC 用户上线下线状态问题
    你不知道的东西! c# == 等于运算符 和 Object.Equals()
    一个明确的目标
    .NET String.Format 方法 线程安全问题
    IEnumerable 接口 实现foreach 遍历 实例
    Android闹钟 AlarmManager的使用*
    @Java四种引用包括强引用,软引用,弱引用,虚引用
  • 原文地址:https://www.cnblogs.com/binwenhome/p/13189113.html
Copyright © 2011-2022 走看看