Introduction To load balancing What is load balancing the Ribbon Implements a single service provider Multiple service providers Load balancing policies Ribbon Common load balancing policies Ribbon Custom load balancing policies FeignFeign What can you do to implement load balancing? References

Introduction to the

What is load balancing

Load balancing is a key component of high availability network infrastructure and is typically used to distribute workloads across multiple servers to improve the performance and reliability of websites, applications, databases, or other services.

A Web architecture without load balancing looks like this:

img

In the example above, the user accesses the Web server through the network. If the server is down, the entire system is unavailable. In addition, if many users access the server at the same time, users may encounter slow loading or no connection at all due to the limited performance of the server.

This failure can be mitigated by adding a load balancer and at least one additional Web server to the back end at this point. In general, back-end servers adopt the A (consistency) principle and provide the same data content so that users can get consistent data no matter which server they visit.

img

As shown in the figure above, multiple servers provide services, and users send requests to the load balancer, which forwards them to any server, increasing the system’s load capacity and improving performance.

Classification of load balancing

Currently, the mainstream load balancing solutions in the industry can be divided into two categories:

Centralized load balancing: A separate load balancing facility (either hardware, such as F5, or software, such as Nginx) is used between the consumer and provider to forward access requests to the provider through certain policies.

In-process load balancing: The logic of load balancing is integrated into the consumer, who learns from the service registry which addresses are available and selects an appropriate provider from these addresses.

Those who want to know more about load balancing classification can refer to the principle of load balancing technology and classification

The Ribbon is in the latter category. It is simply a library that integrates with consumers to obtain appropriate provider addresses.

Architecture diagram of two load balancing modes

img

Ribbon

Spring Cloud Ribbon is a client load balancing tool based on Http and TCP. It is implemented based on Netflix Ribbon. It is not deployed independently like a service registry, configuration center, or API gateway, but it exists in almost every microservice infrastructure. Understanding the Ribbon is very important for us to use Spring Cloud, because load balancing is one of the most important means for system high availability, network stress relief, and processing capacity expansion.

The Ribbon can automatically help service consumers invoke interfaces based on load balancing algorithms such as polling (default), randomization, weighted polling, weighted randomization, and even custom load balancing algorithms.

In Spring Cloud, there are two service invocation methods, Ribbon+RestTemplate and Feign.

When the Ribbon works with Eureka, the Ribbon automatically obtains a list of service provider addresses from the Eureka Server and requests one of the service provider instances based on the load balancing algorithm.

implementation

Let’s continue with the projects we covered in the previous two sections and expand on them. First, let’s recall the previous projects.

The parent module:

  • Springcloud-api: [Packaged entity Class Interface]

  • Springcloud-provider-dept-8001:

  • Springcloud-consumer-dept-80: [Service Consumer]

  • Springcloud-config-eureka-7001:

  • Springcloud-config-eureka-7002: service Registry 7002

  • Springcloud-config-eureka-7003: service Registry 7003

Single service provider

Next we will make changes for the SpringCloud-consumer-Dept-80 project.

1. Import dependencies

<! - ribbon depend on -- -- >

<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>

Copy the code

2. Modify application.yml

server:

  port: 80





# eureka configuration

eureka:

  client:

    register-with-eureka: false

    service-url:

      defaultZone: http://eureka7001:7001/eureka/,http://eureka7002:7002/eureka/,http://eureka7003:7003/eureka/

Copy the code

3. Configure load balancing

@Configuration

public class MyConfig {



    // Configure load balancing to implement RestTemplate

    @Bean

    @LoadBalanced

    public RestTemplate getRestTemplate(a){

        return new RestTemplate();

    }

}

Copy the code

4. Change the service invocation name in DeptConsumerController

// private static final String REST_URL_PREFIX = "http://localhost:8001";

    // Call by service name

    private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";

Copy the code

In the code above, SpringCloud-provider-Dept is the name registered by the service PROVIDER in the registry, as shown below:

Add the @enableeurekaclient annotation to the entry class

