Spring Cloud (6): вызов службы балансировки нагрузки ленты

1 Обзор

Spring Cloud Ribbon - это набор инструментов балансировки клиентской нагрузки на основе Netflix Ribbon.

Проще говоря, Ribbon - это проект с открытым исходным кодом, выпущенный Netflix. Его основная функция заключается в предоставлении клиентских алгоритмов балансировки нагрузки и вызовов служб. Компонент клиента ленты предоставляет ряд полных элементов конфигурации, таких как тайм-аут соединения, повторная попытка и т. Д. Проще говоря, это список всех машин, на которых выполняется балансировка нагрузки (сокращенно LB) в файле конфигурации. Лента автоматически поможет вам подключить эти машины на основе определенных правил (таких как простой опрос, случайное соединение и т. Д.). для нас легко Используйте ленту для реализации настраиваемых алгоритмов балансировки нагрузки.

Информация с официального сайта: https://github.com/Netflix/ribbon/wiki/Getting-Started

2. LB (балансировка нагрузки)

2.1 Что такое балансировка нагрузки LB

Проще говоря, запросы пользователя равномерно распределяются между несколькими серверами, чтобы обеспечить высокую доступность системы. Обычная балансировка нагрузки включает программное обеспечение nginx, LVS, аппаратное обеспечение F5 и т. Д.

2.2 Разница между локальным гостевым клиентом балансировки нагрузки ленты и балансировкой нагрузки сервера nginx

Nginx - это балансировка нагрузки на сервер.Все клиентские запросы передаются в nginx, а затем nginx реализует переадресацию запросов, то есть балансировка нагрузки осуществляется сервером.

Локальная балансировка нагрузки на ленте: при вызове интерфейса микросервиса список служб регистрационной информации будет получен из списка реестра и кэширован локально в JVM, тем самым локально реализуя технологию вызова удаленных служб RPC.

Централизованная LB
относится к использованию независимых LB-средств (оборудования, такого как F5 или программного обеспечения, такого как nginx) между потребителем и поставщиком услуги.Средство отвечает за пересылку запроса на доступ к услуге через определенную стратегию. Provider.

Внутрипроцессный LB
интегрирует логику LB в потребителя. Потребитель выбирает подходящий сервер из реестра служб или из доступных адресов. Лента принадлежит внутрипроцессному LB, который является просто библиотекой классов. Интегрирован в процесс потребителя, через него потребитель получает адрес поставщика услуг.

3. Балансировка нагрузки на ленту.

3.1 Описание архитектуры

Вставьте описание изображения сюда
Лента при работе делится на два этапа:

  • Первый шаг - выбрать Eureka Server, он предпочитает выбирать сервер с меньшей нагрузкой в ​​той же области.
  • Вторая часть выбирает адрес из списка услуг, полученных сервером, в соответствии со стратегией, заданной пользователем.
    Среди них Ribbon предоставляет различные стратегии: такие как опрос, случайный выбор и взвешивание на основе времени ответа.

Описание: Лента на самом деле является клиентским компонентом мягкой балансировки нагрузки. Ее можно использовать вместе с другими клиентами, которым требуются запросы. Комбинация с eureka - лишь один из примеров.

3.2 Использование RestTemplate

https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/javadoc-api/org/springframework/web/client/RestTemplate.html

метод getForObject / метод getForEntity
Вставьте описание изображения сюда

postForObject / postForEntity
Вставьте описание изображения сюда

3.3 Компонент сердечника ленты IRule

IRule: выберите службу, к которой будет осуществляться доступ, из списка служб в соответствии с определенным алгоритмом.

  • com.netflix.loadbalancer.RoundRobinRule: опрос
  • com.netflix.loadbalancer.RandomRule: Случайно
  • com.netflix.loadbalancer.RetryRule: сначала получите услугу в соответствии со стратегией RoundRobinRule, в случае сбоя службы она повторит попытку в течение указанного времени.
  • WeightedResponseTimeRule: расширение RoundRobinRule, чем выше скорость ответа, чем больше вес выбора экземпляра, тем легче его выбрать
  • BestAvailableRule: сначала отфильтрует службы, которые находятся в состоянии отключения выключателя из-за множественных сбоев доступа, а затем выберет службу с наименьшим количеством параллелизма.
  • AvailabilityFilteringRule: сначала отфильтруйте отказавшие экземпляры, а затем выберите экземпляр с меньшим параллелизмом.
  • ZoneAvoidanceRule: правило по умолчанию, составная часть оценивает производительность области, где расположен сервер, и доступность сервера для выбора сервера.

