When there are multiple service provider microservices in a system, how should the service consumer choose which provider to access? Spring Cloud provides the Ribbon for client load balancing. In this article, we will take a look at how to use the Ribbon to achieve load balancing.

Load balancing is divided into client load balancing and server load balancing. Client load balancing means that the client selects specific microservices for access, while server load balancing means that the middleware intercepts client requests and forwards them to the corresponding microservices. The Ribbon provides load balancing on the client side, so we need to install load balancing on the consumer side.

1. The Ribbon configuration

1.1 Configuring the Ribbon on the Consumer end

Find our service provider: Springcloud-Product-Consumer-8200

1.1.1 modified pom. XML
 <! --ribbon -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>
Copy the code
1.1.2 Adding Annotations

We configure the restTemplate with the @loadBalanced annotation

package com.elio.springcloud.config;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestConfig {

    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(a){
        return newRestTemplate(); }}Copy the code
1.1.3 Configuring load Balancing Rules

Add MyRule configuration class, be careful not to build in the same level of directory as the main boot, otherwise there will be problems.

package rule;

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

@Configuration
public class MyRule {

    @Bean
    public IRule getLoadBalancedRule(a){
        return  newRoundRobinRule(); }}Copy the code

1.2 Added apis for accessing service information

Currently the service consumer and service provider apis do not clearly show which microservice we are accessing, so we need to add an API that queries the current access microservice information

1.2.1 Service Provider 8100

We found the new geServieInfo method on the controller of the service provider 8100

package com.elio.springcloud.controller;

import com.elio.springcloud.dto.Result;
import com.elio.springcloud.entity.Product;
import com.elio.springcloud.service.ProductService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

@RestController
@Slf4j
@RequestMapping("/")
public class ProductProviderController {

    @Resource
    private ProductService productService;

    @Value("${spring.application.name}")
    private String instantName;

    @Value("${server.port}")
    private String port;

    @GetMapping("product/provider/get/info")
    public Result geServieInfo(a){
        return new Result(200."Query succeeded".Current service name:+instantName + Current port:+port);
    }

    /** * Query *@param id
     * @return* /
    @GetMapping("product/provider/get/{id}")
    public Result selectById(@PathVariable("id") Long id){
        return new Result(200."Query succeeded", productService.selectById(id));
    }

    /** * Delete *@param id
     * @return* /
    @GetMapping("product/provider/delete/{id}")
    public Result deleteById(@PathVariable("id") Long id){
        return new Result(200."Deletion successful", productService.deleteById(id));
    }

    /** * Modify *@param product
     * @return* /
    @PostMapping("product/provider/update")
    public Result updateById(@RequestBody Product product){
        return new Result(200."Modification succeeded", productService.updateById(product.getId(), product.getName()));

    }

    /** * Add *@return* /
    @PutMapping( "product/provider/add")
    public Result insertById(@RequestBody Product product){
        return new Result(200."Modification succeeded", productService.insertOne(product)); }}Copy the code
1.2.2 Service consumer 8200

Go to the service consumer project, modify the Controller, add the geServieInfo method, and take care to replace the address we wrote dead with the service provider microservice name

package com.elio.springcloud.controller;

import com.elio.springcloud.dto.Result;
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;

@RestController
public class ProductConsumerController {

    @Resource
    RestTemplate restTemplate;

    //public static String url = "http://localhost:8100/";
    public static String url = "http://springcloud-product-provider/";

    /** * Query *@return* /
    @GetMapping("product/consumer/get/info")
    public Result selectById(a){
        return new Result(200."Query succeeded",
                restTemplate.getForObject(url+"product/provider/get/info", Result.class));
    }

    /** * Query *@param id
     * @return* /
    @GetMapping("product/consumer/get/{id}")
    public Result selectById(@PathVariable("id") Long id){

        return new Result(200."Query succeeded",
                restTemplate.getForObject(url+"product/provider/get/"+id, Result.class)); }}Copy the code

1.3 A Service Provider starts multiple Instances

In the previous two articles, we configured multiple instances by adding subprojects, which is a no-brainer and cumbersome approach, so here’s the second approach. Use idea startup configuration to set up a micro server to start on different ports.

Select the service provider project and click the copy button in the upper left corner

The following figure shows the configuration name after replication. Let’s change the name to ProductProvider8103

In VM Options, add the parameter -dserver.port =8103 to indicate that the instance will run on 8103.

After clicking OK, pull down the Run button to see the ProductProvider8103 configuration, and click the debug button on the right to start the service provider on port 8103.

The last thing we need to notice is that the instance name of the service provider must be different, otherwise only one can be registered successfully, because the port is different, so the instance name is different, and the service name is the same.

eureka:
  instance:
    instance-id: ${spring.application.name}:${server.port}
Copy the code

Then start service registry 8300, service provider 8100,8101,8103, service consumer 8200, and then Eureka service center will have three instances of service provider.

1.4 test

Pay attention to the two points I raised during the configuration process, otherwise either registration will fail or load balancing will not be achieved. Next is the test load balancing, API access to consumers, http://localhost:8200/product/consumer/get/info, and then refresh a few times more, found in the order 8100810, 1810, 3 access service provider

2. To summarize

This article provides a simple example of how to configure the Ribbon for client load balancing in a Spring Cloud project. The working principles and workflow are not covered. In the previous article, we raised two issues, which we have addressed in this article, one is to solve the problem of dead service addresses, and the other is to implement load balancing. However, there is still a problem in the existing project, that is, when we access the interface of the service provider, we need to indicate the specific address in the method. If the interface is accessed by multiple places and needs to be modified, it needs to be modified several times. This problem will be solved in the next article.