@SpringBootApplication

@EnableEurekaClient

public class DeptConsumer_80 {



    public static void main(String[] args) {

        SpringApplication.run(DeptConsumer_80.class,args);

    }

}

Copy the code

6, launched three service registry, and service providers and service consumers, visit http://localhost/consumer/dept/list, normal display data page.

Multiple service providers

Create two tables db01 and DB02, and create the same DEPT table as db01 and DB02.

CREATE DATABASE `db01`;

USE `db01`;



CREATE TABLE `dept` (

  `deptId` bigint(20NOT NULL AUTO_INCREMENT,

  `dpName` varchar(60NOT NULL.

  `dbSource` varchar(60NOT NULL.

  PRIMARY KEY (`deptId`)

ENGINE=InnoDB DEFAULT CHARSET=utf8;





insert into dept (dpname, dbsource) values ('Development Department'.DATABASE());

insert into dept (dpname, dbsource) values ('Personnel Department'.DATABASE());

insert into dept (dpname, dbsource) values ('Finance Department'.DATABASE());

insert into dept (dpname, dbsource) values ('Marketing Department'.DATABASE());

insert into dept (dpname, dbsource) values ('Logistics'.DATABASE());

Copy the code

With the database set up, create two new service providers and copy the SpringCloud-provider-dept-8001 project. Change the names to springCloud-provider-dept-8002 and SpringCloud-provider-dept-8003, and modify the configuration file, entry class, and mapper mapping file in the project.

Each service provider is connected to a database as shown in the following example:

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 configuration

eureka:

  client:

    service-url:

      defaultZone: http://eureka7001:7001/eureka/,http://eureka7002:7002/eureka/,http://eureka7003:7003/eureka/

  instance:

Instance-id: springCloud-provider-dept-8002 # Change the default description on eureka

Prefer-ip-address: true # true, the IP address of the service can be displayed



# info configuration

info:

  app.name: hresh-springcloud

  company.name: blog.csdn.net/Herishwater

Copy the code

The current project structure is as follows:

Start three registries, three service providers, and finally service consumers by visiting http://eureka7001:7001/. The page reads as follows:

And then visit http://localhost/consumer/dept/list, and constantly refresh the page, you can see the query to the data in the change.

Load Balancing Policy

Common load balancing policies in the Ribbon

// RoundRobinRule Round poll, default policy, obtain provider in sequence

/ / RandomRule random

/ / AvailabilityFilteringRule: availability of sensitive strategy, can filter out first, trip, visiting breakdown service, for the rest of the polling ~

// RetryRule: The system obtains services ~ based on polling. If obtaining services fails, the system tries again within a specified time

/ / WeightedResponseTimeRule weight polling strategy, according to the response time distribution of a weight of each Provider, the smaller the longer response time of the weight, the lower the likelihood of selected, will use polling strategy for the first time, until the good weight distribution

//BestAvailableRule minimum number of concurrent requests. Select the provider that has a low number of concurrent requests, unless the provider is in a circuit breaker

Copy the code

If you want to change the load balancing policy, in this example, you need to modify the MyConfig configuration file in the service consumer project as follows:

    @Bean

    public IRule getRule(a){

        return new RandomRule();

    }

Copy the code

Added an injection of the RandomRule class so the Ribbon prioritizes randomization.

The Ribbon customizes load balancing policies

In actual production, we may need to design a specific load balancing strategy based on the actual needs of the company. Next, we will design the relevant code.

Create a new folder with the following structure:

Customize MyRandomRule class by modifying the class that mimics random policy

public class MyRandomRule extends AbstractLoadBalancerRule {



    private int count = 0;  // Number of executions per service

    private int providerNum = 0;    // Which service is currently being executed



    public MyRandomRule(a){



    }



    @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(); // Get live service

                List<Server> allList = lb.getAllServers(); // Get all the services

                int serverCount = allList.size();

                if (serverCount == 0) {

                    return null;

                }



                // Core part

// int index = this.chooseRandomInt(serverCount);

// server = (Server)upList.get(index);

                // We define our own execution strategy. Currently we have three providers, so we decide to execute each provider three times, and then execute the next 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) {

    }

}

Copy the code

RuleConfig

@Configuration

public class RuleConfig {



    @Bean

    public IRule getRule(a){

        return new MyRandomRule();

    }

}

Copy the code

Finally, start the policy by adding annotations to the entry class.

@SpringBootApplication

@EnableEurekaClient

Load our custom load balancing policy at microservice startup

@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = RuleConfig.class)

public class DeptConsumer_80 {



    public static void main(String[] args) {

        SpringApplication.run(DeptConsumer_80.class,args);

    }

}

Copy the code

The reason for the location of the myRule folder above is that RuleConfig cannot be in the @ComponentScan of the main application context, otherwise it will be shared by all @RibbonClients. If you use @ComponentScan (or @SpringBootApplication), you need to take steps to avoid inclusion (such as putting it in a separate, non-overlapping package, or specifying it to be at @ComponentScan).

Feign

Spring Cloud Feign is a web service client based on the Implementation of Spring Cloud Ribbon and Spring Cloud Hystrix, which integrates spring Cloud Ribbon and Spring Cloud Hystrix. Similar to controller calling service. SpringCloud integrates Ribbon and Eureka to provide a load-balancing HTTP client when using Feign.

What can Feign do

When we looked at the Ribbon’s use in the last section, we used its request interception for RestTemplate to implement interface calls to dependent services. RestTemplate already encapsulates HTTP requests and forms a set of templated invocation methods. But in actual development, due to the dependence on the service call may be more than one place, often more than one interface will be invoked, so we need for each micro service to encapsulate some client class to wrap these rely on the service invocation, modular code is repeated in each client code quantity will be big.

For example, in the SpringCloud-consumer-Dept-80 project we used in the previous example, the DeptConsumerController class encapsulates the processing of HTTP requests. If we create a new service consumer, To also handle the logic of the DEPT object, you need to copy the DeptConsumerController code.

Spring Cloud Feign further encapsulates this to help define and implement the definition of dependent service interfaces. With the implementation of Spring Cloud Feign, we only need to create an interface and call annotations to configure it to complete the interface binding for service providers, simplifying the development of automatic encapsulation of service invocation clients using Spring Cloud Ribbon.

implementation

First we need to add an interface class that implements Feign to the Spring Cloud-API project.

1. Import dependencies

<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>

Copy the code

2. Add a Service interface class

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(a);

}

Copy the code

Create a Maven project named SpringCloud-consumer-dept-80-feign using the springCloud-consumer-dept-80 project.

1. Import dependencies

<dependencies>

    <dependency>

        <groupId>com.msdn</groupId>

        <artifactId>springcloud-api</artifactId>

        <version>1.0 the 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>

Copy the code

2. DeptConsumerController file

@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(a) {

        return service.queryAll();

    }



    @RequestMapping(name = "/consumer/dept/add")

    public boolean addDept(Dept dept) {

        return service.addDept(dept);

    }



}

Copy the code

3. Add the EnableFeignClients annotation to the entry class

@SpringBootApplication

@EnableEurekaClient

@EnableFeignClients

public class FeignDeptConsumer_80 {



    public static void main(String[] args) {

        SpringApplication.run(FeignDeptConsumer_80.class,args);

    }



Copy the code

4, launched three registry, 3 service providers, and then start a new service consumers, visit http://localhost/consumer/dept/list to refresh the page many times, found that consumer call order is sequential execution, namely the polling strategy.

Details about the code to access: https://github.com/Acorn2/springcloud-eureka, if there is any doubt can contact me.

reference

In-depth understanding of load balancing

What is load balancing?

Interviewer: Tell me about the types of load balancing you know

Spring Cloud Feign Learning 1: Quick Start

Spring-cloud-ribbon Learning Notes (I) : Getting started

Spring-Cloud-Eureka- Study Notes

SpringCloud Learning 1- Service Registration and Discovery (Eureka)