Как заменить
modify cloud-consumer-order80
Обратите внимание на детали конфигурации:
Вставьте описание изображения сюда
Вставьте описание изображения сюда

  • Новый пакет
    Вставьте описание изображения сюда
  • Создайте новый класс MyselfRule
package com.lele.myrule;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author: lele
 * @date: 2021/3/15 7:12
 * @description:
 */
@Configuration
public class MySelfRule {
    
    

    @Bean
    public IRule myRule() {
    
    
        return new RandomRule(); // 定义为随机
    }
}
  • Добавьте доступ
    Вставьте описание изображения сюда
    браузера @RibbonClient к основному классу запуска потребителя 80 : http: // localhost / consumer / payment / get / 1

4. Алгоритм балансировки нагрузки ленты.

4.1 Принцип

Алгоритм балансировки нагрузки: количество запросов к остальному интерфейсу% Общее количество кластеров серверов = фактический индекс местоположения сервера вызовов (счетчик остальных интерфейсов начинается с 1 после каждого перезапуска)

List instances = discoveryClient.getInstances(“CLOUD-PAYMENT-SERVICE”);

List[0] instances = 127.0.0.1:8001
List[1] instances = 127.0.0.1:8002

8001 и 8002 объединены в кластер. Всего у них две машины, а общее количество кластеров равно 2. По принципу алгоритма опроса:

Когда общее количество запросов равно 1, 1% 2 = 1 соответствует позиции индекса 1, а полученный адрес сервера - 127.0.0.1:8002
Когда общее количество запросов равно 2, 2% 2 = 0 соответствует позиция индекса 0, и полученный адрес сервера 127.0.0.1:8001,
когда общее количество запросов равно 3, и 3% 2 = 1 соответствует позиции индекса 1, а полученный адрес сервера - 127.0.0.1 : 8002,
когда общее количество запросов равно 4, 4% 2 = 0 соответствует следующему Если позиция метки равна 0, полученный адрес сервера - 127.0.0.1:8001…
и
так далее

4.2 Алгоритм опроса рукописного ввода

  • Запуск кластера 7001/7002

  • Преобразование микросервисов 8001/8002
    Вставьте описание изображения сюда
    Вставьте описание изображения сюда

  • Преобразование микросервиса 80 порядка:

    • ApplicationContextBean удалить @LoadBalanced
      Вставьте описание изображения сюда

    • LoadBalancer интерфейс
      Вставьте описание изображения сюда

    • MyLB

      package com.lele.springcloud.lb;
      
      import org.springframework.cloud.client.ServiceInstance;
      import org.springframework.stereotype.Component;
      
      import java.util.List;
      import java.util.concurrent.atomic.AtomicInteger;
      
      /**
       * @author: lele
       * @date: 2021/3/16 7:27
       * @description:
       */
      @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 >= 2147483647 ? 0 : current + 1;
              } while (!this.atomicInteger.compareAndSet(current,  next));
              System.out.println("*****第几次访问,次数next:"+next);
              return next;
          }
      
          @Override
          public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
              
              
              int index = getAndIncrement() % serviceInstances.size();
              return serviceInstances.get(index);
          }
      }
      
      
  • 80 OrderController

package com.lele.springcloud.controller;

import com.lele.springcloud.entities.CommonResult;
import com.lele.springcloud.entities.Payment;
import com.lele.springcloud.lb.LoadBalancer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.net.URI;
import java.util.List;

/**
 * @author: lele
 * @date: 2021/3/1 21:33
 * @description:
 */
@RestController
@Slf4j
public class OrderController {
    
    

//    public static final String PAYMENT_URL = "http://localhost:8001";
    public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private LoadBalancer loadBalancer;

    @Resource
    private DiscoveryClient discoveryClient;

    @GetMapping("/consumer/payment/create")
    public CommonResult<Payment> create(Payment payment) {
    
    
        return restTemplate.postForObject(PAYMENT_URL + "/payment/create", payment, CommonResult.class);
    }

    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable("id") Long id) {
    
    
        return restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);
    }

    @GetMapping("/consumer/payment/getForEntity/{id}")
    public CommonResult<Payment> getPayment2(@PathVariable("id") Long id) {
    
    
        ResponseEntity<CommonResult> entity = restTemplate.getForEntity(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);

        if (entity.getStatusCode().is2xxSuccessful()) {
    
    
            return entity.getBody();
        } else {
    
    
            return new CommonResult<>(444, "操作失败");
        }
    }

    @GetMapping(value = "/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);
    }

}

  • 测试
    http: // localhost / consumer / payment / lb

рекомендация

отblog.csdn.net/houwanle/article/details/114789056