terça-feira, 15 de novembro de 2016

Spring Cloud Netflix Zuul - Edge Server/Api Gateway/Gateway Service

Zuul is the front door for all requests from devices and web sites to the backend of the Netflix streaming application. As an edge service application, Zuul is built to enable dynamic routing, monitoring, resiliency and security. 




Routing in an integral part of a microservice architecture. For example, may be mapped to your web application, /api/users is mapped to the user service and /api/shop is mapped to the shop service. Zuul is a JVM based router and server side load balancer by Netflix.

The volume and diversity of Netflix API traffic sometimes results in production issues arising quickly and without warning. We need a system that allows us to rapidly change behavior in order to react to these situations.


Zuul uses a range of different types of filters that enables us to quickly and nimbly apply functionality to our edge service. These filters help us perform the following functions: 


  • Authentication and Security: identifying authentication requirements for each resource.
  • Insights and Monitoring: tracking meaningful data and statistics.
  • Dynamic Routing: dynamically routing requests to different backend..
  • Stress Testing: gradually increasing the traffic.
  • Load Shedding: allocating capacity for each type of request and dropping requests.
  • Static Response handling: building some responses directly.
  • Multiregion Resiliency: routing requests across AWS regions.

Zuul contains multiple components:
  • zuul-core: library which contains the core functionality of compiling and executing Filters
  • zuul-simple-webapp: webapp which shows a simple example of how to build an application with zuul-core
  • zuul-netflix: library which adds other NetflixOSS components to Zuul - using Ribbon for routing requests, for example.
  • zuul-netflix-webapp: webapp which packages zuul-core and zuul-netflix together into an easy to use package
Zuul gives us a lot of insight, flexibility, and resiliency, in part by making use of other Netflix OSS components:
  • Hystrix is used to wrap calls to our origins, which allows us to shed and prioritize traffic when issues occur
  • Ribbon is our client for all outbound requests from Zuul, which provides detailed information into network performance and errors, as well as handles software load balancing for even load distribution
  • Turbine aggregates fine­grained metrics in real­time so that we can quickly observe and react to problems
  • Archaius handles configuration and gives the ability to dynamically change properties

I talk about these components here:

We can create a filter to route a specific customer or device to a separate API cluster for debugging. Prior to using Zuul, we were using Hadoop to query through billions of logged requests to find the several thousand requests we were interested in.

We have an automated process that uses dynamic Archaius configurations within a Zuul filter to steadily increase the traffic routed to a small cluster of origin servers. As the instances receive more traffic, we measure their performance characteristics and capacity.

Spring Cloud has created an embedded Zuul proxy to ease the development of a very common use case where a UI application wants to proxy calls to one or more back end services. This feature is useful for a user interface to proxy to the backend services it requires, avoiding the need to manage CORS and authentication concerns independently for all the backends.

To enable it, annotate a Spring Boot main class with @EnableZuulProxy, and this forwards local calls to the appropriate service. By convention, a service with the ID "users", will receive requests from the proxy located at /users.
The proxy uses Ribbon to locate an instance to forward to via discovery, and all requests are executed in a hystrix command, so failures will show up in Hystrix metrics, and once the circuit is open the proxy will not try to contact the service.

Zuul Request Lifecycle



In this picture is possible check that, before access the original server, Zuul provide some functionality to add in requests , or after requests (response), like filter, routing, aggregation, error treatment etc.

In my sample, I implemented filter/routing with Zuul.


I have 2 components in this sample, service and Zuul.


Service will provide some operations :




@RestController
@SpringBootApplicationpublic class BookApplication {

 
@RequestMapping(value = "/available")
 
public String available() {
   
return "Spring in Action";
  }

 
@RequestMapping(value = "/checked-out")
 
public String checkedOut() {
   
return "Spring Boot in Action";
  }

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






Zuul service:

 @EnableZuulProxy
@SpringBootApplication
public class GatewayApplication {
  public static void main(String[] args) {
    SpringApplication.run(GatewayApplication.
class, args);
  }
  @Bean
 
public SimpleFilter simpleFilter() {
   
return new SimpleFilter();
  }
}

public class SimpleFilter extends ZuulFilter {
  private static Logger log = LoggerFactory.getLogger(SimpleFilter.class);
  @Override
 
public String filterType() {
   
return "pre";
  }
  @Override
 
public int filterOrder() {
   
return 1;
  }
  @Override
 
public boolean shouldFilter() {
   
return true;
  }
  @Override
 
public Object run() {
    RequestContext
ctx = RequestContext.getCurrentContext();
    HttpServletRequest request = ctx.getRequest();
    log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString()));
    return null;
  }
}








With Zuul and book service working together we have possibility access books operation available and checked-out across  http://localhost:8080/books

Sample: 




terça-feira, 18 de outubro de 2016

Managing your Database with Liquibase and Gradle

One of the major system development problems has always been how and when we will update the database.

When happen some database change in the development environment, always some questions appear:
  • Scripts for DB changes were created?
  • Where to save the DB changes?
  • When should we apply these changes?
  • These changes have already been implemented?
  • How do we track and manage database changes?
  • Who did these changes?

