Client-side service discovery allows services to find and communicate with each other without hard coding hostname and port. The only ‘fixed point’ in such an architecture consists of a service registry with which each service has to register.
A drawback is that all clients must implement a certain logic to interact with this fixed point. This assumes an additional network round trip before the actual request.
With Netflix Eureka each client can simultaneously act as a server, to replicate its status to a connected peer. In other words, a client retrieves a list of all connected peers of a service registry and makes all further requests to any other services through a load-balancing algorithm.
To be informed about the presence of a client, they have to send a heartbeat signal to the registry.
To achieve the goal of this write-up, we will implement three microservices:
a service registry (Eureka Server),
a REST service which registers itself at the registry (Eureka Client) and
a web-application, which is consuming the REST service as a registry-aware client (Spring Cloud Netflix Feign Client).
2. Eureka Server
To implement a Eureka Server for using as service registry is as easy as: adding spring-cloud-starter-eureka-server to the dependencies, enable the Eureka Server in a @SpringBootApplication per annotate it with @EnableEurekaServerand configure some properties. But we’ll do it step by step.
Firstly we’ll create a new Maven project and put the dependencies into it. You have to notice that we’re importing the spring-cloud-starter-parent to all projects described in this tutorial:
Finally, we’re configuring the properties in YAML format; so an application.yml will be our configuration file:
Here we’re configuring an application port – 8761 is the default one for Eurekaservers. We are telling the built-in Eureka Client not to register with ‘itself’, because our application should be acting as a server.
Now we will point our browser to http://localhost:8761 to view the Eurekadashboard, where we will later inspecting the registered instances.
At the moment, we see basic indicators such as status and health indicators.
3. Eureka Client
For a @SpringBootApplication to be discovery-aware, we have to include some Spring Discovery Client (for example spring-cloud-starter-eureka)into our classpath.
Then we need to annotate a @Configuration with either @EnableDiscoveryClient or @EnableEurekaClient.
The latter tells Spring Boot to use Spring Netflix Eureka for service discovery explicitly. To fill our client application with some sample-life, we’ll also include the spring-boot-starter-web package in the pom.xml and implement a RESTcontroller.
When we decided to set up our Eureka Client this way, we had in mind that this kind of service should later be easily scalable.
Now we will run the client and point our browser to http://localhost:8761 again, to see its registration status on the Eureka Dashboard. By using the Dashboard, we can do further configuration e.g. link the homepage of a registered client with the Dashboard for administrative purposes. The configuration options, however, are beyond the scope of this article.
4. Feign Client
To finalize our project with three dependent microservices, we will now implement an REST-consuming web application using Spring Netflix Feign Client.
Think of Feign as discovery-aware SpringRestTemplate using interfaces to communicate with endpoints. This interfaces will be automatically implemented at runtime and instead of service-urls, it is using service-names.
Without Feign we would have to autowire an instance of EurekaClient into our controller with which we could receive a service-information by service-name as an Application object.
We would use this Application to get a list of all instances of this service, pick a suitable one and use this InstanceInfo to get hostname and port. With this, we could do a standard request with any http client.
The Feign Client is located in the spring-cloud-starter-feign package. To enable it, we have to annotate a @Configuration with @EnableFeignClients. To use it, we simply annotate an interface with @FeignClient(“service-name”) and auto-wire it into a controller.
A good method to create such FeignClients is to create interfaces with @RequestMapping annotated methods and put them into a separate module. This way they can be shared between server and client. On server-side, you can implement them as @Controller, and on client-side, they can be extended and annotated as @FeignClient.
As we’ve seen, we’re now able to implement a service registry using Spring Netflix Eureka Server and register some Eureka Clients with it.
Because our Eureka Client from step 3 listens on a randomly chosen port, it doesn’t know its location without the information from the registry. With a Feign Client and our registry, we can locate and consume the REST service, even when the location changes.
Finally, we’ve got a big picture about using service discovery in a microservice architecture.