Балансировка нагрузки для обучения входа в SpringCloud

Spring Cloud

ВведениеЧто такое балансировка нагрузкиКлассификация балансировки нагрузкиRibbonвыполнитьединый поставщик услугнесколько поставщиков услугстратегия балансировки нагрузкиОбщие стратегии балансировки нагрузки для лентыНастраиваемая стратегия балансировки нагрузки лентыFeignчто можно сделатьвыполнитьиспользованная литература

Введение

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

Балансировка нагрузки является ключевым компонентом высокодоступной сетевой инфраструктуры и часто используется для распределения рабочих нагрузок между несколькими серверами для повышения производительности и надежности веб-сайтов, приложений, баз данных или других служб.

Веб-архитектура без балансировки нагрузки выглядит так:

img
img

На приведенном выше рисунке пользователь получает доступ к веб-серверу через сеть.Если сервер не работает, вся система будет недоступна. Кроме того, если к серверу одновременно обращается много пользователей, пользователи могут испытывать медленную загрузку или вообще не иметь возможности подключиться из-за ограниченной производительности сервера.

Сбой можно смягчить, добавив на этом этапе балансировщик нагрузки и хотя бы один дополнительный веб-сервер. Вообще говоря, внутренний сервер будет использовать принцип A (непротиворечивость) для предоставления одного и того же содержимого данных, чтобы пользователи могли получать согласованные данные независимо от того, к какому серверу они обращаются.

img
img

Как показано на рисунке выше, несколько серверов предоставляют услуги, и пользователи отправляют запросы балансировщику нагрузки, которые перенаправляются на любой сервер через балансировщик нагрузки, что увеличивает нагрузочную способность системы и повышает производительность.

Классификация балансировки нагрузки

В настоящее время основные решения для балансировки нагрузки в отрасли можно разделить на две категории:

Централизованная балансировка нагрузки: то есть независимое средство балансировки нагрузки (которое может быть аппаратным, например F5, или программным, например Nginx) используется между потребителем и провайдером, и средство перенаправляет запрос на доступ к провайдеру через определенная стратегия.

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

Для студентов, которые хотят узнать больше о классификации балансировки нагрузки, вы можете обратиться кПринцип и классификация технологии балансировки нагрузки

Лента относится ко вторым, это просто библиотека классов, которая интегрирована в потребитель, и потребитель использует ее для получения соответствующего адреса провайдера.

Схема архитектуры двух методов балансировки нагрузки

img
img

Ribbon

Spring Cloud Ribbon — это инструмент балансировки нагрузки на стороне клиента, основанный на Http и TCP, который реализован на основе ленты Netflix. Он не развертывается отдельно, как сервисный реестр, центр конфигурации, API-шлюз, но существует в инфраструктуре почти каждого микросервиса. Понимание ленты очень важно для нас, чтобы использовать Spring Cloud, потому что балансировка нагрузки является одним из важных средств для обеспечения высокой доступности системы, снижения нагрузки на сеть и расширения вычислительных мощностей.

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

В Spring Cloud существует два метода вызова службы: один — Ribbon+RestTemplate, а другой — Feign.

Когда Ribbon используется в сочетании с Eureka, Ribbon может автоматически получать список адресов поставщиков услуг от Eureka Server и запрашивать один из экземпляров поставщиков услуг на основе алгоритма балансировки нагрузки.

выполнить

Мы продолжаем повторно использовать проекты, упомянутые в предыдущих двух разделах, и расширяться на этой основе.Во-первых, давайте вспомним предыдущие проекты.

Родительский модуль:

  • springcloud-api: [инкапсулированный интерфейс класса сущностей]

  • springcloud-provider-dept-8001: [Поставщик услуг]

  • springcloud-consumer-dept-80: [Потребитель услуг]

  • springcloud-config-eureka-7001: [Сервисный реестр 7001]

  • springcloud-config-eureka-7002: [Реестр служб 7002]

  • springcloud-config-eureka-7003: [Сервисный реестр 7003]

