Saturday, March 23, 2019

Microservices - Client side load balancing with Ribbon

Greetings!

In my previous post I introduced Feign REST client with hard coded (or single) URL. We can improve it using Ribbon.
Ribbon is a client side load balancer which not only provides load balancing feature but also support caching, fault tolerance.

Source code can be found at github.


Add Ribbon library

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

Update properties

Update cart-service.yml
catalog-service:
  ribbon:
    listOfServers: localhost:8010,localhost:8011

Update Fiegn Client

@FeignClient(name = "catalog-service")
@RibbonClient(name = "catalog-service")
public interface CatalogServiceFeign

Restart the cart service and test the application. Remember to push the configuration changes to github.

References

https://github.com/Netflix/ribbon
https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-ribbon.html

Microservices - Feign Rest client

Greetings!

In our previous posts we used Spring RestTemplate as our Rest client. Even though it was easy to use, we have lots of boilerplate code. This is why we are going to use Netflix Feign Client. If you have used Retrofit, this looks familiar (or Spring Data JPA). With Feign, we are only creating the interface with few annotations. Then Feign will create the necessary implementation for us.
One of the main advantages using Feign is, inbuilt support of Ribbon load balancing and easy to connect with Eureka server.

Source code can be found at github

Add Feign library

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

Enable Feign client

@EnableFeignClients
@SpringBootApplication
public class ShoppingCartServiceApplication

Implement Feign client

  • Create an interface.
  • Annotate it with @FeignClient with url and mandatory name.
  • Add method signature as same as the corresponding controller method.
@FeignClient(name = "catalog-service", url = "http://localhost:8010")
public interface CatalogServiceFeign {

    @GetMapping("/{id}")
    Product findProduct(@PathVariable("id") String id);

}

That is all!


Microservices - Configuration Management

Greetings!

There were time we hard coded configuration properties directly into the code. When we get matured we learnt that it is always a better choice to remove hard coded values from the code and add them as configurable properties. That definitely paid off. For an example we add our database configuration in a separate file so that depending on the environment we can easily change it. We when use profiles we go one step further to add file per environment like dev, live, etc.

How will this effect to microservices architecture? If we are dealing with small number of microservices it is ok to bundle them with the corresponding jar though it is not the microservices way of doing things.

When number of the services are growing how do you maintain your environment? It will be a nightmare to keep a track of all properties in this way. Also, when we automate our release process it will be harder to do so.

This is why in microservices architecture we need to segregate all the service configurations. Application configurations will not bundle with the service instance, instead it will pick its configurations from a central location.

Say what, our microservices will be using another microservices to get their configuration properties!

By the way, how many times have you deployed into production environment with your development environment properties ;)

Complete Source Code

Do it in Spring way

Sure thing, we are using Spring framework with Spring Boot hence we use Spring Cloud Config.
This is what they say;
"Spring Cloud Config provides server and client-side support for externalized configuration in a distributed system. With the Config Server you have a central place to manage external properties for applications across all environments."

Spring cloud config uses file location or github location as the configuration repository which makes maintenance very easy.


Let's create our configuration server


  1. Generate a project using https://start.spring.io
  2. Add spring-cloud-config-server as dependencies.
  3. @EnableConfigServer
  4. Add configuration repository path.
  5. Add configurations properties.

pom.xml

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>

Boostrap class

@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication

Application properties

Easiest way to add a file repository is using a file location. Let's create default and dev profiles in a file location. (mine is /home/manjula/config-repo)
Special thing to note here is we need to name file according to our service name.
<service_name>-<profile>.yml

myservice.yml
message: "Hello from default profile"

myservice-dev.yml

message: "Hello from development team"


Update the application.yml
server:
  port: 8888

spring:
  profiles:
    active: native
  cloud:
    config:
      server:
        native:
          searchLocations: file:///home/manjula/config-repo

Start the application and locate to http://localhost:8888/myservice/default
You should get this output.
{
    "name": "myservice",
    "profiles": [
        "default"
    ],
    "label": null,
    "version": null,
    "state": null,
    "propertySources": [
        {
            "name": "file:///home/manjula/config-repo/myservice.yml",
            "source": {
                "message": "Hello from default profile"
            }
        }
    ]
}

For the dev profile locate to http://localhost:8888/myservice/dev
// ommited
        {
            "name": "file:///home/manjula/config-repo/myservice-dev.yml",
            "source": {
                "message": "Hello from development team"
            }
        },
        {
            "name": "file:///home/manjula/config-repo/myservice.yml",
            "source": {
                "message": "Hello from default profile"
            }
        }
// ommited

Note that this gives both properties though when using in a client dev profile will override the values from the default profile.

Using a Git repository

Even though file location solution seems simple and easy, it will add additional problems when working with a team. Also, using a Git repository we can easily manage version history.
Instead of the file location, create a Git repository and commit our service's configuration properties.

