Thursday, September 19, 2019

Get your hands dirty with Micro Services- part 2

STEP 3:
Client Side Load Balancing with Ribbon


In Part 1 of this tutorial, we already covered the basic concepts of micro services. As a hands on, we created a sample application(TEST-APP) and applied those concepts and  registered the instances of the application in the service registry.

Anyway micro services are loosely coupled, independent deployable components.  Since each service is responsible to have a small functionality, it might need to involve a lot of services to complete a single transaction. So inter service communication is really important in micro service architecture which is a big challenging topic.



 3.1 Client Side vs Server Side Load Balancing

Refer the my load balancing blog post to get more idea about the client side vs server side load balancing.
Suppose there is a scenario which Service A wants to access the Service B. There are multiple instances in Service B. Anyway, to properly handle the incoming traffic, we can distribute the incoming requests from Service A among the server instances of Service B.

Anyway, there are two different ways to do the load balancing.


Server side load balancing

There is a load balancer in between the Service A and Service B. All the instances are registered in the service registry. Load balancer fetches the available instances of Service B from the service registry and distribute the incoming traffic from Service A.


Client side load balancing



There is no separate server to load balance in between services. Here the service A works as the client and the load balancing handle from their side itself. Service A fetches the available server instances of Service B from service registry and distributes the load among the Service B instances.


3.2 What is the RestTemplate?

RestTemplate is the basic Spring class for simultaneous client side HTTP access. It simplifies the interaction with HTTP servers and enforces RESTful systems.

3.3 Client side load balancing with Ribbon

Let's apply the load balancing to our sample application created in  Part 1. Ribbon is one of the client side load balancer, which facilitate to do the load balancing in micro service architecture.

Create a new spring boot application as mentioned in Part 1. We are going to invoke this new service from our previous TEST-APP service.



Project structure of the new spring boot application(ribbonApp)




Sample Java Code


SalaryController.java

package com.sample.ribon.controller;

import com.sample.ribon.model.Salary;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SalaryController {

    @Autowired
    Environment environment;
    @Autowired
    Salary salary;

    @RequestMapping("/salary")
    public Salary getSalary() {
        System.out.println("hitting get salary operation");
        salary.setId("emp1");
        salary.setMonth("January");
        salary.setAmount(1000);
        return salary;
    }

    @RequestMapping("/portNumber")
    public String getPortNumber() {
        System.out.println("hitting get port number operation");
        String serverPort = environment.getProperty("local.server.port");
        return " Host : localhost " + " :: Port : " + serverPort;
    }
}

Salary.java

package com.sample.ribon.model;

import org.springframework.stereotype.Component;

@Component
public class Salary {
    private String id;
    private int amount;
    private String month;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public int getAmount() {
        return amount;
    }

    public void setAmount(int amount) {
        this.amount = amount;
    }

    public String getMonth() {
        return month;
    }

    public void setMonth(String month) {
        this.month = month;
    }
}

RibonApplication.java

package com.sample.ribon;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class RibonApplication {

 public static void main(String[] args) {
  SpringApplication.run(RibonApplication.class, args);
 }

}

Application.properties

spring.application.name=ribonapp
server.port = 8768
eureka.client.serviceUrl.defaultZone= http://${registry.host:localhost}:${registry.port:8765}/eureka/



pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.1.7.RELEASE</version>
  <relativePath/> <!-- lookup parent from repository -->
 </parent>
 <groupId>com.sample</groupId>
 <artifactId>ribon</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <name>ribon</name>
 <description>Demo project for Spring Boot</description>

 <properties>
  <java.version>1.8</java.version>
  <spring-cloud.version>Greenwich.SR2</spring-cloud.version>
 </properties>

        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </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>

 <build>
  <plugins>
   <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
   </plugin>
  </plugins>
 </build>
</project>



Make the following changes in the existing sample application(TEST-APP) to represent it as a ribbon client.


Project structure




RibbonConfiguration.java

Add a new java class called RibbonConfiguration.java.This class contains the ribbon client configuration for client side load balancing.

package com.test.sample;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;

public class RibbonConfiguration {
    @Autowired
    IClientConfig ribbonClientConfig;

    @Bean
    public IPing ribbonPing(IClientConfig config) {
        return new PingUrl();
    }

    @Bean
    public IRule ribbonRule(IClientConfig config) {
        return new WeightedResponseTimeRule();
    }

}

Do the below changes in the existing files.

pom.xml

