Developing MicroServices using Spring Cloud Netflix API
Hi, I am Malathi Boggavarapu working at Volvo Group and i live in Gothenburg, Sweden. I have been working on Java since several years and had vast experience and knowledge across various technologies.
Before we begin let's get little bit more familiar with what Spring cloud is. I think you have already heard about "The Cloud" and is often hyped as Game changer and Magical solution for everything which solve all the problems. Now-a-days companies and enterprises have finally started to truely embrace the Cloud. And some of that hype is becoming a reality and its more often the norm to see enterprises and companies using the Cloud.
Cloud computing is really changing the way we build the software. We are moving from using Centralized Monolith to applications which are distributed and use MicroServices. Not only the Software is changing but also the Hardware. We are moving from Finite resources to infinite and on-demand and self-service resource.
We also can't just move our existing application to the Cloud and make them Cloud-enabled automatically. We may get some benefits when we move our application to the Cloud but we can not fully utilize the Cloud. Inorder to fully utilize the Cloud, it requires a change. And that's where Spring Cloud helps. Spring Cloud helps to build Cloud native applications.
So how we define a Cloud native application?
Cloud native applications means that your application is specifically built and engineered for the Cloud. It means your application fully utilize all of the Cloud computing paradigms.
Spring Cloud itself is not a framework. It is used to describe the number of projects such as Spring Cloud config, Spring Cloud Cluster , Spring Cloud consul, Spring Cloud Stream and many more which all comes under the same umbrella.
In this course we focus on Fundamentals which is Spring Cloud config and Spring Cloud Netflix.
Prerequisites
- Java8 - Good understanding of Java and particularly Java 8
- Spring Boot. Good understanding of Spring Boot because Spring Cloud is built on top of Spring Boot. Those who does not have knowledge about Spring Boot, you can follow one of my course 'How to build Spring Boot application from scratch'
- MicroServices. Atleast you should know what MicroServices are and also about its terminology You can follow my posts on MicroServices before taking up this course.
Now let's get started with the theoritical concepts first and later we go through demo applications where we built Service Discovery Server, Services and Application Client. We will go through them one after the other.
Once the application has finished loading, go ahead and expand the Console window. You will notice several exceptions there. What happens is that the Discovery server is starting up and its trying to register itself with peer Service Discovery. This is mainly for high availability purposes. When we are running in standalone or development mode, it is difficult to setup multiple instances of Discovery Server. So instead we are going to configure Eureka server not to configure itself with the peers. And you definitly only want to do this in development mode since you want that high availability in production.
Now go to application.properties in src/main/resources and add the following.
spring.application.name=discovery-server
eureka.client.register-with-eureka=false (Since this application itself is Discovery server
and we are running in standalone mode, we don't need to register with any other peers because there aren't any other peers. So make sure you set the value to false)
eureka.client.fetch-registry=false (This property controls whether or not the Eureka client would fetch the registry from the eureka server. And this itself is Eureka server, there is nothing to fetch from anybody else. So we will set this to false.)
server.port=8761 (The default port for Eureka Discovery server)
So now again run the DiscoverServerApplication.java as 'Spring Boot App' as said above. When the application is started, go and look in the console and it says 'Started Eureka Server'.
So now we have a running Service Discovery Server
Before we begin let's get little bit more familiar with what Spring cloud is. I think you have already heard about "The Cloud" and is often hyped as Game changer and Magical solution for everything which solve all the problems. Now-a-days companies and enterprises have finally started to truely embrace the Cloud. And some of that hype is becoming a reality and its more often the norm to see enterprises and companies using the Cloud.
Cloud computing is really changing the way we build the software. We are moving from using Centralized Monolith to applications which are distributed and use MicroServices. Not only the Software is changing but also the Hardware. We are moving from Finite resources to infinite and on-demand and self-service resource.
New challenges
New challenges arise with Cloud. We have to think differently. We can't just design and architect and use the same principles or techniques that we are used to do earlier. Cloud is elastic, resources such as for example Databases, Servers and disks can grow and shrink, appear and disappear at any given time. So we have to consider that Cloud is ever changing and constantly evolving thing.We also can't just move our existing application to the Cloud and make them Cloud-enabled automatically. We may get some benefits when we move our application to the Cloud but we can not fully utilize the Cloud. Inorder to fully utilize the Cloud, it requires a change. And that's where Spring Cloud helps. Spring Cloud helps to build Cloud native applications.
So how we define a Cloud native application?
Cloud native applications means that your application is specifically built and engineered for the Cloud. It means your application fully utilize all of the Cloud computing paradigms.
Spring Cloud itself is not a framework. It is used to describe the number of projects such as Spring Cloud config, Spring Cloud Cluster , Spring Cloud consul, Spring Cloud Stream and many more which all comes under the same umbrella.
In this course we focus on Fundamentals which is Spring Cloud config and Spring Cloud Netflix.
Prerequisites
- Java8 - Good understanding of Java and particularly Java 8
- Spring Boot. Good understanding of Spring Boot because Spring Cloud is built on top of Spring Boot. Those who does not have knowledge about Spring Boot, you can follow one of my course 'How to build Spring Boot application from scratch'
- MicroServices. Atleast you should know what MicroServices are and also about its terminology You can follow my posts on MicroServices before taking up this course.
Now let's get started with the theoritical concepts first and later we go through demo applications where we built Service Discovery Server, Services and Application Client. We will go through them one after the other.
Service Discovery
Remember that the cloud is changing the way we build software. We are moving from building the single large applications and breaking them into smaller and smaller Services and each of the services can be independantly deployed on their own servers and scaled on their own and together as a whole they form the overall application.
So here comes the problem. How does one Service know where another service is located, its host and its port so that other services can call and use it.?
One simple approach is that we can simply configure all services to know the location and port of other services but there are some problems with this approach. For example if we have two Services A and B. We have one instance of A and two instances of B running on the Servers and Service A want to call Service B. If we use configuration, everytime we add and remove the instance of Application Service B we need to update that configuration. Imagine if you have 100 instances instead of just 2 then configuration management alone is unsustainable.
Our simple configuration start to break down further as we move to Cloud environment. In Cloud environment we have instances of Services that can come and go according to the demand.
For example, Application Services B starts with two instances. If there is huge traffic for your application for example an E-commerce application which might have huge traffic during Christmas or New year events, an automated process kicksoff and start two more instances to handle all of that demand. If you are using simple configuration, Application Service A will not even know about the two new instances of Application Service B which were added in response to the demand because of the huge traffic. It only know only the two instances of Application Service B according to the Configuration.
Another thing to consider is, Application Services will eventually fail because of some memory problems or Hardware, Software problems. So if we use simple configuration, Services will continue sending the traffic to the failed instances.
For example, we know that we have two instances running for Application Service B and Service A calling Service B. Assume that if one of the instance of Service B fail. Application Service A does not know about it and it continue sending the request to that failed instance.
So we need to have something which is dynamic. That's where Service Discovery comes in.
It provides the following functionalities
- Allows a Service to register itself. So when the Service comes online, it can call out the Service Discovery server and know about its location and port so that other Services can call it.
- Also provides the way for the Service to de-register itself. So if the Service wants to be temporarily shutdown for upgrades, it can let the Service Discovery server know that it is not available for other Services to use.
- Provides a way for Client to find other Services. Client here refers to a Service. So if a Service wants to find other Services, it can ask Service Discovery Server the location and port of other Services inorder to make a request.
- Provides the way to check the health of the Service and remove unhealthy instances. So each Application Service will implement a health check typically via a REST endpoint and Service Discovery server will call that endpoint and if the health check of the Service fails, it just removes the instance.
Discovering Services with Spring Cloud
There are different ways to discover the Services using Spring Cloud. We have Spring Cloud ZooKeeper, Spring Cloud Consul and Spring Cloud Netflix projects to do that. But we are going to focus on Spring Cloud Netflix project. Spring Cloud project took the Netflix open source project and added some Spring and Spring Boot features and finally brought Spring Cloud Netflix project.
Spring Cloud Netflix project is the collection of projects such as Spring Cloud Netflix Eureka Server and Spring Cloud Netflix Eureka Client
Components of Service Discovery
There are 3 components involved in Service Discovery. They are the Discovery Server, Application Service and the Application Client. We will now discuss how these components gather and interact with each other.
First thing that happens is the Application Service starts up and when it startsup it calls out the Discovery server and register itself. It tells the Discovery server, it's location and it's port and a Service identifier where others can use to find it.
At some point of time the Client wants to call the Service but it does not know the location and port of Service in order to make a call. Then it need to ask Discovery Server. It sends out a request to Discovery Server and sends along the Service Identifier. Based on the Service Identifier the Discovery Server knows which Client request the Service and the Service sends the response back.
Now that we learnt how the key components interact with each other. Now we will dig further into the Discovery Server.
Discovery Server
Discovery Server is an actively managed registry of Service locations. It is responsible for allowing others to find services and for services to register and de-register themselves. The most important thing is we should manage multiple instances of Discovery Server because it is the key component to locate all the other services. If you can not locate other services, you can not call the Services.
Setting up a Discovery Server
Now we will see how to create Discovery Server and starting it up using the Spring Cloud Eureka Server project. Go to start.spring.io and use Spring Initializr to create a stub for the project.
Fill in the fields of Group and Artifact of your choice and search for the dependencies Eureka Server, Devtools, Spring Boot Actuator and add them. Next click on Generate Project. After you click it, it will automatically download a ZIP file for you and this contains the stub of your project. Unzip the downloaded ZIP file and open the IDE and import it. Please Note - Use Spring tool suite (STS) so that it is easy to practise this course. STS is specifically designed for developing Spring applications. Try it!! It is really good.
See the below picture.
After you import the project into IDE, you will find DiscoveryServerApplication inside src/main/java folder. This is where we are going to add annotation to enable our Discovery server. So go ahead and add the annotation @EnableEurekaServer at the class level. That's all. We are now ready to start our Discovery Server. So go ahead and right click on the DiscoveryServerApplication -> Run as -> Spring Boot App
Once the application has finished loading, go ahead and expand the Console window. You will notice several exceptions there. What happens is that the Discovery server is starting up and its trying to register itself with peer Service Discovery. This is mainly for high availability purposes. When we are running in standalone or development mode, it is difficult to setup multiple instances of Discovery Server. So instead we are going to configure Eureka server not to configure itself with the peers. And you definitly only want to do this in development mode since you want that high availability in production.
Now go to application.properties in src/main/resources and add the following.
spring.application.name=discovery-server
eureka.client.register-with-eureka=false (Since this application itself is Discovery server
and we are running in standalone mode, we don't need to register with any other peers because there aren't any other peers. So make sure you set the value to false)
eureka.client.fetch-registry=false (This property controls whether or not the Eureka client would fetch the registry from the eureka server. And this itself is Eureka server, there is nothing to fetch from anybody else. So we will set this to false.)
server.port=8761 (The default port for Eureka Discovery server)
So now again run the DiscoverServerApplication.java as 'Spring Boot App' as said above. When the application is started, go and look in the console and it says 'Started Eureka Server'.
So now we have a running Service Discovery Server
Application Service
Now let's create an application for Service. Generate the stub for the Service in http://start.spring.io/ (in the same way that we did for Discovery Server). But there is some slight change in chosing the dependencies here. You should choose Eureka Discovery instead of Eureka Server and other dependencies should be the same. So finally we are going to choose Eureka Discovery, DevTools and Actuator as dependencies.
After the stub is generated, go ahead and import the project into the IDE. Expand the project structure and inside src/main/java, you will find main application class called ServiceApplication.java. In this class we add an annotation @EnableDiscoveryClient. This will turn Service application as a client of the Discovery Server and it cause to register in Discovery Server when it startsup. See the below picture.
And the plan is to start multiple instances of ServiceApplication. So add the following property in ServiceApplication class (just before main method)
@Value("${service.instance.name}")
private String instance;
Also annotate the class with @RestController to make the class accept the requests. We should actually create different class and annotate it with @RestController but for time being i am keeping it short and simple. But this is not the best practice to follow. We should always create a separate RestController class to do that.
Create a method called message() and add it to the class. See below. It accepts the request with request mapping ('/')
Create a method called message() and add it to the class. See below. It accepts the request with request mapping ('/')
@RequestMapping("/")
public String message(){
return "Hello from " +instance;
}
Now go to src/main/resources and open application.properties and add the following properties to it.
spring.application.name=service
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
The last property is actually the location of Service Discovery server which is located at localhost and at port 8761.
Since we are going to run more than one instance of our ServiceApplication, we have to setup some Run configuration so that each instance run on different port and has a different instance name. Right click on ServiceApplication class and go to Run As -> Run configurations. Select Spring Boot App and click on New. For instance 1 of Service application, set the properties such as server.port to 8081 and service.instance.name to instance 1. Similarly create one more configuration and add server.port to 8082 and service.instance.name to instance 2. See the below picture. Save the configurations.
Before we start instances we need to start Discovery Server so that instances of ServiceApplication will register themselves in the Discovery Server. So go ahead and run DiscoveryServerApplication as Spring Boot App. After it is started, go to the Run configurations of ServiceApplication and run both the instances. Hope you understand. Try it and comment down if you have any questions.
Now we have started the DiscoveryServer and also both the instances of ServiceApplication. And ofcourse both the instances should also be registered in DiscoveryServer. Go ahead and check the logs so that you will understand what's happening.
The last property is actually the location of Service Discovery server which is located at localhost and at port 8761.
Since we are going to run more than one instance of our ServiceApplication, we have to setup some Run configuration so that each instance run on different port and has a different instance name. Right click on ServiceApplication class and go to Run As -> Run configurations. Select Spring Boot App and click on New. For instance 1 of Service application, set the properties such as server.port to 8081 and service.instance.name to instance 1. Similarly create one more configuration and add server.port to 8082 and service.instance.name to instance 2. See the below picture. Save the configurations.
Before we start instances we need to start Discovery Server so that instances of ServiceApplication will register themselves in the Discovery Server. So go ahead and run DiscoveryServerApplication as Spring Boot App. After it is started, go to the Run configurations of ServiceApplication and run both the instances. Hope you understand. Try it and comment down if you have any questions.
Now we have started the DiscoveryServer and also both the instances of ServiceApplication. And ofcourse both the instances should also be registered in DiscoveryServer. Go ahead and check the logs so that you will understand what's happening.
Application Client
Let's continue with the components involved in our Service Discovery. Now we are going to discuss about the Application Client. Application Client is the client which would call out other Services to implement some functionalities in it's service. It depends on another services and issues the requests to them. Similar to Application Service, Application Client is also the user of Service Discovery but uses the Service Discovery in other way. It doesn't use it to register or deregister anything but uses it to find other service locations. It is perfectly OK for an application to be both as Service and a Client. An Application can be a service which provide services to others and at the same time can be a client which depends on other Services. What we are referring here is the Application which acts as a Client but not a Service.
Inorder to create our client we have to again go to start.spring.io, fill in Group and Artifact Id and add the required dependencies. We add exact same dependencies that we used in Application Service. So add Eureka Discovery, DevTools, Actuator dependencies and click on Generate button. ZIP file will be downloaded and unzip the file and import into the IDE.
Expand the project structure and go to src/main/java and open the class called ClientApplication.java. See the below picture.
Add annotations @EnableDiscoveryClient and @RestController to the class and also add @EurekaClient and autowire it.
@EnableDiscoveryClient
@SpringBootApplication
@RestController
public class ClientApplication{
@AutoWired
private EurekaClient client;
@AutoWired
private RestTemplateBuilder builder;
public static void main(String args[]){
SpringApplication.run(ClientApplication.class, args);
}
@RequestMapping("/")
public String callService(){
RestTemplate restTemplate = builder.build();
InstanceInfo instanceInfo = client.getNextServerFromEureka("service", false);
String baseUrl = instanceInfo.getHomePageUrl();
ResponseEntity<String> response = restTemplate.exchange(baseUrl, HttpMethod.GET, null, Stirng.class);
return response.getBody();
}
}
So in the above code, the EurekaClient is calling out the DiscoveryServer and getting information about Service ID called service and InstanceInfo is returned back. From InstanceInfo we are getting home page url which is base Url for our Service and we are using RestTemplate to call that service and we are returning the response body.
So now we go to src/main/resources and open application.properties. Add the following properties
spring.application.name=client
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
eureka.client.register-with-eureka=false
Using the property eureka.client.service-url.defaultZone, we are configuring the Discovery Server inorder to find other Services. The last property says that the Application Client no need to register to Discovery Server because it does not need any other Service to discover it as our Application Client only consume other Services to implement it's functionalities.
Now before we start our Application client, we need to start the Discovery Server and each of the Application Service instances. After they were started, go to the ClientApplication class and Run it as Spring Boot App. Now go to the web browser and access http://localhost:8080 and you should see the following response
Hello from instance 1
And if you refresh it, it might say Hello from instance 2. And if we continue to do that over and over again, and each time we can see that it is getting instance form Eureka registry.
Spring Cloud Eureka Dashboard
One of the useful things that Spring Cloud Eureka Server provides is a Dashboard. It is enabled by default and it is web based dashboard. It displays the bunch of useful information like whether the Service is Up or Down, number of instanes that are registered.
Go to the browser and access url localhost:8761. It shows the Spring Eureka dashboard. Just go around different data available there. You will get to know how Dahsboard looks like.
Health and High availability
Ths Spring Cloud Eureka Server has some additional features about Health and high availability. Its constantly ensure that the Application Services that it is returning back to client are healthy and available. It also ensure that when the Discovery Server is down, all the clients still can operate with out interruption. Eureka Server assess the health of the Services by sending the HeartyBeat every 30 seconds. If it does not get any response from Services after 90 seconds, it will be removed from the regsitry. Sending HearBeat is the default configuration but you can also configure Eureka Server to hit an endpoint such as /health endpoint which comes with Spring Boot Actuator.
Eureka was built with high availability in mind and one of the ways it acheives is that when the Client request the Service location from Discovery Server, Discovery Server actually sends back the copy of the registry. What happens here is the registry gets distributed across all the clients. If the Service discovery server goes down, those clients can continue to operate. If the Discovery Server has new information about the Services, the client should fetch a new registry so often. It does not fetch the full registry again but only the changes that were done in the Service Discovery Server.
We have reached the END of this module. We started with knowing about Service Discovery and its importance. We learnt about how to use Spring Cloud Eureka Client to discover services and Spring Cloud Eureka Server to store a registry of services so that others can discover them. And we also talked about Spring Cloud Eureka Dashboard and also about Health and availability of Services
Please post your comments about this course which are very useful to improve and develop my blog.
And also please post your questions if you have any.
NOTE:
I created a SpringCloud repository in GitHub and uploaded the exercise files. You can pull them and try it on your own.
Clone my below GitHub project to your local machine and try out the exercise files.
NOTE:
I created a SpringCloud repository in GitHub and uploaded the exercise files. You can pull them and try it on your own.
Clone my below GitHub project to your local machine and try out the exercise files.
/SpringCloud
Happy Learning!!
ReplyDeleteThis is an amazing blog, thank you so much for sharing such valuable information with us.
Microservices Online Training
Microservices Training in Hyderabad