Liquibase is the library that can help address these issues.

Liquibase is an independent library open source database used to track, manage, and apply changes to the database.

Liquibase works better because it understands what the changes are. For example, a database comparison program would simply see the “person” table on integration has a “firstname” and a “lastname” column, but on live, the “person” table has a “name” column. It would report that you need to drop the “name” column and add a “firstname” and a “lastname” column. While this would leave you with the correct schema, you would lose everyone’s name in the process. With Liquibase, you would have a changeset that says “rename ‘name’ to ‘lastname’ and add a ‘firstname’ column” or, even better, “split the name column on a space and place the values in new ‘firstname’ and ‘lastname’ columns, then drop the ‘name’ column.” Knowing why they are different allows changes to production databases without the fear of losing valuable data.

In this post I will show how you can use the powerful tool Liquibase together with Gradle to automate these tasks, from there will be easy to put Liquibase to work with your continuos integration tools.

Some important concepts:

Changelog file

  • Is the file that contains references of all scripts that should be applied to the database in any environment.

ChangeSet Files:

  • Are all the files recorded in a Changelog
  • Changesets files can be written primarily in XML, YAML, JSON, SQL
    •  I chose for this example SQL.

Some Advices:

  • IDs cannot be repeated, otherwise they will not run
  • Scripts should be smalls
  • Should be added script Rollback whenever possible
  • Must be added new scripts on the changelog.xml
  • Everything that was executed is registered on table DATABASECHANGELOG

Sample:

changelog.xml


001.SAMPLE.sql


002.SAMPLE.sql

build.gradle

I created tasks for every environment I have and where liquibase should run the script.

With Gradle I need only choose a task as it is below:
  • To execute:
    • gradle task dev update
    • gradle task qa update
    • gradle task prod update

After that you can check in your database, that these scripts 001 and 002 were applied.

On the table DATABASECHANGELOG is possible check some records like these:



This sample above complete in my GitHub 

References:


quinta-feira, 13 de outubro de 2016

Library for configuration management from Netflix

Archaius is the Netflix client side configuration library. It is the library used by all of the Netflix OSS components for configuration. 

It is an extension of the Apache Commons Configuration project. It allows updates to configuration by either polling a source for changes or for a source to push changes to the client. Archaius uses Dynamic Property classes as handles to properties.

Some Archaius features: 
  • Dynamic, Typed Properties
  • High throughput and Thread Safe Configuration operations
  • A polling framework that allows obtaining property changes of a Configuration Source
  • A Callback mechanism that gets invoked on effective
  • A JMX MBean that can be accessed via JConsole to inspect and invoke operations on properties
  • Out of the box, Composite Configurations for applications
  • Implementations of dynamic configuration sources for URLs, JDBC and Amazon DynamoDB
  • Scala dynamic property wrappers

In my sample I will show how use Dynamic Properties and how is could be used Archaius with configuration with many environments.



About ArchaiusSandBox class:
  • Set default configuration with property archaius.properties 
  • installConfig is a method that apply config, with polling to each 1 second 
  • In set environment we will get value from "environment" variable, we expected in this case DEV or TEST
  • In the main method, we call the configuration to get "myprop"
    • it is possible put default configuration to property, I defined "NOT FOUND" but is possible put any value.
    • waiting 10 seconds to put new configuration and call again 







Resources folder. There are 3 properties:
  • archaius.properties is the default configuration with  reference to configuration available per environment
  • archaius-dev.properties configuration specific to DEV
  • archaius-test configuration specific to TEST













In runtime is possible change property, to work in this sample, should be added on archaius.properties (within 10 seconds) the property myprop=TEST-VALUE.

After 10 seconds put in main method it should printed the new value.

In this post I used some archaius functionalities, there are many others available. But with these few codes is possible create configuration to many environments with possibility to change in runtime.




References:


segunda-feira, 26 de setembro de 2016

Spring Cloud Netflix - Load Balancer with Ribbon/Feign

Spring Cloud Netflix to provide client-side load balancing in calls to another microservice.
The idea in this post is show some concepts about load balancing, Ribbon and Feign, and step by step who work Ribbon and Feign.




Load Balancing 

 Load Balancing automatically distributes incoming application traffic between two or more computers. It enables you to achieve fault tolerance in your applications, seamlessly providing the required amount of load balancing capacity needed to route application traffic. Load balancing aims to optimize resource use, maximize throughput, minimize response time, and avoid overload of any single resource. Using multiple components with load balancing instead of a single component may increase reliability and availability through redundancy.
Ribbon  - Load Balancer without Eureka 

Ribbon is a client side load balancer, which gives you a lot of control over the behavior of HTTP and TCP clients. Ribbon's Client component offers a good set of configuration options such as connection timeouts, retries, retry algorithm (exponential, bounded back off) etc. Ribbon comes built in with a pluggable and customizable Load Balancing component. 
Some of the load balancing strategies offered are listed below:

  • Simple Round Robin LB
  • Weighted Response Time LB
  • Zone Aware Round Robin LB
  • Random LB


Client-Side  Load Balancing

