Spring Cloud Netflix components Eureka and Ribbon are used to build single-registry load balancing services.

Spring Cloud is a spring-based microservices stack, which contains many components such as service discovery registration, configuration center, message bus, load balancing, circuit breakers, data monitoring, etc., which can be integrated and used by Spring Boot.

Currently, there is a requirement in the project that Spring Boot do a Web service and then call the TensorFlow model to get the result. However, due to the GPU version of TensorFlow does not support multi-threading and multi-engine scheduling, only multi-process scheduling can be adopted, so a load balancing is required. Load balancing can be divided into client and server load balancing. I haven’t realized the difference yet. After all, the overall architecture is the same, as shown below. Spring Cloud Ribbon is the representative of client load balancing and Nginx is the representative of server load balancing.

Since the project was not under much pressure, averaging around 5000 requests per day, components in the Spring Cloud were used for client load balancing. The main uses are Spring Cloud and Eureka. The Ribbon also appears in many blogs. In fact, they are all components in Spring Cloud Netflix to build microservices. The example described in this article can also be viewed as a microservice, where an algorithmic service is split into several smaller services. The various components of Spring Cloud mentioned earlier are also designed to make these independent services more manageable and collaborative.

Back to load balancing, a client load balancing service built using Spring Boot actually requires only one component, Rureka.

Eureka is an important component of Spring Cloud Netflix for service registration and discovery. Eureka adopts the C-S design architecture. As shown in the figure below, Eureka Server acts as a registry and serves as the service center, while the remaining services are Clients of Eureka. All services need to be registered with the Eureka Server for unified management and discovery. As the management center, Eureka Server naturally has other functions such as monitoring in addition to registration and discovery services.

Specifically from the perspective of load balancing:

  1. Eureka Server – Provides service registration and discovery
  2. Service Provider – A Service Provider that typically has multiple services involved in scheduling
  3. Service Consumer — The Service Consumer gets the list of registered services from Eureka and is able to consume the Service, which is the direct entry point to the request.

Service building

The following is the main practice of load balancing service construction.

As mentioned above, a complete load balancing service requires at least three services.

1. Registry — Eureka Server

Create a Spring Boot project containing Eureka Server directly through IDEA, importing the desired Dependency directly. These include spring-cloud-dependencies and Spring-cloud-starter-Netflix-Eureka-Server.

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
Copy the code

Add an annotation @enableeurekaserver to the startup class.

@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
    public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); }}Copy the code

Configure Eureka in YML.

server:
  port: 8080
eureka:.
    instance:
    prefer-ip-address: true
  client:
    # indicates whether to register yourself with Eureka Server. Default is true
    register-with-eureka: false
    # indicates whether to obtain registration information from Eureka Server. Default is true
    fetch-registry: false
    service-url:
      This url is used to register all other services
      defaultZone: http://localhost:${server.port}/eureka/
Copy the code

Because the current configuration is a single-node registry, register-with-eureka and fetch-registry are both set to false, so you do not need to register yourself with the service center, and do not need to obtain registration information.

After starting the project, visit: http://localhost:8080/ and you will see a graphical admin interface. Currently, no services are registered.

2. Service Provider — Service Provider

Configure Eureka in YML.

eureka:
  instance:
    prefer-ip-address: true    Register as an IP address
    # change the name from hostname to IP
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    serviceUrl:
      defaultZone: http://localhost:8080/eureka/    # Register with the previous service center
server:
  port: 8084
spring:
  application:
    name: services-provider    # app name
Copy the code

By default, Eureka is registered with the Eureka Server through hostname. Since multi-node configuration may be involved later, hostname may not be as convenient as IP management, so prefer-ip-address is set to true. Register through an IP address and change the instance-id format to:

${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
Copy the code

Note Ip-address is a short line connection.

Then write a simple Web service to test.

@RestController
public class ServicesController {
    @RequestMapping("/")
    public String home(a) {
        return "Hello world"; }}Copy the code

And then run the project.

3. Service consumers

Create a new project like 2 and then configure Eureka:

eureka:
  instance:
    prefer-ip-address: true
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    serviceUrl:
      defaultZone: http://localhost:8080/eureka/
server:
  port: 8085
spring:
  application:
    name: services-consumer
Copy the code

As before, be careful to distinguish between port number and name.

In the startup class, configure the RestTemplate for service distribution for load balancing. This is a basic way to consume a service, and a second Feign is described below.

@SpringBootApplication
public class ServicesConsumerApplication {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(a) {
        return new RestTemplate();
    }
    public static void main(String[] args) { SpringApplication.run(ServicesConsumerApplication.class, args); }}Copy the code

Call in Controller

@RestController
public class ConsumerController {
    // services-provider indicates the application.name of the service provider. Load balancing requires that the names of multiple services be the same
    private final String servicesUrl = "http://services-provider/";
    private final RestTemplate restTemplate;

    public ConsumerController(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @RequestMapping("/")
    public String home(a) {
        returnrestTemplate.getForObject(servicesUrl,String.class); }}Copy the code

Then run the project and you can see that both services have been successfully registered with the registry.

Some of the blogs might say you need to add @enableDiscoveryClient or @enableeurekaclient, but actually, the official documentation says, As long as the Spring-cloud-starter-Netflix-Eureka-client is in the classpath, the application is automatically registered with the Eureka Server.

By having spring-cloud-starter-netflix-eureka-clienton the classpath, your application automatically registers with the Eureka Server. Configuration is required to locate the Eureka server. Cloud. Spring. IO/spring – clou…

Localhost :8085: Hello world If you don’t believe me, you can start two provider services and output different strings to verify that the load balancing is successful.

The 2019-08-13 15:08:18. 14100-689 the INFO [nio - 8085 - exec - 4] C.N.L.D ynamicServerListLoadBalancer: DynamicServerListLoadBalancer for client services-provider initialized: DynamicServerListLoadBalancer: {NFLoadBalancer: name = services provider, the current list of Servers = [192.168.140.1:8084]}Copy the code

Simplified log as above, you can see, annotations of the @ LoadBalanced load balance function is realized through DynamicServerListLoadBalancer, this is a kind of the default load balancing strategy. After obtaining the service list, distribute the service based on the Round Robin policy (service polling starts from 1 to N in sequence).

At this point, the local load balancing service is set up.

Service consumption Feign with Circuit breaker Hystrix

You can skip this section if you’re experiencing it for the first time. This section was added for service integrity. In actual development, Feign is likely to use it more, and more in conjunction with Hystrix.

Feign is also a service consumption method, which is declarative and used more like a local call, and is a member of Spring Cloud Netflix.

Hystrix, in short, is a circuit breaker. If a service fails to be reachable during load balancing, Hystrix can be configured to degrade the service and disconnect the service. This function is not provided by Eureka by default. Therefore, as mentioned earlier, it needs to be added for load balancing integrity, otherwise the Ribbon will still distribute requests to the service in question.

To use them, you first need to add dependencies

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
Copy the code

Add @enableFeignClients to the startup class.

You need to implement the interface when you call it.

@FeignClient(value = "services-provider")
public interface IRestRemote {
    @GetMapping("/")
    String home(a);
}
Copy the code

Finally, inject the interface into the Controller and call it directly.

@RestController
public class ConsumerController {
    private final IRestRemote remote;

    public ConsumerController(IRestRemote remote) {
        this.remote = remote;
    }

    @RequestMapping("/")
    public String home(a) {
        return remote.home();
    }
Copy the code

Compared to RestTemplate, Fegin is easier to use and does not require the construction of parameter requests, and Feign’s Ribbon integration does not require the @loadBalanced annotation to be displayed. Feign can also use Hystrix directly as described below.

Hystrix does a lot more than just a circuit breaker. See other blogs for more details. Here’s how Feign integrated Hystrix’s work.

The following describes the specific scenario. If there are two load balancing services and one of them is down or abnormal, service distribution will still be performed if there is no circuit breaker. If Hystrix is enabled, a FallBack occurs, the default method is followed, and the service is disabled if certain conditions are met.

Add fallback parameter on the basis of @feignClient, and implement degraded service.

@FeignClient(value = "services-provider",fallback = RestRemoteHystrix.class)
public interface IRestRemote {
    @GetMapping("/")
    String home(a);
}
Copy the code
@Component
public class RestRemoteHystrix implements IRestRemote {
    @override
    public String home(a) {
        return "default"; }}Copy the code

Finally, turn on Feign’s Hystrix switch in the configuration file.

feign:
  hystrix:
    enabled: true
Copy the code

The following can be tested, along the previous example, respectively open two services, and output different text, when shut down a service, and then request will be found, allocated to the closed service, will display “default”, after repeated requests, the service is not available, indicating that the circuit breaker configuration is successful! For more information, see References 5-6.

Pay special attention to

1. Configure multiple nodes

If the system is not standalone, you need to modify some fields as follows:

eureka:
  instance:
    prefer-ip-address: true     Register as an IP address
    IP address of the host (also considering the cluster environment, a node may be configured with multiple IP addresses, here can specify the specific IP address)
    ip-address:
    Server. post is an external HTTP communication port on a host. This port is different from server.post.
    This field is the port number configured to map to the extranet
    non-secure-port:
     # change the name from hostname to IP
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
  client:
    serviceUrl:
      Localhost = 'port'
      defaultZone: http://ip:8080/eureka/
server:
  port: 8084
spring:
  application:
    name: services-provider    # app name
Copy the code

2. High availability registry

In this paper, the above is an example of a single registry, which has basically met my current project needs. However, in reading other blogs, it is found that the real microservices architecture, in order to achieve high availability, usually has multiple registries and is formed with each other. So let’s make a quick note here.

3. More complex and customized load balancing rules.

At the moment, simple load balancing is achieved by simply introducing spring Cloud and Eureka dependencies. But look closely DynamicServerListLoadBalancer class position, is under the Ribbon. Although Ribbon dependencies are not explicitly added, they are already included. So what is the Ribbon?

Ribbon is a client-side load balancer that gives you a lot of control over the behavior of HTTP and TCP clients. Feign already uses Ribbon, so, if you use @FeignClient, this section also applies.

The Ribbon is a component of Spring Cloud that provides client load balancing. Do not pay attention to the underlying details, it may not be related to the above services, in fact, still used. If you need to customize complex balanced rules, configure the Ribbon to do so.

Summary

This article is mainly “borrowed” idea, directly using several components in the Spring Cloud to build a load balancing service. In order to better carry out service governance, it is necessary to learn basic principles and concepts step by step, such as CAP theory, and gradually learn components in Cloud to have a certain global view.

The registry Eureka itself satisfies AP, and in a production environment, it is necessary to have at least two registries in order to ensure high availability of services.

Reference

  1. Springcloud (II) : Registry Eureka
  2. Springcloud iii: Service provision and invocation
  3. Spring Cloud Netflix
  4. SpringCloud – load balancer Ribbon
  5. Hystrix (Finchley)
  6. Setup a Circuit Breaker with Hystrix, Feign Client and Spring Boot

Source Code

This article was first written in 2019-09-24 and the information described in this article may have changed. Please use it with caution.