единый поставщик услуг

Далее мы вносим изменения в проект springcloud-consumer-dept-80.

1. Импорт зависимостей

<!--ribbon依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

2. Измените application.yml

server:
  port: 80


#eureka配置
eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001:7001/eureka/,http://eureka7002:7002/eureka/,http://eureka7003:7003/eureka/

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

@Configuration
public class MyConfig {

    //配置负载均衡实现RestTemplate
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

4. Измените имя вызова службы в файле DeptConsumerController.

//    private static final String REST_URL_PREFIX = "http://localhost:8001";
    //通过服务名进行调用
    private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";

SPRINGCLOUD-PROVIDER-DEPT в приведенном выше коде — это имя, зарегистрированное поставщиком услуг в реестре, как показано на следующем рисунке:

5. Добавьте аннотацию @EnableEurekaClient к классу входа.

@SpringBootApplication
@EnableEurekaClient
public class DeptConsumer_80 {

    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class,args);
    }
}

6. Запустите три проекта реестра услуг, а также поставщиков услуг и потребителей услуг, посетите http://localhost/consumer/dept/list, и страница отобразит данные в обычном режиме.

несколько поставщиков услуг

Создайте две новые базы данных, db01 и db02, и одну и ту же таблицу отделов.Выражение SQL выглядит следующим образом:

CREATE DATABASE `db01`;
USE `db01`;

