Micronaut  - Discovery Client and Client-side load balancing with Consul

Micronaut - Discovery Client and Client-side load balancing with Consul

Help Superheroes to get discovered

Introduction

In any microservice architecture, we need multiple instances of the services. Our superhero API is no different. While we have been running only one instance of superhero API and command center, it is far from reality.

In the real world, the load on servers is expected to increase. We need to establish efficient communication to talk between services.

Suppose, there is a surge in load, we need to increase the instances of superhero API, how will the command-center know the new instances URLs. How will it call them and balance the load on servers? Till now, we hardcoded it with the @Client annotation and value as URL.

Can we solve this problem if we have another service that can keep track of all the services deployed? If it can know all the instances of any service and can give us the URLs. How good it could be if we distribute the load among all available instances.

In this section we will solve this using Consul Service discovery and client-side load balancing.

Approach

  • Add the discovery dependency to command-center and superhero api.

  • Run consul

  • Update the @Client annotation to use id of the service rather URLs

Add the discovery dependency to command-center and superhero api.

When we add this dependency and let client know that they have to register at consul service discovery, client will sent HTTP request at startup. it keeps sending the request at regular interval to let the consul service discovery app know that its up and running.

superhero API.png

Add the below dependency to the superhero API and command center poms

  <dependency>
            <groupId>io.micronaut.discovery</groupId>
            <artifactId>micronaut-discovery-client</artifactId>
            <scope>compile</scope>
        </dependency>

Once it is added, we will tell apps the address of the consul server so that they can register themselves.

Add the below in superhero and command-center application.yml

consul:
  client:
    registration:
      enabled: true
    defaultZone: "${CONSUL_HOST:localhost}:${CONSUL_PORT:8500}"

This will tell the application about the address of the consul server. At the start of microservices, they will hit the server on this port to let it know about their availability.

Run consul

There are many ways to run consul, let us keep simple with docker, run below docker command to run it

docker run -p 8500:8500 consul

This will sun consul app and expose to 8500 port.

Update the @Client annotation to use id of the service rather URLs

Till now we have used hardcoded @Client value , let us use id rather than URL now. Ids are the same as Micronaut's application name . We will update the declarative client used in the last section with id.

Below is the code


@Client(id = "superHeroes")
@Header(name = "Accept", value = HEADER_ACCEPT)
public interface SuperheroClient {
    @Get("/rx/superheroes")
    Flux<Superhero> superheroes();

    @Get("/rx/superhero/{id}")
    Mono<Superhero> superheroesById(Long id);

    @Post("/rx/superhero")
    Publisher<Superhero> create( @Body  Superhero superhero);

    @Put("/rx/superhero")
    Publisher<Superhero> update( Superhero superhero);

    @Delete("/rx/superhero/{id}")
    Publisher<HttpResponse<Long>> delete(Long id);
}

If you observe we have updated @Client with id of superhero API. Whenever a call to superhero API is made, it can select one of the instances that have registered itself at consul.

Test The Setup

Once it is all done , it's time to test the setup. To do that let us start multiple instance on superhero API. We can start them by directly invoking jar in the target folder and passing micronaut.server.port={PORT_NO} as parameter.

Open two terminals and navingate to project. Change directory to target folder and run the command

 java -jar .\super-heroes-0.1.jar --micronaut.server.port=8082
 java -jar .\super-heroes-0.1.jar --micronaut.server.port=8081

The above commands will start two instances of superhero API at 8081 and 8082 port. You will notice the application will register itself with consul and log it.

Superhero API Registered at consul at port 8081

RegisterATConsul0.PNG

Superhero API Registered at consul at port 8082

RegisterATConsul1.PNG

Start command-center App and Test the sever

Once command-center all is up and you can see it registered to consul, you can verify all of them are at consul UI too. visit http://localhost:8500 where docker is running the consul

consulAppunnig.PNG

If you hit the API via command-center, You can see logs are different console widows of superhero API.

This shows the working load balancing of HttpClient with consul.

Did you find this article valuable?

Support Kumar Pallav by becoming a sponsor. Any amount is appreciated!