Below is the updated application.yml
server:
  port: 8888

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/slmanju/microservices-demo
          searchPaths: configurations
          skipSslValidation: true

Re-start the server and you should get the same responses as before.

Config Client

Now our configuration server is up. We need to update our microservices to fetch the properties from configuration server.
Spring Boot uses bootstrap file early in the booting process. Hence we can add our service name and configuration service location into boostrap.yml file.

  1. Create and update bootstap.yml file.
  2. Add corresponding property/yml files into configuration repo.
  3. Update maven dependencies to add config-server.
  4. Run the application.

Note: Pay attention to this line;
Fetching config from server at : http://localhost:8888

bootstrap.yml

spring:
  application:
    name: catalog-service

  cloud:
    config:
      uri: http://localhost:8888

add maven dependency

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>



Microservices - Basic Project

Greetings!

To explain microservices architecture in coming posts I am going to create a very basic shopping cart. This is very simple set up with shopping cart service which interact with product service to get product details.

Get the initial project

I have provided necessary postman collection to test the project.



Just to brush up, let's see how easy it to create a microservice with modern Java tech stack.


  1. Navigate to https://start.spring.io/
  2. Select Web, Actuator, JPA, H2, Lombok dependencies.
  3. Generate the project.
  4. Import the project into preferred IDE.
  5. Run the application.


That is within few minutes we have a running skeleton.




Sunday, March 17, 2019

Microservices - Getting Started

Greetings!

In the past we used to pack all our services into a single bundle and deploy it. This monolithic applications have it's own pros and cons.

  • Massive code bases are difficult to maintain.
  • To deliver a single feature we have to deploy full application.
  • If something fail, whole system fail.
  • Difficult to scale.
  • Domains are tightly coupled.
  • Everything in a single database.
  • Quick deliveries are difficult.


This does not mean monolithic systems are bad. It is depending on the system we build. Above mentioned disadvantages will become advantages on those situations. In addition to that a monolithic system;

  • Easy to monitor
  • Have one code base to maintain
  • Easy to trace any error
  • Easy transaction handling.


Ideally, if your company is not willing to bear the initial cost (specially start ups), CI/CD pipelines, server costs, etc go with monolithic.

On the other hand microservices are here to solve these kind of problems although it is not a one fit for all solution. Given all the advantages, one of the main advantage of the microservice architecture is replaceability. Since the services are properly decoupled we can replace whole system without breaking any.

In a microservice architecture application is broken into small-grained components by their business domain. One of main difficulties is identifying business boundaries. That is why it is always better to use "monolithic first" approach since it will give us proper understanding about the system we are going to build. A properly structured microservice give us;

  • Faster delivery of new features
  • Independent delivery of business.
  • Independent deploy, update, replace, scale.
  • Highly flexible
  • Resilient
  • Scalable
  • Database is divided as per the domain.
  • Different technologies as per the demand.


It is widely misunderstood that breaking a system into REST APIs is the microservice architecture. It should be noted that there is no proper definition for a microservices and we should ask the question from ourselves. Is my service is really a microservice?

A bad microservice


  • A service with too many responsibilities.
  • Having large number of tables (more than 5).
  • Service per a table.
  • Heavily interdependent on one another.
  • Cannot re-write within few days.


A good microservice


  • Replace within few days with different technologies.
  • Single responsibility
  • Serving small number to tables (usually less than 5)
  • Independent of other services.


In addition to those it is always better to stick to below practices.

  • Use REST philosophy.
  • Proper URI names to communicate intent.
  • HTTP status codes to communicate results.
  • JSON as the request/ result type.
  • Versions from the beginning.
  • Communicate its health.
  • Self contained and independently deployable.


Nothing comes free. When working with microservices we are going to face new set of problems.

  • How to manage configurations?
  • How does services find each other?
  • How can we load balance?
  • How to pin down a failure and monitor logs?
  • How to handle security?
  • What are we going to do if a service is failed?


Lucky for us we are not alone. Giants in the industry already have faced these difficulties which lead them to create frameworks to handle them. Companies like Pivotal, Netflix has gone one step further making their products free and open source. With Spring Boot it is a matter of adding few dependencies into our build automation tool which help us to focus on our business domain.

  • Spring Boot - Quickly create microservices
  • Spring Cloud Config - Configuration management
  • Netflix Eureka - Service discovery
  • Netflix Zuul - Route gateway
  • Netflix Ribbon - Client side load balancing
  • Netflix Histrix - Circuit breaker
  • Spring Cloud Sleuth - Distributed tracing
  • Spring Cloud Stream - Asynchronous event processing 
  • Spring Cloud Security - Authentication and authorization management

Further reading


https://spring.io/projects/spring-cloud
https://netflix.github.io/
https://12factor.net/
Spring microservices in action
Learn microservices with spring boot
Microservices with spring boot and spring cloud
https://microservices.io/
https://martinfowler.com/articles/microservices.html
How netflix works