Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
190 lines (135 sloc) 15.8 KB

Source Code for my blog - http://dhaval-shah.com/understanding-cloud-native-architecture-with-an-example/

Reservation Service

An application which allows user to manage Reservatioins

This is a POC application which does not have a UI, with a purpose of demonstrating Microservice Architecture Pattern using Spring Boot and leveraging Cloud Native Architecture via Spring Cloud.

Functional service(s)

Since this application is a POC, so from a functional standpoint it just has a single service called Reservation Service which allows to create and view reservations for user.

Functional services

Reservation service

Comprises of business flow which allows user to add and edit reservations

Method Path Description User authenticated Available from UI
GET /reservations/names Gets entire list of reservations done by user × ×
POST /reservations/ Creates reservations for a given user ×

Infrastructure Services

There are industry standard cloud patterns which can help us to ease out infrastructure and operational concerns. Spring cloud provides tools for developers to quickly build some of the common patterns in distributed systems (e.g. configuration management, service discovery, circuit breakers, intelligent routing etc.)

I will cover some of them as we proceed further.

Infrastructure services

Config service

Spring Cloud Config is horizontally scalable centralized configuration service for distributed systems. It uses a pluggable repository layer that currently supports Git and local storage.

This POC simply loads config files from the local classpath. These files are available at config-files directory in Config service resources. By following the rule of convention whenever reservation-service requests it's configuration, this Config service responds with config-files/reservation-service.properties and config-files/application.properties.

Client side usage

For using above configurations just build Spring Boot application that depends on spring-cloud-config-client. The most easiest and straight forward way to add this dependency via spring-cloud-starter-config POM.

With this you don't need any properties to be managed via your application. Just provide bootstrap.properties with Config service url and application name :

spring.cloud.config.uri = http://localhost:8888
spring.application.name = reservation-service
With Spring Cloud Config, how to change app configuration dynamically?

In our application, MessageRestController within reservation-service is annotated with @RefreshScope; which means, it can not only get updated value of message but also rest of the values from reservation-service.properties without rebuild and application (i.e. reservation-service) restart.

First, change required properties in Config server. Then, perform refresh request to reservation-service: curl -d{} http://localhost:8000/refresh and there after try accessing http://localhost:8000/message

Notes

Spring Cloud Config can be primarily be used for :

Service discovery

One of the key tenats of Microservice Architecture pattern is Service discovery. With Microservice Architecture one would generally have myriad set of services and keeping track of each of them in distributed topology would be too cumbersome and time consuming. Hence we need a service registry which can keep track of all the services - not only the ones which are newly created but also ones which have been deleted. It allows automatic detection of service instances.

Most significant part of Service discovery is Registry. We will be using Netflix Eureka in this application. With Spring Boot, you can easily build Eureka Registry with spring-cloud-starter-eureka-server dependency, @EnableEurekaServer annotation and simple configuration properties.

spring.cloud.config.uri = http://localhost:8888
spring.application.name = eureka-service

Client support can be enabled with @EnableDiscoveryClient annotation an bootstrap.properties with application name:

spring.cloud.config.uri = http://localhost:8888
spring.application.name = reservation-service

Now, on application startup, Eureka Server will register itself. It also provide meta-data such as host and port, health indicator URL etc. Eureka receives heartbeat messages from each instance belonging to a service. If the heartbeat fails over a configurable timetable, the instance will be removed from the registry.

Important endpoints

Endpoint Description
http://localhost:8761 simple interface, where you can track running services and number of available instances
http://localhost:8761/metrics Provides detailed metric report

API Gateway

For an enterprise application you would want to keep your core domain completely decoupled from its actors (i.e. end user or a service). This is in a way aligning with Hexagonal Architecture where actors which are liable to induce changes within system are not directly dependent on core business domain.

In principle, there will be myriad clients viz. Android app, iOS app, HTML5, IOT device etc who can make requests to each of the microservices directly. But obviously, following Hexagonal Architecture we would certainly not like to expose our core domain i.e. reservation-service directly to these clients. Also each of the clients will have specialized concerns and requirements considering their UI/UX capabilities. So rather than retrofitting core business service for each of the clients it is advisable to set up an Edge service, which is client specific. Key advantage to this approach is - it will act as a single entry point into the system, which will also be used to handle requests for a specific client by routing them to the appropriate backend service or by invoking multiple backend services and aggregating the results

Hence we can set up a micro proxy by enabling it with one @EnableZuulProxy annotation. In this project, we use Zuul to route requests to appropriate microservices. To augment or change the proxy routes, you can add external configuration within application.yml like the following:

zuul:
  routes:
    reservation-client:
        path: /reservations/**
        serviceId: reservation-service
        stripPrefix: false

That means all requests starting with /reservations will be routed to Reservation service.

How does an edge service know, which instance of downstream service to invoke - It does it via client side load balancing using Ribbon whose use within the context of application is explained below.

Ribbon

Ribbon is a client side load balancer which not only gives you a lot of control over the behaviour of HTTP and TCP clients but also implements various load balancing strategies. It in a way has java based implementation which is responsible for doing the lookup via Ribbon Client configurations

Out of the box, it integrates with Spring Cloud and Service Discovery. To include Ribbon in your project use the starter with group org.springframework.cloud and artifact id spring-cloud-starter-ribbon

One can still do a declarative way of doing load balancing explicitly by injecting RestTemplate along with @LoadBalanced annotation. Since this looks like a boiler plate code, it can be avoided by using Feign whose use within the context of application is explained below.

Feign

Feign is a declarative web service / Http client, which seamlessly integrates with Ribbon, Eureka and Hystrix to facilitate resilient load balanced client. So with just spring-cloud-starter-feign dependency and @EnableFeignClients annotation you have a complete set of Load balancer, Circuit breaker and Http client with sensible ready-to-go default configurations.

Here is an example from Reservation Client:

@FeignClient("reservation-service")
interface ReservationReader {
	@RequestMapping(method = RequestMethod.GET, value="/reservations")
	Resources<Reservation> read();
}

Each feign client is part of an ensemble of components ApplicationContext for each named client using FeignClientsConfiguration which contains (amongst other things) a feign.Decoder, a feign.Encoder, and a feign.Contract.

Hystrix

Hystrix is an implementation of Circuit Breaker pattern, which allows to have control over latency and failure of dependencies accessed over the network. In high performing enterprise application, failures are inevitable and hence there has to be mechanisms for gracefully handling them. The main idea is to gracefully handle cascading effect of failures in a distributed environment; With Microservice Architecture this becomes extremely imperative as it helps to fail fast with gracefull degradation - which is a fundamental characteristic of any fault-tolerant systems i.e. They self-heal!

With Hystrix you can add a fallback method that will be executed in case the main command fails.

Moreover, Hystrix generates metrics via /health and this can be used to monitor health of each circuit breaker efficiently. To include the Hystrix Dashboard in our project we have used the starter with group org.springframework.cloud and artifact id spring-cloud-starter-hystrix-dashboard. For running the Hystrix Dashboard annotate your Spring Boot main class with @EnableHystrixDashboard. You then visit /hystrix and point the dashboard to an individual instances /hystrix.stream endpoint in a Hystrix client application. It initiates heart beat stream which comes off from Edge Service

Hystrix Dashboard

Can we achieve similar kind of behavior for insert / update operations? Answer is YES, and hence POC application makes use of RabbitMQ as message broker. Underlying prcinciple is to model our system such that transactions are inter-leavable, such that each of those transaction has compensatory transactions, so that it can be replayed as many times as necessary. This in a way ensures that system remains in semantically consistent state - which is also know as eventual consistency.

This can be implemented using Spring Integration as it uses message channels to connect with different systems via Enterprise Integration Patterns. So in our application we will use Spring Cloud stream which provides a framework for building message driven microservice applications. Implicitly it uses Spring Integration for providing connectivity to underlying message brokers

Zipkin

Considering the fact that there will be myriad set of microservices, distributed tracing becomes an inevitable characteristic of the infrastructure. Distributed tracing in a way will assist us in having better systemic view and observability of system in whole. So Zipkin will ensure that request is traced from one service to another till the response is sent back. We will be using Spring Cloud Sleuth for enabling distributed tracing within our solution.

Zipkin Tracing

Authentication & Authorization

In order to provide Authentication and Authorization, we will be leveraging OAuth2. Spring provides Spring cloud OAuth module via spring-cloud-starter-oauth2 to achieve the same with some pre configured user along with their credentials. As an underlying framework it leverages Spring Security.

How to use this service for accessing Reservation services
  • Send a POST to http://localhost:9191/uaa/oauth/token to fetch access token. Response would look like JSON - Auth Response { "access_token": "f1175786-e525-40d3-8389-fffa133c8d84", "token_type": "bearer", "expires_in": 43199, "scope": "openid"

  • Use above access token whilst invoking read / update Reservation Service i.e.

  • curl -H"authorization: bearer fd3444b6-0e2a-4d54-ab9b-778146b599d5" http://localhost:9999/reservations/names

  • curl -X POST -H "authorization: bearer fd3444b6-0e2a-4d54-ab9b-778146b599d5" -H "Content-Type: application/json" -d "{"reservationName" : "Dr. Jigar Patel"}" http://localhost:9999/reservations

Note

We can remove authentication and authorization module by removing Spring Oauth dependency from Reservation client pom

Microservices Dashboard

Since with Microservices Architecture, an application will have myriad set of services (i.e. > 100). Hence it is quiet important to have bird's eye view of the entire architecture. Thanks to JWorks for providing dashboard application which can provide visual representation of microservices architecture and its ecosystem. Systemic view of microservice can be be mainly categorized into -

  • UI
  • Resources
  • Microservices
  • Backends

It mainly collates information from Spring Boot Actuator health endpoints.

Primarily it comprises of 3 components -

  • Spring Boot Admin Server
  • Spring Boot Admin UI Server
  • Microservices Dashboard Server

Having said that, for our POC application we will be implementing Admin server and Admin UI Server as a single microservice application i.e. Spring Boot Admin and a separate application for Microservices Dashboard. A sample screenshot of Microservice Dasboard for our POC application is as shown below :

Microservice Dashboard

Open for feedback

Feel free to contact me in case of queries or clarifications if any.