CREATE TABLE `dept` (
  `deptId` bigint(20) NOT NULL AUTO_INCREMENT,
  `dpName` varchar(60) NOT NULL,
  `dbSource` varchar(60) NOT NULL,
  PRIMARY KEY (`deptId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


insert into dept (dpname, dbsource) values ('开发部',DATABASE());
insert into dept (dpname, dbsource) values ('人事部',DATABASE());
insert into dept (dpname, dbsource) values ('财务部',DATABASE());
insert into dept (dpname, dbsource) values ('市场部',DATABASE());
insert into dept (dpname, dbsource) values ('后勤部',DATABASE());

После создания базы данных мы создадим двух новых поставщиков услуг, скопируем проект springcloud-provider-dept-8001 и изменим имена на springcloud-provider-dept-8002 и springcloud-provider-dept-8003.Обратите внимание на изменение файлы конфигурации и записи в проекте.Файлы сопоставления классов и преобразователей.

Каждый поставщик услуг соответствует соединению с базой данных. Пример выглядит следующим образом:

server:
  port: 8002

spring:
  datasource:
    username: root
    password: mysql521695
    url: jdbc:mysql://localhost:3306/db01?useUnicode=true&useSSL=true&serverTimezone=UTC&characterEncoding=utf-8
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
  application:
    name: springcloud-provider-dept

mybatis:
  type-aliases-package: com.msdn.pojo
  mapper-locations: classpath:mybatis/mapper/*.xml

#Eureka配置
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001:7001/eureka/,http://eureka7002:7002/eureka/,http://eureka7003:7003/eureka/
  instance:
    instance-id: springcloud-provider-dept-8002   # 修改eureka上的默认描述信息
    prefer-ip-address: true  # true,可以显示服务的IP地址

#info配置
info:
  app.name: hresh-springcloud
  company.name: blog.csdn.net/Herishwater

Текущая структура проекта выглядит следующим образом:

Запустите 3 регистрационных центра, 3 поставщиков услуг и, наконец, запустите потребителя услуг, сначала посетите http://eureka7001:7001/, содержимое страницы выглядит следующим образом:

Затем посетите http://localhost/consumer/dept/list, постоянно обновляйте страницу, и вы увидите, что запрашиваемые данные меняются.

стратегия балансировки нагрузки

Общие стратегии балансировки нагрузки для ленты

// RoundRobinRule 轮询,默认策略,按序获取provider
// RandomRule 随机
// AvailabilityFilteringRule : 可用性敏感策略,会先过滤掉,跳闸,访问故障的服务~,对剩下的进行轮询~
// RetryRule : 会先按照轮询获取服务~,如果服务获取失败,则会在指定的时间内进行,重试
//WeightedResponseTimeRule 权重轮询策略,根据每个Provider的响应时间分配一个权重,响应时间越长权重越小,被选中的可能性就越低,初次会使用轮询策略,直到分配好权重
//BestAvailableRule 最少并发数策略,选择正在请求中并发数量小的provider,除非这个provider在熔断中

Если вы хотите изменить стратегию балансировки нагрузки, в этом примере вам необходимо изменить файл конфигурации MyConfig в проекте потребителя службы следующим образом:

    @Bean
    public IRule getRule(){
        return new RandomRule();
    }

Увеличьте внедрение класса RandomRule, чтобы лента сначала выбирала случайную стратегию.

Настраиваемая стратегия балансировки нагрузки ленты

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

Создайте новую папку со следующей структурой:

Измените класс, имитирующий случайную стратегию, и настройте класс MyRandomRule.

public class MyRandomRule extends AbstractLoadBalancerRule {

    private int count = 0;  //每个服务执行次数
    private int providerNum = 0;    //当前哪个服务被执行

    public MyRandomRule(){

    }

    @SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        } else {
            Server server = null;

            while(server == null) {
                if (Thread.interrupted()) {
                    return null;
                }

                List<Server> upList = lb.getReachableServers(); //获得活着的服务
                List<Server> allList = lb.getAllServers(); //获得全部的服务
                int serverCount = allList.size();
                if (serverCount == 0) {
                    return null;
                }

                //核心部分
//                int index = this.chooseRandomInt(serverCount);
//                server = (Server)upList.get(index);
                //我们定义属于自己的执行策略,目前我们有3个provider,那么决定每个provider执行3次,然后接着执行下一个provider
                if(count<3){
                    server = (Server)upList.get(providerNum);
                    count++;
                }else{
                    count = 0;
                    providerNum++;
                    if(providerNum>=serverCount){
                        providerNum = 0;
                    }
                    server = (Server)upList.get(providerNum);
                }


                if (server == null) {
                    Thread.yield();
                } else {
                    if (server.isAlive()) {
                        return server;
                    }

                    server = null;
                    Thread.yield();
                }
            }

            return server;
        }
    }

    protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);
    }

    public Server choose(Object key) {
        return this.choose(this.getLoadBalancer(), key);
    }

    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }
}

RuleConfig

@Configuration
public class RuleConfig {

    @Bean
    public IRule getRule(){
        return new MyRandomRule();
    }
}

Наконец, добавьте аннотации к классу входа, чтобы активировать стратегию.

@SpringBootApplication
@EnableEurekaClient
//在微服务启动时去加载我们自定义的负载均衡策略
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = RuleConfig.class)
public class DeptConsumer_80 {

    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class,args);
    }
}

Что касается расположения вышеуказанной папки myrule, то причина в следующем:RuleConfig не может находиться в основном контексте приложения.@ComponentScan, иначе он будет определяться всеми@RibbonClientsобщий. если вы используете@ComponentScan(или@SpringBootApplication), необходимо предпринять шаги, чтобы избежать включения (например, поместить его в отдельный непересекающийся пакет или указать@ComponentScan).

Feign

spring cloud feignна основеNetfix Feignреализованный, интегрированныйspring cloud Ribbonа такжеspring cloud Hystrix, — это декларативный клиент веб-службы, который упрощает вызовы между микрослужбами, подобно службе вызова контроллера. SpringCloud интегрирует Ribbon и Eureka, чтобы обеспечить сбалансированный по нагрузке http-клиент при использовании Feign.

что можно сделать

Когда мы описывали использование Ribbon в предыдущем разделе, мы использовали его перехват запросов RestTemplate для реализации вызовов интерфейса к зависимым службам, а RestTemplate уже реализовал инкапсуляцию обработки http-запросов, формируя набор шаблонных методов вызова. Однако в реальной разработке, поскольку может быть более одного вызова зависимостей служб, интерфейс часто вызывается в нескольких местах, поэтому нам необходимо инкапсулировать некоторые клиентские классы для каждой микрослужбы, чтобы обернуть вызов этих зависимых служб, разделив код на модули. повторяется в каждом клиенте, и объем кода будет относительно большим.

Например, в проекте springcloud-consumer-dept-80, который мы использовали в предыдущем случае, класс DeptConsumerController инкапсулирует метод обработки HTTP-запросов.Если в это время мы создаем нового потребителя службы, нам также необходимо обработать соответствующую логику. объекта отдела. Вам необходимо скопировать копию кода DeptConsumerController.

а такжеspring cloud feignНа этой основе он дополнительно инкапсулируется, что помогает нам определить и реализовать определение зависимых сервисных интерфейсов. существуетspring cloud feignПри реализации нам нужно только создать интерфейс и вызвать аннотацию для его настройки, а затем можно будет выполнить привязку интерфейса к сервис-провайдеру, что упрощает использованиеspring cloud ribbonПри автоматической инкапсуляции тома разработки службы, вызывающей клиента.

выполнить

Во-первых, нам нужно добавить класс интерфейса, реализующий Feign, в проект springcloud-api.

1. Импорт зависимостей

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-feign</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
</dependencies>

2. Добавьте класс интерфейса службы

DeptFeignService

package com.msdn.service;

import com.msdn.pojo.Dept;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.List;

@Service
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptFeignService {

    @PostMapping("/dept/add")
    boolean addDept(@RequestBody Dept dept);

    @GetMapping("/dept/get/{id}")
    Dept queryDept(@PathVariable("id") long id);

    @GetMapping("/dept/list")
    List<Dept> queryAll();
}

Обратитесь к проекту springcloud-consumer-dept-80, чтобы создать новый проект maven с именем springcloud-consumer-dept-80-feign Общее содержание остается прежним, с некоторыми изменениями.

1. Импорт зависимостей

<dependencies>
    <dependency>
        <groupId>com.msdn</groupId>
        <artifactId>springcloud-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-feign</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-ribbon</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
</dependencies>

2. Файл DeptConsumerController

@RestController
public class DeptConsumerController {

    @Autowired
    DeptFeignService service;

    @RequestMapping("/consumer/dept/get/{id}")
    public Dept getDept(@PathVariable("id") long id) {
        return service.queryDept(id);
    }

    @RequestMapping("/consumer/dept/list")
    public List<Dept> queryAll() {
        return service.queryAll();
    }

    @RequestMapping(name = "/consumer/dept/add")
    public boolean addDept(Dept dept) {
        return service.addDept(dept);
    }

}

3. Добавьте аннотацию EnableFeignClients к классу входа.

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class FeignDeptConsumer_80 {

    public static void main(String[] args) {
        SpringApplication.run(FeignDeptConsumer_80.class,args);
    }

4. Запустите 3 реестра и 3 поставщика услуг, затем запустите нового потребителя службы, посетите http://localhost/consumer/dept/list, обновите страницу несколько раз и обнаружите, что последовательность вызовов потребителей выполняется последовательно, то есть , стратегия голосования.

Для получения подробной информации посетите: https://github.com/Acorn2/springcloud-eureka, если у вас есть какие-либо вопросы, свяжитесь со мной.

использованная литература

Глубокое понимание балансировки нагрузки

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

Интервьюер: Расскажите мне о нескольких известных вам категориях балансировки нагрузки.

Spring Cloud Simulation Learning 1: быстрый старт

Учебные заметки Spring-Cloud-Ribbon (1): Начало работы

Spring-Cloud-Eureka-Study Notes

SpringCloud Learning 1 — Регистрация и обнаружение сервисов (Eureka)