Add below highlighted dependency to the pom.xml. This dependency related to the ribbon client.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.1.6.RELEASE</version>
  <relativePath/> <!-- lookup parent from repository -->
 </parent>
 <groupId>com.test</groupId>
 <artifactId>sample</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <name>sample</name>
 <description>Demo project for Spring Boot</description>

 <properties>
  <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR2</spring-cloud.version>
 </properties>
 <dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
  </dependency>
                <dependency>
                        <groupId>org.springframework.cloud</groupId>
                        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
                </dependency>
                <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
                </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>

 <build>
  <plugins>
   <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
   </plugin>
  </plugins>
 </build>

</project>


EmployeeController.java


package com.test.sample.controller;

import com.test.sample.model.Department;
import com.test.sample.model.Employee;
import com.test.sample.model.Salary;
import com.test.sample.service.DepartmentService;
import com.test.sample.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/employee")
public class EmployeeController {

    @Autowired
    EmployeeService employeeService;
    @Autowired
    DepartmentService departmentService;

    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

    @Autowired
    RestTemplate restTemplate;


    @RequestMapping("/personalInfo")
    public Employee getEmployeeDetails() {
        return employeeService.getEmployeePersonalInfo();
    }

    @RequestMapping("/departmentInfo")
    public Department getDepartmentDetails() {
        return departmentService.getDepartmentInfo();
    }

    @RequestMapping("/salaryInfo")
    public Object getsalary() {
        Object salary = this.restTemplate.getForObject("http://ribonapp/salary", Object.class);
        return salary;
    }

    @RequestMapping("/portInfo")
    public String getPortNumber() {
        String randomString = this.restTemplate1.getForObject("http://ribonapp/portNumber", String.class);
        return "Server Response :: " + randomString;
    }


}

We are using rest template to make the http request to the external service. Anyway, it has annotated with @LoadBalanced to use the RibbonLoadBalancerClient to interact with the external services.

Object salary = this.restTemplate.getForObject("http://ribonapp/salary", Salary.class);

spring.application.name=ribonapp

When invoking the services via restTemplate.getForObject(), need to pass the value set in the "spring.application.name" property of the calling service's application.proprerties file as the host name of the url.

SampleApplication.java


package com.test.sample;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.context.annotation.ComponentScan;


@SpringBootApplication
@EnableDiscoveryClient
@ComponentScan(basePackages = "com.test.sample")
@RibbonClient(name="ribbonService",configuration = RibbonConfiguration.class)
public class SampleApplication {

 public static void main(String[] args) {
  SpringApplication.run(SampleApplication.class, args);
 }

}

@RibbonClient annotation is set to make this application as a ribbon client. Here we are passing  a
name and configuration parameters. You can choose any meaningful name. But as configuration, you need to pass the exact ribbon configuration class name which we created before.

Testing

1. Start the Eureka registry instance by right click and press run on the "EurekaApplication.java" class.
2. Start the SampleService(TEST-APP) by right click and press run on the "SampleApplication.java" class.
3. We are going to start the two instances of Ribbon application to check the load balancing functionality.
To start two instances in different ports, first build the project and create a jar file. Run "mvn clean install" from the location of pom.xml file.
4. Once you have built that, you can see the "ribon-0.0.1-SNAPSHOT.jar" created in target directory.
5. Go into that directory and run execute the jar. To start two instances, change the port number and execute.

  • java -jar  -Dserver.port=8768 ribon-0.0.1-SNAPSHOT.jar
  • java -jar  -Dserver.port=8769 ribon-0.0.1-SNAPSHOT.jar



Once you started all the service instances, go and check the service registry. You can see the 3 service instances(1 sample application & 2 ribbon application instances) have registered in Eureka.



Let' invoke the salaryInfo operation. sample application will invoke the ribbon applicaiton and you can get the below response from ribbon application.

But how can we verify the requests to the salaryInfo are distributed among the two ribbon instances. To verify that, let's invoke portInfo operation which is returning the port of the responding server.
Send multiple request and you will see the responses are returned by two servers in round robin manner.







Wednesday, September 4, 2019

Get your hands dirty with Micro Services- part 1


STEP:1

Building a Simple Application with Spring Boot

1.1 Controller-Service-Repository Architecture




  • Controller- Controller layer contains the *application logic, mapping the user request to particular functions and passing the user input to service layer to apply the business logic.
  • Service- This is the layer between the controller and repository which performs the *business logic and validation logic. The controller passes the user input to the service layer and after applying the business logic, it is passed to the repository layer.
  • Repository- The layer which interact with the database CRUD operations via the DAOs(data access objects).
  • Model- Is the simple POJO classes which is acting as the DTO(Interact with application level data transfer) or DAO(Interaction with database operations)    
*Business logic vs application logic - Business logic addresses the logical manipulations relates to the business domain. Simply business logics more specific to the business. 
On the other hand the application logics represent the application level operations, which is not specific to the business domain but a function of the application itself. Ex: Press the button and pop up the login form is an example of the application logic. Validating the user login data is the domain specific requirement which comes under business logic.

1.2 Create Spring Projecr Structure

 Go to the https://start.spring.io and there you can configure the spring project structure. In this sample we are using the Java 1.8 as the JRE and maven as the build tool. In addition to that we need to add spring dependencies. For the moment we will add 'spring web starter' dependency. You can add it by just typing the key-word 'web' in the dependencies text box and select the 'spring web starter' dependency from the list. After that press the 'generate the project' button to save the project in your local machine.


After that you can import the project into the IDE(Here I'm using Inte IntelliJ IDEA) and continue your development. As the first change, we need to add the layer structure(controller-model-service-repository) as below.


1.3 Build a Sample Application


I'm going to build the very simple application to expose some APIs. Before going through the sample code, It's worth to get some idea about the usage of the annotations and some important concepts in spring framework.

Spring Annotations used in this application

  • @Controller,@Repository,@Service

In spring framework,we can use the class level annotation @Component to order to create a bean from the class automatically and register in the Spring container to release it on demand.
Ex: 
A bean of the Car class will be registered in the Spring container with the below definition.

@Component
class Car{
}




@Controller, @Repository,@Service annotations are inherited from @Component annotation. All of them are registering beans relevant to the classes which they have annotated with. In addition to that we can clearly differentiate the classes in the layered architecture by those annotation names instead of using the @Component for all. The other important thing is those three annotations have some special features than the @Component annotation. 
Ex:The @Controller annotation is not only registering a controller bean in the container, but also providing the capability of handling the  request mappings(@RequestMapping) received from the clients.

  • @Autowired

The heart of the spring framework is dependency injection. Instead of creating the objects using class constructor with 'new' key word, we are asking the spring container to inject the bean object to the property annotated with @Autowired annotation.


Class Test{
@Autowired
Car BMW;
}

  • @RequestMapping


As I mentioned earlier, the class annotated with @Controller handle the request path mappings. So it can contain multiple request mappings. @RequestMapping is used to define the particular path which the request should be mapped to.

  • @Bean and @Configuration


Instead of using the class level annotation @Component to register bean classes, we can use @Bean method level annotation. But the class should be annotated with @Configuration to indicate this class has the methods for bean definitions.

@Configuration
public class AppConfig {

@Bean
    public Employee employee123() {
return new Employee();
}

}

                • @SpringBootApplication




                This annotation consists of the following three annotations.






                @EnableAutoConfiguration -  It is used to get the default configurations in spring. Spring boot gathers the required component to run the application from the class path and automatically provide those configurations and objects from the dependencies which you already added to the project.(Ex: Once it found the DB driver in the class path, It will automatically add the DB configurations)
                @ComponentScan - This annotation indicates the application to check the components inside the package to find out the beans, services and configuration required to run the application.
                @Configuration -Already described above.

                Concepts of code to interface and dependency injection

                Dependency injection is the concept of getting the support of the third party to inject the dependency required by the classes instead of creating them itself.
                Ex: If class Car needs to invoke the  methods of class Engine, the traditional way is creating the object inside the class Car and invoke the method of class Engine.

                class Car{
                Engine engine=new Engine();
                System.out.println(engine.power());
                }


                Anyway the problem of the above traditional way is if we changed the class name 'Enging' as 'Motor', we need to make that change in each and every class which create the 'engine' object  by referring the Engine class. To overcome that issue we can use the concept of 'code to interface'.
                We can define an interface called 'CarParts' and implement that interface.

                Interface CarParts{
                engine.power();
                }
                
                class Motor implements CarParts{
                int cylinderCapacity=1000;
                public int power(){
                return cylinderCapacity*4;
                }
                }

                With the above interface definition, we can define the reference variable in our 'Car' class by referring the interface as below.

                class Car{
                CarParts engine=new Motor();
                System.out.println(engine.power());
                }


                 But still we have to change the constructor used to create the object from the new Motor class. The only way to overcome this issue is getting the help of third party to create the object and inject the object at run time. In spring, It is done by the spring container with the help of beans. Finally, your Car class appears like below.

                class Car{
                CarParts engine;
                System.out.println(engine.power());
                }

                With the above code, even though we make the changes to the Motor class, no need to touch the other classes which it refers. The dependency objects contains all the changes and inject them at the run time to the Car class.


                Sample Java Code, Run Application and Testings

                The classes and interfaces should be added as below in the project structure.


                Controller

                EmployeeController.java

                package com.test.sample.controller;
                
                import com.test.sample.model.Department;
                import com.test.sample.model.Employee;
                import com.test.sample.service.DepartmentService;
                import com.test.sample.service.EmployeeService;
                import org.springframework.beans.factory.annotation.Autowired;
                import org.springframework.web.bind.annotation.RequestMapping;
                import org.springframework.web.bind.annotation.RestController;
                
                @RestController
                @RequestMapping("/employee")
                public class EmployeeController {
                
                    @Autowired
                    EmployeeService employeeService;
                    @Autowired
                    DepartmentService departmentService;
                
                    @RequestMapping("/personalInfo")
                    public Employee getEmployeeDetails() {
                        return employeeService.getEmployeePersonalInfo();
                    }
                
                    @RequestMapping("/departmentInfo")
                    public Department getDepartmentDetails() {
                        return departmentService.getDepartmentInfo();
                    }
                
                }

                Service

                EmployeeService.java

                package com.test.sample.service;
                
                import com.test.sample.model.Employee;
                
                public interface EmployeeService {
                
                    Employee getEmployeePersonalInfo();
                }

                EmployeeServiceImpl.java

                package com.test.sample.service;
                
                import com.test.sample.model.Employee;
                import com.test.sample.repository.EmployeeRepository;
                import org.springframework.beans.factory.annotation.Autowired;
                import org.springframework.stereotype.Service;
                
                @Service
                public class EmployeeServiceImpl implements EmployeeService {
                
                    @Autowired
                EmployeeRepository employeeRepository;
                
                    @Override
                    public Employee getEmployeePersonalInfo() {
                        return employeeRepository.getEmployeePersonalInfo();
                    }
                }

                DepartmentService.java

                package com.test.sample.service;
                
                import com.test.sample.model.Department;
                
                public interface DepartmentService {
                
                    Department getDepartmentInfo();
                
                }

                DepartmentServiceImpl.java

                package com.test.sample.service;
                
                import com.test.sample.model.Department;
                import com.test.sample.repository.DepartmentRepository;
                import org.springframework.beans.factory.annotation.Autowired;
                import org.springframework.stereotype.Service;
                
                @Service
                public class DepartmentServiceImpl implements DepartmentService {
                
                    @Autowired
                    DepartmentRepository departmentRepository;
                
                    @Override
                    public Department getDepartmentInfo() {
                        return departmentRepository.getDepartmentInfo();
                
                    }
                }

                Repository

                EmployeeRepository.java

                package com.test.sample.repository;
                
                import com.test.sample.model.Employee;
                
                public interface EmployeeRepository {
                
                    Employee getEmployeePersonalInfo();
                }

                EmployeeRepositoryImpl.java

                package com.test.sample.repository;
                
                import com.test.sample.model.Employee;
                import org.springframework.beans.factory.annotation.Autowired;
                import org.springframework.stereotype.Repository;
                
                @Repository
                public class EmployeeRepositoryImpl implements EmployeeRepository {
                
                    @Autowired
                    Employee employee;
                
                    @Override
                    public Employee getEmployeePersonalInfo() {
                        employee.setEmpId(1);
                        employee.setEmpName("Randika");
                        employee.setEmpAddress("Maharagama");
                        return employee;
                    }
                }

                DepartmentRepository.java

                package com.test.sample.repository;
                
                import com.test.sample.model.Department;
                
                public interface DepartmentRepository {
                
                    Department getDepartmentInfo();
                }

                DepartmentRepositoryImpl.java

                package com.test.sample.repository;
                
                import com.test.sample.model.Department;
                import org.springframework.beans.factory.annotation.Autowired;
                import org.springframework.stereotype.Repository;
                
                @Repository
                public class DepartmentRepositoryImpl implements DepartmentRepository {
                
                    @Autowired
                    Department department;
                
                    @Override
                    public Department getDepartmentInfo() {
                
                        department.setDeptId("D12");
                        department.setDeptName("Finance");
                        return department;
                    }
                }

                Model

                To create the beans in following two classes, I have used different method as I mentioned earlier. In the department class, I used class level annotation @Component to create a bean. But in Employee class I'm using method level annotation @Bean with @Configuration annotation which is defined inside the AppConfig.java class.

                Department.java


                package com.test.sample.model;
                
                import org.springframework.stereotype.Component;
                
                @Component
                public class Department {
                
                    private String deptId;
                    private String deptName;
                
                    public String getDeptId() {
                        return deptId;
                    }
                
                    public void setDeptId(String deptId) {
                        this.deptId = deptId;
                    }
                
                    public String getDeptName() {
                        return deptName;
                    }
                
                    public void setDeptName(String deptName) {
                        this.deptName = deptName;
                    }
                }

                Employee.java

                package com.test.sample.model;
                
                public class Employee {
                
                    private int empId;
                    private String empName;
                    private String empAddress;
                
                    public int getEmpId() {
                        return empId;
                    }
                
                    public void setEmpId(int empId) {
                        this.empId = empId;
                    }
                
                    public String getEmpName() {
                        return empName;
                    }
                
                    public void setEmpName(String empName) {
                        this.empName = empName;
                    }
                
                    public String getEmpAddress() {
                        return empAddress;
                    }
                
                    public void setEmpAddress(String empAddress) {
                        this.empAddress = empAddress;
                    }
                }


                Bean Definition

                AppConfig.java

                package com.test.sample;
                
                import com.test.sample.model.Employee;
                import org.springframework.context.annotation.Bean;
                import org.springframework.context.annotation.Configuration;
                
                @Configuration
                public class AppConfig {
                
                    @Bean
                    public Employee employee() {
                        return new Employee();
                    }
                
                }

                Application

                SampleApplication.java

                package com.test.sample;
                
                import org.springframework.boot.SpringApplication;
                import org.springframework.boot.autoconfigure.SpringBootApplication;
                
                @SpringBootApplication
                public class SampleApplication {
                
                 public static void main(String[] args) {
                  SpringApplication.run(SampleApplication.class, args);
                 }
                
                }


                application.properties

                /*Spring boot contains the embeded tomcat server.
                We can define the application running port by below property.*/
                server.port=9090

                Run the application  - right click on the 'SampleApplication.java' and run. If the application started correctly, you can see the following log.


                Test the application - Invoke the following requests via the browser.



                STEP:2

                Registering the Server Instances in Service Registry.

                2.1 What is Service Registry?





                Suppose there are REST APIs deployed in multiple server instances and a client needs to access the service from outside.According to the traditional way, every instance has a static network address which is controlled by the hardware infrastructure and we can configure the load balancer with those static network addresses to redirect the incoming requests among those instances.
                But in cloud based micro service architectures, can't apply these static network addresses, because of there are concepts like auto scaling, failures, upgrades etc...
                In micro service architecture this is done by service registry. Actually, it is a database of network addresses of available instances. Service registry exposes an API to register(POST), update(PUT), delete(DELETE) the network location of server instances.
                Netflix Eureka is a sample for service registry. Eureka client query DNS to discover the network locations of Eureka servers. 

                2.2 Discovery Patterns

                Clients use the following methods to search the service discovery and get the network address of the service instances which it needs to access.

                Client side discovery - Client is responsible to find the network address of the service instance which needs to connect to access the service.



                Server side discovery - Client sends the request to the outside load balancer and load balancer responsible to search the service registry and redirect the request to relevant service instances.



                2.3 Create Eureka Service Registry(Eureka server)

                Create the project structure with https://start.spring.io/. Add the following dependencies when you create the project structure.

                • Spring Web Starter
                • Eureka Server



                After creating the project, import that into your IDE.



                Sample Java Code, Run Application and Testings



                • Configuring Eureka Registry Server

                EurekaApplication.java

                package com.example.eureka;
                
                import org.springframework.boot.SpringApplication;
                import org.springframework.boot.autoconfigure.SpringBootApplication;
                import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
                
                @SpringBootApplication
                @EnableEurekaServer
                public class EurekaApplication {
                
                 public static void main(String[] args) {
                  SpringApplication.run(EurekaApplication.class, args);
                 }
                }

                • @EnableEurekaServer annotation indicates that this spring boot application need to be catered as a registry server

                spring.application.name= Eureka Application
                
                server.port = 8765
                eureka.client.registerWithEureka= false
                eureka.client.fetch-registry=false
                eureka.client.serviceUrl.defaultZone= http://localhost:${server.port}/eureka/


                • eureka.client.registerWithEureka: If we set this property as true then while the server starts the inbuilt client will try to register itself with the Eureka server.
                • eureka.client.fetch-registry: The inbuilt client will try to fetch the Eureka registry if we set this property as true.It's like a response from cache.
                • eureka.client.serviceUrl.defaultZone: Define the host and port which Eureka server is running and the eureka clients need to be fetch the information for register
                Start the Eureka server by running the "EurekaApplication.java". After starting the application, browse the console by 'localhost:8765'.



                • Registering service instance in Eureka(Service Registry)

                You need to add new configuration to the following files to represent our sample application as discovery client and enable the service registration with Eureka registry server.

                pom.xml


                <?xml version="1.0" encoding="UTF-8"?>
                <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
                   <modelVersion>4.0.0</modelVersion>
                   <parent>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-parent</artifactId>
                      <version>2.1.7.RELEASE</version>
                      <relativePath />
                      <!-- lookup parent from repository -->
                   </parent>
                   <groupId>com.test</groupId>
                   <artifactId>sample</artifactId>
                   <version>0.0.1-SNAPSHOT</version>
                   <name>sample</name>
                   <description>Demo project for Spring Boot</description>
                   <properties>
                      <java.version>1.8</java.version>
                      <spring-cloud.version>Greenwich.SR2</spring-cloud.version>
                   </properties>
                   <dependencies>
                      <dependency>
                         <groupId>org.springframework.boot</groupId>
                         <artifactId>spring-boot-starter-web</artifactId>
                      </dependency>
                      <dependency>
                         <groupId>org.springframework.boot</groupId>
                         <artifactId>spring-boot-starter-test</artifactId>
                         <scope>test</scope>
                      </dependency>
                      <dependency>
                         <groupId>org.springframework.cloud</groupId>
                         <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
                      </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>
                   <build>
                      <plugins>
                         <plugin>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-maven-plugin</artifactId>
                         </plugin>
                      </plugins>
                   </build>
                </project>
                

                In the pom.xml, add the above highlighted dependencies related to eureka client configuration.



                application.properties

                server.port=9090
                spring.application.name=Test-app
                eureka.client.serviceUrl.defaultZone= http://localhost:8765/eureka/
                Insert correct eureka.client.serviceUrl.defaultZone to register the application with Eureka server.


                SampleApplication.java

                package com.test.sample;
                
                import org.springframework.boot.SpringApplication;
                import org.springframework.boot.autoconfigure.SpringBootApplication;
                import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
                
                
                @SpringBootApplication
                @EnableDiscoveryClient
                public class SampleApplication {
                
                 public static void main(String[] args) {
                  SpringApplication.run(SampleApplication.class, args);
                 }
                
                }

                Add @EnableDiscoveryClient annotation to make the application as a discovery client and register in the Eureka server.


                • Start the service instances
                We are going to start two service instances from this application and register them in the service registry.
                For one instance we have already given the port number server.port=9090.
                Any way we can override this port number at the time of starting the application. To do that we need to create a jar file from the application and run the jar file with the specific port number. We can start multiple application instances by running the jar file with different port numbers.


                • To create a jar file, execute  mvn clean install from the location of pom.xml file. A jar file will be created in the target folder.


                • From target directory, run the following command with different port number to start two instances.
                java -jar -Dserver.port=8766 sample-0.0.1-SNAPSHOT.jar
                java -jar -Dserver.port=8767 sample-0.0.1-SNAPSHOT.jar



                After starting the instances, go and refresh the Eureka server console


                You can see that two instances from TEST-APP registered with the service registry.





                Wednesday, July 17, 2019

                Server Side Load Balancing vs Client Side Load Balancing


                Server Side Load Balancing




                In server side load balancing, there is a load balancer (separate server) in between requests and responses. So all the incoming traffic will be hitting to the edge server and It will distribute the incoming requests among the service instances based on the predefined rule.Ex: round robin
                This edge server can be a hardware load balancer or a software load balancer.

                Client Side Load Balancing

                Basically client side load balancing came into the picture with the micro service architecture.

                According to the micro service architecture there are a lot of loosely coupled services and inter service communication is required at the service level to expose a multiple entity involvement feature to the outside. Service discovery registering multiple instances from each service and load balancing among those instances and happening on the client side.



                Suppose Service A (client side) wants to access Service B (server side). Service B has three instances and register all at the discover server (Eureka). Service A has enabled the Ribbon client which allows to do the client side load balancing. It's getting the available Service B instances from the discovery server and redirect the traffic by staying from the client side.
                That's the concept of client side load balancing.