An approach to load balancing is to deliver a list of server IPs to the client, and then to have client randomly select the IP from the list on each connection. It has been claimed that client-side random load balancing tends to provide better load distribution than round-robin DNS. With this approach, the method of delivery of list of IPs to the client can vary, and may be implemented as a DNS list (delivered to all the clients without any round-robin), or via hardcoding it to the list. If a "smart client" is used, detecting that randomly selected server is down and connecting randomly again, it also provides fault tolerance.
Ribbon provides the following features:

  • Load balancing
  • Fault tolerance
  • Multiple protocol (HTTP, TCP, UDP) support in an asynchronous and reactive model
  • Caching and batching
A central concept in Ribbon is that of the named client. Each load balancer is part of an ensemble of components that work together to contact a remote server on demand, and the ensemble has a name that you give it as an application developer.

Using Ribbon - Code:


First Service is hello-service 

This service provide some aleatory greeting when access http://localhost:8090/greeting


@RestController
@SpringBootApplication
public class HelloApplication {

private static Logger log = LoggerFactory.getLogger(HelloApplication.class);

@RequestMapping(value = "/greeting")
public String greet() {
log.info("Access /greeting");

List<String> greetings = Arrays.asList("Hi there", "Greetings", "Salutations");
Random rand = new Random();

int randomNum = rand.nextInt(greetings.size());
return greetings.get(randomNum);
}

@RequestMapping(value = "/")
public String home() {
log.info("Access /");
return "Hi!";
}

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

}


File: application.yml

spring:
  application:
    name: hello-service

server:
  port: 8090

OBS: should create two more hello-service in Port 9092, 9999


Second Service is user-service 
This service call for hello-service, operation greeting, with ribbon configured, this service call hello-service based on algorithm round-robin.


@SpringBootApplication
@RestController
@RibbonClient(name = "hello-service", configuration = HelloServiceConfiguration.class)
public class UserApplication {

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

@Autowired
RestTemplate restTemplate;

@RequestMapping("/hi")
public String hi(@RequestParam(value = "name", defaultValue = "Rafael") String name) {
String greeting = this.restTemplate.getForObject("http://hello-service/greeting", String.class);
return String.format("%s, %s!", greeting, name);
}

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

}

public class HelloServiceConfiguration {
@Autowired
IClientConfig ribbonClientConfig;

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

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

File: application.yml
In ribbon configuration are listed all services available.


spring:
  application:
    name: user-service

server:
  port: 8888
  
hello-service:
  ribbon:
    eureka:
      enabled: false
    listOfServers: localhost:8090,localhost:9092,localhost:9999

    ServerListRefreshInterval: 15000


When we call the service on URL http://localhost:8090/greeting , on console is possible see each service it is called, for example, in the fist call any host configured on list of servers could be used.



Feign - Load Balancer using Eureka 

Feign is a declarative web service client, or declarative REST client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web. 
Spring Cloud integrates Ribbon and Eureka to provide a load balanced http client when using Feign.

I talk more about Eureka here.

Using Feign - Code:

Eureka server Project: http://localhost:8761


@SpringBootApplication
@EnableEurekaServer
public class ApplicationEurekaServer {
    public static void main(String[] args) {
        new SpringApplicationBuilder(ApplicationEurekaServer.class)
        .web(true)
        .run(args);
    }

}

File: application.yml

#Server Specifics
server:
  port: 8761

error:
    whitelabel:
      enabled: false

spring:
  application:
    name: eureka-server

#Eureka Specifics

eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/



Service is hello-service http://localhost:7111/greeting



@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class HelloApplication {
@Autowired
DiscoveryClient client;

@RequestMapping("/")
public String hello() {
ServiceInstance localInstance = client.getLocalServiceInstance();
return "Hello World: "+ localInstance.getServiceId()+":"+localInstance.getHost()+":"+localInstance.getPort();
}

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

}

File: application.yml

spring:
  application:
    name: hello-service

server:
  port: 7111
  
eureka:
  client:
    healthcheck:
      enabled: true
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/  

Should be create other hello-service on Port 7112 http://localhost:7112/greeting

And the service that will consume these hello-service is user-service.


@SpringBootApplication
@EnableDiscoveryClient
@RestController
@EnableFeignClients

public class UserApplication {
@Autowired
HelloClient client;

@RequestMapping("/")
public String hello() {
return client.hello();
}

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

@FeignClient("hello-service")
interface HelloClient {
@RequestMapping(value = "/", method = GET)
String hello();
}

}

File: application.yml

spring:
  application:
    name: user-service

server:
  port: 7211
  
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  instance:
    leaseRenewalIntervalInSeconds: 10
    metadataMap:
      instanceId: ${vcap.application.instance_id:${spring.application.name}:${spring.application.instance_id:${server.port}}}

endpoints:
  restart:
    enabled: true
  shutdown:
    enabled: true
  health:
    sensitive: false



This service will be available on http://localhost:7211
user-service will ask to Eureka the hello-service address, and will receive some address that is registered.

If everything OK this service will be registered on Eureka:


When we call http://localhost:7211 on of these message will be showed:

Hello World: hello-service:192.168.0.14:7112

Hello World: hello-service:192.168.0.14:7111



References: