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.

                Monday, August 20, 2018

                WSO2 ESB Clustering


                Why do we need a clustered Application/Environment?

                Deploying the artifacts in a single server may completely unusable if that server goes down or unavailable.The huge risk is there due to the probability of single point of failure.
                When designing a deployment architecture for a software system, two things need to be concerned as a high importance.
                •  Availability
                •  Scalability
                What is availability?

                How well the system provides there functionality in the given set of time period without any service failures.



                What is scalability?

                It is a property of what amount of work the system or application can be handled and easily be expanded on demand.
                There are two different aspects of scalability.



                Vertical scalability

                Scaling up by adding more processing power to the existing systems to cater more requests.




                Horizontal scalability

                Expanding the processing ability of the system by adding new nodes parallelly which have identical functionality and distribute the incoming traffic among those nodes via a load balancer.



                Note: Clustering will addressed the above concepts of availability and scalability.

                Challenges in adding multiple nodes to the clustered system


                • Keeping the identical behavior in all the nodes(Replicate the changes among the nodes).
                • Managing the better communication among the servers.
                Active-Active & Active-Passive Clusters
                • Active-Active - All the nodes of the cluster are in active mode. In that case the load will balance among all the nodes.
                • Active-Passive - Some of the nodes are act as backup nodes.If Active nodes are down, the passive nodes are activate and handle the load.

                Multicast vs Unicast(WKA) Clusters

                A cluster can be created in the Runtime Manager from servers that are already registered with the Runtime Manager console. While configuring a cluster, you can specify either unicast or multicast options for identifying a node within the cluster:
                • Unicast: A unicast cluster requires that you configure the IP addresses of which nodes to associate together. No special network configuration is necessary other than to indicate which are the server IP addresses that make up the cluster.
                %3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22Node1%22%20style%3D%22ellipse%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3Baspect%3Dfixed%3BfillColor%3D%23fff2cc%3BstrokeColor%3D%23d6b656%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22160%22%20y%3D%22180%22%20width%3D%2260%22%20height%3D%2260%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%223%22%20value%3D%22%22%20style%3D%22ellipse%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3Baspect%3Dfixed%3BfillColor%3D%23f8cecc%3BstrokeColor%3D%23b85450%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22334%22%20y%3D%22187%22%20width%3D%2246%22%20height%3D%2246%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%224%22%20value%3D%22Multicast%20Channel%22%20style%3D%22text%3Bhtml%3D1%3Bresizable%3D0%3Bpoints%3D%5B%5D%3Bautosize%3D1%3Balign%3Dleft%3BverticalAlign%3Dtop%3BspacingTop%3D-4%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22296%22%20y%3D%22245%22%20width%3D%22110%22%20height%3D%2220%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%225%22%20value%3D%22Node4%22%20style%3D%22ellipse%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3Baspect%3Dfixed%3BfillColor%3D%23d5e8d4%3BstrokeColor%3D%2382b366%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22470%22%20y%3D%22250%22%20width%3D%2260%22%20height%3D%2260%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%226%22%20value%3D%22Node3%22%20style%3D%22ellipse%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3Baspect%3Dfixed%3BfillColor%3D%23d5e8d4%3BstrokeColor%3D%2382b366%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22470%22%20y%3D%22180%22%20width%3D%2260%22%20height%3D%2260%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%227%22%20value%3D%22Node2%22%20style%3D%22ellipse%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3Baspect%3Dfixed%3BfillColor%3D%23d5e8d4%3BstrokeColor%3D%2382b366%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22470%22%20y%3D%22110%22%20width%3D%2260%22%20height%3D%2260%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%228%22%20value%3D%22%22%20style%3D%22endArrow%3Dclassic%3Bhtml%3D1%3BentryX%3D0%3BentryY%3D0.5%3BexitX%3D1%3BexitY%3D0.5%3B%22%20edge%3D%221%22%20source%3D%222%22%20target%3D%223%22%20parent%3D%221%22%3E%3CmxGeometry%20width%3D%2250%22%20height%3D%2250%22%20relative%3D%221%22%20as%3D%22geometry%22%3E%3CmxPoint%20x%3D%22240%22%20y%3D%22130%22%20as%3D%22sourcePoint%22%2F%3E%3CmxPoint%20x%3D%22290%22%20y%3D%2280%22%20as%3D%22targetPoint%22%2F%3E%3C%2FmxGeometry%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%229%22%20value%3D%22%22%20style%3D%22endArrow%3Dclassic%3Bhtml%3D1%3BentryX%3D0%3BentryY%3D0.5%3B%22%20edge%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20width%3D%2250%22%20height%3D%2250%22%20relative%3D%221%22%20as%3D%22geometry%22%3E%3CmxPoint%20x%3D%22380%22%20y%3D%22210%22%20as%3D%22sourcePoint%22%2F%3E%3CmxPoint%20x%3D%22470.5%22%20y%3D%22139.5%22%20as%3D%22targetPoint%22%2F%3E%3C%2FmxGeometry%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2210%22%20value%3D%22%22%20style%3D%22endArrow%3Dclassic%3Bhtml%3D1%3BentryX%3D0%3BentryY%3D0.5%3B%22%20edge%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20width%3D%2250%22%20height%3D%2250%22%20relative%3D%221%22%20as%3D%22geometry%22%3E%3CmxPoint%20x%3D%22380%22%20y%3D%22210%22%20as%3D%22sourcePoint%22%2F%3E%3CmxPoint%20x%3D%22474%22%20y%3D%22210%22%20as%3D%22targetPoint%22%2F%3E%3C%2FmxGeometry%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2211%22%20value%3D%22%22%20style%3D%22endArrow%3Dclassic%3Bhtml%3D1%3BentryX%3D0%3BentryY%3D0.5%3B%22%20edge%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20width%3D%2250%22%20height%3D%2250%22%20relative%3D%221%22%20as%3D%22geometry%22%3E%3CmxPoint%20x%3D%22380%22%20y%3D%22210%22%20as%3D%22sourcePoint%22%2F%3E%3CmxPoint%20x%3D%22468%22%20y%3D%22279.5%22%20as%3D%22targetPoint%22%2F%3E%3C%2FmxGeometry%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E



                %3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22Node1%22%20style%3D%22ellipse%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3Baspect%3Dfixed%3BfillColor%3D%23fff2cc%3BstrokeColor%3D%23d6b656%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22160%22%20y%3D%22180%22%20width%3D%2260%22%20height%3D%2260%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%223%22%20value%3D%22%22%20style%3D%22ellipse%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3Baspect%3Dfixed%3BfillColor%3D%23f8cecc%3BstrokeColor%3D%23b85450%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22334%22%20y%3D%22187%22%20width%3D%2246%22%20height%3D%2246%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%224%22%20value%3D%22Multicast%20Channel%22%20style%3D%22text%3Bhtml%3D1%3Bresizable%3D0%3Bpoints%3D%5B%5D%3Bautosize%3D1%3Balign%3Dleft%3BverticalAlign%3Dtop%3BspacingTop%3D-4%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22296%22%20y%3D%22245%22%20width%3D%22110%22%20height%3D%2220%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%225%22%20value%3D%22Node4%22%20style%3D%22ellipse%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3Baspect%3Dfixed%3BfillColor%3D%23d5e8d4%3BstrokeColor%3D%2382b366%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22470%22%20y%3D%22250%22%20width%3D%2260%22%20height%3D%2260%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%226%22%20value%3D%22Node3%22%20style%3D%22ellipse%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3Baspect%3Dfixed%3BfillColor%3D%23d5e8d4%3BstrokeColor%3D%2382b366%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22470%22%20y%3D%22180%22%20width%3D%2260%22%20height%3D%2260%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%227%22%20value%3D%22Node2%22%20style%3D%22ellipse%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3Baspect%3Dfixed%3BfillColor%3D%23d5e8d4%3BstrokeColor%3D%2382b366%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22470%22%20y%3D%22110%22%20width%3D%2260%22%20height%3D%2260%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%228%22%20value%3D%22%22%20style%3D%22endArrow%3Dclassic%3Bhtml%3D1%3BentryX%3D0%3BentryY%3D0.5%3BexitX%3D1%3BexitY%3D0.5%3B%22%20edge%3D%221%22%20source%3D%222%22%20target%3D%223%22%20parent%3D%221%22%3E%3CmxGeometry%20width%3D%2250%22%20height%3D%2250%22%20relative%3D%221%22%20as%3D%22geometry%22%3E%3CmxPoint%20x%3D%22240%22%20y%3D%22130%22%20as%3D%22sourcePoint%22%2F%3E%3CmxPoint%20x%3D%22290%22%20y%3D%2280%22%20as%3D%22targetPoint%22%2F%3E%3C%2FmxGeometry%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%229%22%20value%3D%22%22%20style%3D%22endArrow%3Dclassic%3Bhtml%3D1%3BentryX%3D0%3BentryY%3D0.5%3B%22%20edge%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20width%3D%2250%22%20height%3D%2250%22%20relative%3D%221%22%20as%3D%22geometry%22%3E%3CmxPoint%20x%3D%22380%22%20y%3D%22210%22%20as%3D%22sourcePoint%22%2F%3E%3CmxPoint%20x%3D%22470.5%22%20y%3D%22139.5%22%20as%3D%22targetPoint%22%2F%3E%3C%2FmxGeometry%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2210%22%20value%3D%22%22%20style%3D%22endArrow%3Dclassic%3Bhtml%3D1%3BentryX%3D0%3BentryY%3D0.5%3B%22%20edge%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20width%3D%2250%22%20height%3D%2250%22%20relative%3D%221%22%20as%3D%22geometry%22%3E%3CmxPoint%20x%3D%22380%22%20y%3D%22210%22%20as%3D%22sourcePoint%22%2F%3E%3CmxPoint%20x%3D%22474%22%20y%3D%22210%22%20as%3D%22targetPoint%22%2F%3E%3C%2FmxGeometry%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2211%22%20value%3D%22%22%20style%3D%22endArrow%3Dclassic%3Bhtml%3D1%3BentryX%3D0%3BentryY%3D0.5%3B%22%20edge%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20width%3D%2250%22%20height%3D%2250%22%20relative%3D%221%22%20as%3D%22geometry%22%3E%3CmxPoint%20x%3D%22380%22%20y%3D%22210%22%20as%3D%22sourcePoint%22%2F%3E%3CmxPoint%20x%3D%22468%22%20y%3D%22279.5%22%20as%3D%22targetPoint%22%2F%3E%3C%2FmxGeometry%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E

                • Multicast: A multicast cluster groups servers that automatically detect each other. Servers that are part of a multicast cluster should be on the same network segment.One advantage of using multicast is that a server does not need to be running to be configured as a node in a cluster.


                WSO2 ESB clustering concepts


                1. Cluster Nodes
                • Manger Node- Manager Node is responsible to do the management operations of the cluster.Generally the manager node is not handle the work load.
                • Worker Node- Worker node is handling the work load in the clustered environment.It is not allowed to provide any management operations. If multiple worker nodes are there, the work load will be balance among them via a load balancer.

                Note: In the ESB clustered environment, we are not allowed to access the management console of the worker nodes and only allow in manager node.

                2. Database Setup

                When database setup in wso2 esb clustered environment, we need to make our attention on following databases.
                • User Management Db- Keep the information of ESB users
                • Registry Db - There are three major registries maintained by WSO2 ESB.

                Local Registry -Stores configuration and run time data that is local to the server.This partition is not shared with multiple servers and can be browsed under /_system/local in the registry browser.

                Configuration Registry -Stores product-specific configurations. This partition can be shared across multiple instances of the same product, such as sharing ESB configuration across a ESB cluster, and can be browsed under /_system/config in the registry browser.

                Governance Registry -Stores configurations and data that are shared across the whole platform. This space typically includes services, service descriptions, endpoints, and data sources, and it can be browsed under /_system/governance in the registry browser.


                In clustered environment, the following database structure should be maintained.
                • Separate databases for local registry in each node.
                • Shared database for user management.
                • Shared database for config and governance registry.

                3. Deployment Synchronization

                Deployment Synchronizer provides capability to synchronize deployment artifacts across the nodes of a product cluster. The following scenarios will be covered by Dep Sync in ESB cluster.
                • Maintaining an up-to-date backup of the artifact repository.
                • Sharing a single artifact repository among multiple servers in a cluster.
                • Enforcing artifact updates to be deployed on a server at run time.

                 There are two different ways of deployment synchronization.

                • SVN based Deployment Synchronizer- Use check in and check out functionality of SVN repository.




                • rsync for deployment Synchronization- Use rsync tool for copying files.



                Deployment diagram




                Create SVN Repository

                For the purpose of deployment synchronization, here we are using SVN based synchronizer and we can locally setup it as below.

                1.Create SVN repository.

                 svnadmin create <repostitory name>;  
                

                2.Add userName and password properties to the <repository name>/conf/passwd file as below.

                 ### This file is an example password file for svnserve.  
                 ### Its format is similar to that of svnserve.conf. As shown in the  
                 ### example below it contains one section labelled [users].  
                 ### The name and password for each user follow, one account per line.  
                 [users]  
                 randika = randika123  

                Set the passwd file as password-db in <repository name>/conf/svnserver.conf file as below.

                 ### users have read and write access to the repository.  
                 anon-access = write  
                 # auth-access = write  
                 ### The password-db option controls the location of the password  
                 ### database file. Unless you specify a path starting with a /,  
                 ### the file's location is relative to the directory containing  
                 ### this configuration file.  
                 ### If SASL is enabled (see below), this file will NOT be used.  
                 ### Uncomment the line below to use the default password file.  
                 password-db = passwd  
                


                Setting up Databases

                Need to create two shared databases for registry(conf and gov) and user management.

                 create user db  
                 mysql> create database wso2_user_db;  
                 mysql> use wso2_user_db;  
                 mysql> source /home/engineer/Documents/mitrai/cluster/manager/dbscripts/mysql.sql  
                 create registry db for shared config and governance  
                 mysql> create database wso2_reg_db;  
                 mysql> use wso2_reg_db;  
                 mysql> source /home/engineer/Documents/mitrai/cluster/manager/dbscripts/mysql.sql;  
                

                note: Here we are using mysql database and need to copy the jdbc driver .jar to the repository/components/lib directory.


                Configuring wso2 ESB Cluster(manger with 2 workers)

                In each node of the cluster, we need to change the configurations in below files.
                • axis2.xml- Enable the clustering, membership scheme and cluster node configurations.
                • carbon.xml- Deployment synchronization related configurations.
                • registry.xml- Registry mounting configurations.
                • user-mgt.xml- Change User management database configurations.
                • master-datasources.xml- Configurations for shared databases(Registry and User-management )

                Configurations of Manager node

                axis2.xml


                 <clustering class="org.wso2.carbon.core.clustering.hazelcast.HazelcastClusteringAgent"  
                         enable="true">  
                     <parameter name="clusteringPattern">WorkerManager</parameter>  
                     <parameter name="AvoidInitiation">true</parameter>  
                      <parameter name="membershipScheme">wka</parameter>  
                      <parameter name="domain">wso2.carbon.domain</parameter>  
                      <!-- The host name or IP address of this member -->  
                     <parameter name="localMemberHost">172.20.0.1</parameter>  
                     <!--  
                     The TCP port used by this member. This is the port through which other nodes will  
                     contact this member  
                      -->  
                     <parameter name="localMemberPort">4000</parameter>  
                     <!--  
                     Properties specific to this member  
                     -->  
                     <parameter name="properties">  
                       <property name="backendServerURL" value="https://${hostName}:${httpsPort}/services/"/>  
                       <property name="mgtConsoleURL" value="https://${hostName}:${httpsPort}/"/>  
                         <!-- Manger Setup with Port Mapping-->  
                       <property name="subDomain" value="mgt"/>  
                        <!-- Worker Setup-->  
                        <!--property name="subDomain" value="worker"/-->  
                     </parameter>  
                     <!--  
                       The list of static or well-known members. These entries will only be valid if the  
                       "membershipScheme" above is set to "wka"  
                     -->  
                     <members>  
                       <member>  
                         <hostName>172.20.0.1</hostName>  
                         <port>4100</port>  
                       </member>  
                        <member>  
                         <hostName>172.20.0.1</hostName>  
                         <port>4200</port>  
                       </member>  
                     </members>  
                     <!--  
                     Enable the groupManagement entry if you need to run this node as a cluster manager.  
                     Multiple application domains with different GroupManagementAgent implementations  
                     can be defined in this section.  
                     -->  
                     <groupManagement enable="false">  
                       <applicationDomain name="wso2.esb.domain"  
                                 description="ESB group"  
                                 agent="org.wso2.carbon.core.clustering.hazelcast.HazelcastGroupManagementAgent"  
                                 subDomain="worker"  
                                 port="2222"/>  
                     </groupManagement>  
                   </clustering>  
                

                carbon.xml

                     <Offset>1</Offset>  
                

                 <DeploymentSynchronizer>  
                     <Enabled>true</Enabled>  
                     <AutoCommit>true</AutoCommit>  
                     <AutoCheckout>true</AutoCheckout>  
                     <RepositoryType>svn</RepositoryType>  
                     <SvnUrl>file:///home/engineer/Documents/mitrai/repo/</SvnUrl>  
                     <SvnUser>randika</SvnUser>  
                     <SvnPassword>randika123</SvnPassword>  
                     <SvnUrlAppendTenantId>true</SvnUrlAppendTenantId>  
                   </DeploymentSynchronizer>  
                


                master-datasources.xml

                 <datasource>  
                       <name>WSO2_REG_DB</name>  
                                <description>The datasource used for shared config and governance registry</description>  
                                <jndiConfig>  
                                     <name>jdbc/WSO2SharedDB</name>  
                                </jndiConfig>  
                                <definition type="RDBMS">  
                                <configuration>  
                                     <url>jdbc:mysql://localhost:3306/wso2_reg_db</url>  
                                     <username>root</username>  
                                     <password>root</password>  
                                     <driverClassName>com.mysql.jdbc.Driver</driverClassName>  
                                     <maxActive>50</maxActive>  
                                     <maxWait>60000</maxWait>  
                                     <testOnBorrow>true</testOnBorrow>  
                                     <validationQuery>SELECT 1</validationQuery>  
                                     <validationInterval>30000</validationInterval>  
                                </configuration>  
                                </definition>  
                     </datasource>  
                     <datasource>  
                       <name>WSO2_USER_DB</name>  
                                <description>The datasource used for shared user db</description>  
                                <jndiConfig>  
                                     <name>jdbc/WSO2UserDB</name>  
                                </jndiConfig>  
                                <definition type="RDBMS">  
                                <configuration>  
                                     <url>jdbc:mysql://localhost:3306/wso2_user_db</url>  
                                     <username>root</username>  
                                     <password>root</password>  
                                     <driverClassName>com.mysql.jdbc.Driver</driverClassName>  
                                     <maxActive>50</maxActive>  
                                     <maxWait>60000</maxWait>  
                                     <testOnBorrow>true</testOnBorrow>  
                                     <validationQuery>SELECT 1</validationQuery>  
                                     <validationInterval>30000</validationInterval>  
                                </configuration>  
                                </definition>  
                     </datasource>  
                


                registry.xml


                 <dbConfig name="sharedregistry">  
                 <dataSource>jdbc/WSO2SharedDB</dataSource>  
                 </dbConfig>  
                 <remoteInstance url="https://localhost:9444/registry">  
                 <id>instanceid</id>  
                 <dbConfig>sharedregistry</dbConfig>  
                 <readOnly>false</readOnly>  
                 <enableCache>true</enableCache>  
                 <registryRoot>/</registryRoot>  
                 </remoteInstance>  
                 <mount path="/_system/config" overwrite="true">  
                 <instanceId>instanceid</instanceId>  
                 <targetPath>/_system/esbnodes</targetPath>  
                 </mount>  
                 <mount path="/_system/governance" overwrite="true">  
                 <instanceId>instanceid</instanceId>  
                 <targetPath>/_system/governance</targetPath>  
                 </mount>  
                

                user-mgt.xml

                       <Property name="dataSource">jdbc/WSO2UserDB</Property>  
                


                Configurations of Worker node1

                axis2.xml


                 <clustering class="org.wso2.carbon.core.clustering.hazelcast.HazelcastClusteringAgent"  
                         enable="true">  
                     <parameter name="clusteringPattern">WorkerManager</parameter>  
                     <parameter name="AvoidInitiation">true</parameter>  
                      <parameter name="membershipScheme">wka</parameter>  
                      <parameter name="domain">wso2.carbon.domain</parameter>  
                      <!-- The host name or IP address of this member -->  
                     <parameter name="localMemberHost">172.20.0.1</parameter>  
                     <!--  
                     The TCP port used by this member. This is the port through which other nodes will  
                     contact this member  
                      -->  
                     <parameter name="localMemberPort">4100</parameter>  
                     <!--  
                     Properties specific to this member  
                     -->  
                     <parameter name="properties">  
                       <property name="backendServerURL" value="https://${hostName}:${httpsPort}/services/"/>  
                       <property name="mgtConsoleURL" value="https://${hostName}:${httpsPort}/"/>  
                         <!-- Manger Setup with Port Mapping-->  
                       <!--<property name="subDomain" value="mgt"/>--> 
                        <!-- Worker Setup-->  
                        <property name="subDomain" value="worker"/>  
                     </parameter>  
                     <!--  
                       The list of static or well-known members. These entries will only be valid if the  
                       "membershipScheme" above is set to "wka"  
                     -->  
                     <members>  
                       <member>  
                         <hostName>172.20.0.1</hostName>  
                         <port>4000</port>  
                       </member>  
                        <member>  
                         <hostName>172.20.0.1</hostName>  
                         <port>4200</port>  
                       </member>  
                     </members>  
                     <!--  
                     Enable the groupManagement entry if you need to run this node as a cluster manager.  
                     Multiple application domains with different GroupManagementAgent implementations  
                     can be defined in this section.  
                     -->  
                     <groupManagement enable="false">  
                       <applicationDomain name="wso2.esb.domain"  
                                 description="ESB group"  
                                 agent="org.wso2.carbon.core.clustering.hazelcast.HazelcastGroupManagementAgent"  
                                 subDomain="worker"  
                                 port="2222"/>  
                     </groupManagement>  
                   </clustering>  
                

                carbon.xml

                     <Offset>2</Offset>  
                

                 <DeploymentSynchronizer>  
                     <Enabled>true</Enabled>  
                     <AutoCommit>false</AutoCommit>  
                     <AutoCheckout>true</AutoCheckout>  
                     <RepositoryType>svn</RepositoryType>  
                     <SvnUrl>file:///home/engineer/Documents/mitrai/repo/</SvnUrl>  
                     <SvnUser>randika</SvnUser>  
                     <SvnPassword>randika123</SvnPassword>  
                     <SvnUrlAppendTenantId>true</SvnUrlAppendTenantId>  
                   </DeploymentSynchronizer>  
                


                master-datasources.xml

                 <datasource>  
                       <name>WSO2_REG_DB</name>  
                                <description>The datasource used for shared config and governance registry</description>  
                                <jndiConfig>  
                                     <name>jdbc/WSO2SharedDB</name>  
                                </jndiConfig>  
                                <definition type="RDBMS">  
                                <configuration>  
                                     <url>jdbc:mysql://localhost:3306/wso2_reg_db</url>  
                                     <username>root</username>  
                                     <password>root</password>  
                                     <driverClassName>com.mysql.jdbc.Driver</driverClassName>  
                                     <maxActive>50</maxActive>  
                                     <maxWait>60000</maxWait>  
                                     <testOnBorrow>true</testOnBorrow>  
                                     <validationQuery>SELECT 1</validationQuery>  
                                     <validationInterval>30000</validationInterval>  
                                </configuration>  
                                </definition>  
                     </datasource>  
                     <datasource>  
                       <name>WSO2_USER_DB</name>  
                                <description>The datasource used for shared user db</description>  
                                <jndiConfig>  
                                     <name>jdbc/WSO2UserDB</name>  
                                </jndiConfig>  
                                <definition type="RDBMS">  
                                <configuration>  
                                     <url>jdbc:mysql://localhost:3306/wso2_user_db</url>  
                                     <username>root</username>  
                                     <password>root</password>  
                                     <driverClassName>com.mysql.jdbc.Driver</driverClassName>  
                                     <maxActive>50</maxActive>  
                                     <maxWait>60000</maxWait>  
                                     <testOnBorrow>true</testOnBorrow>  
                                     <validationQuery>SELECT 1</validationQuery>  
                                     <validationInterval>30000</validationInterval>  
                                </configuration>  
                                </definition>  
                     </datasource>  
                


                registry.xml


                 <dbConfig name="sharedregistry">  
                 <dataSource>jdbc/WSO2SharedDB</dataSource>  
                 </dbConfig>  
                 <remoteInstance url="https://localhost:9444/registry">  
                 <id>instanceid</id>  
                 <dbConfig>sharedregistry</dbConfig>  
                 <readOnly>false</readOnly>  
                 <enableCache>true</enableCache>  
                 <registryRoot>/</registryRoot>  
                 </remoteInstance>  
                 <mount path="/_system/config" overwrite="true">  
                 <instanceId>instanceid</instanceId>  
                 <targetPath>/_system/esbnodes</targetPath>  
                 </mount>  
                 <mount path="/_system/governance" overwrite="true">  
                 <instanceId>instanceid</instanceId>  
                 <targetPath>/_system/governance</targetPath>  
                 </mount>  
                

                user-mgt.xml

                       <Property name="dataSource">jdbc/WSO2UserDB</Property>  
                



                Configurations of Worker node2

                axis2.xml


                 <clustering class="org.wso2.carbon.core.clustering.hazelcast.HazelcastClusteringAgent"  
                         enable="true">  
                     <parameter name="clusteringPattern">WorkerManager</parameter>  
                     <parameter name="AvoidInitiation">true</parameter>  
                      <parameter name="membershipScheme">wka</parameter>  
                      <parameter name="domain">wso2.carbon.domain</parameter>  
                      <!-- The host name or IP address of this member -->  
                     <parameter name="localMemberHost">172.20.0.1</parameter>  
                     <!--  
                     The TCP port used by this member. This is the port through which other nodes will  
                     contact this member  
                      -->  
                     <parameter name="localMemberPort">4200</parameter>  
                     <!--  
                     Properties specific to this member  
                     -->  
                     <parameter name="properties">  
                       <property name="backendServerURL" value="https://${hostName}:${httpsPort}/services/"/>  
                       <property name="mgtConsoleURL" value="https://${hostName}:${httpsPort}/"/>  
                         <!-- Manger Setup with Port Mapping-->  
                       <!--<property name="subDomain" value="mgt"/>--> 
                        <!-- Worker Setup-->  
                        <property name="subDomain" value="worker"/>  
                     </parameter>  
                     <!--  
                       The list of static or well-known members. These entries will only be valid if the  
                       "membershipScheme" above is set to "wka"  
                     -->  
                     <members>  
                       <member>  
                         <hostName>172.20.0.1</hostName>  
                         <port>4100</port>  
                       </member>  
                        <member>  
                         <hostName>172.20.0.1</hostName>  
                         <port>4200</port>  
                       </member>  
                     </members>  
                     <!--  
                     Enable the groupManagement entry if you need to run this node as a cluster manager.  
                     Multiple application domains with different GroupManagementAgent implementations  
                     can be defined in this section.  
                     -->  
                     <groupManagement enable="false">  
                       <applicationDomain name="wso2.esb.domain"  
                                 description="ESB group"  
                                 agent="org.wso2.carbon.core.clustering.hazelcast.HazelcastGroupManagementAgent"  
                                 subDomain="worker"  
                                 port="2222"/>  
                     </groupManagement>  
                   </clustering>  
                

                carbon.xml

                     <Offset>3</Offset>  
                

                 <DeploymentSynchronizer>  
                     <Enabled>true</Enabled>  
                     <AutoCommit>false</AutoCommit>  
                     <AutoCheckout>true</AutoCheckout>  
                     <RepositoryType>svn</RepositoryType>  
                     <SvnUrl>file:///home/engineer/Documents/mitrai/repo/</SvnUrl>  
                     <SvnUser>randika</SvnUser>  
                     <SvnPassword>randika123</SvnPassword>  
                     <SvnUrlAppendTenantId>true</SvnUrlAppendTenantId>  
                   </DeploymentSynchronizer>  
                


                master-datasources.xml

                 <datasource>  
                       <name>WSO2_REG_DB</name>  
                                <description>The datasource used for shared config and governance registry</description>  
                                <jndiConfig>  
                                     <name>jdbc/WSO2SharedDB</name>  
                                </jndiConfig>  
                                <definition type="RDBMS">  
                                <configuration>  
                                     <url>jdbc:mysql://localhost:3306/wso2_reg_db</url>  
                                     <username>root</username>  
                                     <password>root</password>  
                                     <driverClassName>com.mysql.jdbc.Driver</driverClassName>  
                                     <maxActive>50</maxActive>  
                                     <maxWait>60000</maxWait>  
                                     <testOnBorrow>true</testOnBorrow>  
                                     <validationQuery>SELECT 1</validationQuery>  
                                     <validationInterval>30000</validationInterval>  
                                </configuration>  
                                </definition>  
                     </datasource>  
                     <datasource>  
                       <name>WSO2_USER_DB</name>  
                                <description>The datasource used for shared user db</description>  
                                <jndiConfig>  
                                     <name>jdbc/WSO2UserDB</name>  
                                </jndiConfig>  
                                <definition type="RDBMS">  
                                <configuration>  
                                     <url>jdbc:mysql://localhost:3306/wso2_user_db</url>  
                                     <username>root</username>  
                                     <password>root</password>  
                                     <driverClassName>com.mysql.jdbc.Driver</driverClassName>  
                                     <maxActive>50</maxActive>  
                                     <maxWait>60000</maxWait>  
                                     <testOnBorrow>true</testOnBorrow>  
                                     <validationQuery>SELECT 1</validationQuery>  
                                     <validationInterval>30000</validationInterval>  
                                </configuration>  
                                </definition>  
                     </datasource>  
                


                registry.xml


                 <dbConfig name="sharedregistry">  
                 <dataSource>jdbc/WSO2SharedDB</dataSource>  
                 </dbConfig>  
                 <remoteInstance url="https://localhost:9444/registry">  
                 <id>instanceid</id>  
                 <dbConfig>sharedregistry</dbConfig>  
                 <readOnly>false</readOnly>  
                 <enableCache>true</enableCache>  
                 <registryRoot>/</registryRoot>  
                 </remoteInstance>  
                 <mount path="/_system/config" overwrite="true">  
                 <instanceId>instanceid</instanceId>  
                 <targetPath>/_system/esbnodes</targetPath>  
                 </mount>  
                 <mount path="/_system/governance" overwrite="true">  
                 <instanceId>instanceid</instanceId>  
                 <targetPath>/_system/governance</targetPath>  
                 </mount>  
                

                user-mgt.xml

                       <Property name="dataSource">jdbc/WSO2UserDB</Property>  
                


                Setting up nginx

                Install nginx
                 $sudo apt-get install nginx  
                

                Configurations in /etc/nginx/nginx.conf file
                 upstream test_cluster{  
                      server worker1.com:8282;  
                      server worker1.com:8283;  
                 }  
                 server {  
                      listen 80;  
                      server_name mitrai.test.com;  
                      location / {  
                           proxy_pass http://test_cluster;  
                      }  
                 }  
                

                Check the status of nginx.conf file
                 engineer@engineer-VirtualBox:/etc/nginx$ sudo nginx -t  
                 nginx: the configuration file /etc/nginx/nginx.conf syntax is ok  
                

                Start nginx server

                 sudo /etc/init.d/nginx start  
                


                Starting Server Nodes

                Start the Manager node first and after worker nodes.

                • Manager node:
                   ./Wso2server.sh  
                  
                • Worker Nodes:
                   ./Wso2server.sh -DworkerNode=true