Understanding Cloud Native Architecture with an example

Whenever the buzz word ‘Cloud Native Architecture‘ gets to our ears, first thing that comes to our mind is – It sounds too jazzy and latest and would have something to do with technology since it has a word called ‘Architecture‘ within it :). Because of this it creates a perception in the minds of lot of people that ‘Cloud Native Architecture‘ is just about TECHNOLOGY. Unfortunately, this is one of the most common misconception that prevails currently in the industry.

Cloud Native Architecture is mainly about people, mindset and technology. As such there is no hard and fast definition for what exactly Cloud Native means. As per Joe Bida (Founder and contributor of Google Compute Engine and Kubernetes) –

‘Cloud Native Architecture’ is mainly about team structure, culture and technology to utilize automation and architectures to manage complexity and unlock velocity

So one would certainly wonder what exactly it takes to be ‘Cloud Native’?

Matt Stine in his book “Migrating To Cloud-Native Application Architectures” describes about characteristics of cloud native applications –

  • Is a 12-factor application
  • Follows a Microservices architecture
  • Uses self-service agile infrastructure – AKA a Platform-as-a-service
  • Uses API-based collaboration
  • Is anti-fragile

12 Factor Application

This is a methodology for building enterprise applications – generally speaking they are either web apps or SaaS. Twelve Factor apps are built for agility and continuous deployment, enabling continuous delivery and reducing the time and cost for all the stakeholders. At the same time, their architecture is built to exploit the principles of modern cloud platforms. Heroku is considered to be the early protagonist of these guidelines –

  1. Codebase – One codebase tracked in revision control, many deploys
  2. Dependencies – Explicitly declare and isolate dependencies
  3. Configuration – Store configuration in the environment
  4. Backing Services – Treat backing services as attached resources
  5. Build, release, run – Strictly separate build and run stages
  6. Processes – Execute the app as one or more stateless processes
  7. Port binding – Export services via port binding
  8. Concurrency – Scale out via the process model
  9. Disposability – Maximize robustness with fast startup and graceful shutdown
  10. Dev/prod parity – Keep development, staging, and production as similar as possible
  11. Logs – Treat logs as event streams
  12. Admin processes – Run admin/management tasks as one-off processes

These guidelines can be used as a starting point for being ‘cloud native’ and also as a yardstick to evaluate ‘cloud native’ readiness for any monolithic application.

Microservice Architecture

In order to overcome the perils of monolith viz. –

  • Slower release cycles affecting business and market
  • Time spent on regression testing for each new functionality and fix
  • High build and deployment time of application which eventually slows down
  • Handling catastrophic failures without affecting down time of application and user experience
  • Addition of new hardware and resources without incurring additional and unnecessary cost
  • Managing dependencies with minimal impact
  • Ease of developer understanding

it is recommended to move towards Microservices Architecture. I think Martin Fowler and James Lewis describe it best:

“In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API”

Self Service Agile Infrastructure

In order for the team and release to be really Agile, infrastructure also needs to be agile; which can only be achieved with  PaaS. Since we are going to have set of independent services (i.e. application) which will have its own life cycle, it is recommended to have a very streamlined way of providing right infrastructure to these (micro)services – as we are going to have more than 100s of services to be deployed for our application to work. One can leverage various options for PaaS that are available in market viz. Pivotal Cloud Foundry, Amazon Web Service, Microsoft Azure etc.

Uses API based collaboration

With Microservices based approach we are going to have myriad set of services and each of these services will internally collaborate over REST based API contracts. Reason why it is not recommended to go with method based API contracts is that, it will make microservices more invasive in nature and thereby increase inter dependency among them. Also the nature of usage of each of these services might require to have its own hardware and processing capabilities

Is Anti-fragile

For any application, expected uptime is 99.999%, however if we are ready to accept reality than we clearly know that applications are bound to go down and hence they are inevitable – as Googles, Facebooks and Twitters also go down. Most important characteristics of High Available systems is – how gracefully they are able to handle such failures and how quickly they are able to recover. So the architecture (including infrastructure) has to be resilient in nature and has to be implemented by keeping such failures in mind.

Tenets of Cloud Native Architecture

Courtesy – Casey West

So cloud is a platform which manages everything i.e. infrastructure for each service, packaging and deployment of applications, observability of applications sharing key insights on its health, usage etc. So considering technology aspects of ‘Cloud Native Architecture’, it mainly comprises of –

  • Framework
  • Container Runtime
  • Infrastructure Automation

Where is the code honey? 🙂

For all the technologists you may feel – ‘All the guidelines and principles sounds logically cool !‘ 🙂 But can we get to see an example that can help us understand above fundamentals of ‘Cloud Native Architecture‘?

So answer to the above question is YES !

For sake of simplicity we will be just having a single service for Reservation which has following set of services –

Reservation Services

MethodPathDescriptionUser AuthenticatedAvailable from UI
GET/reservations/namesGets entire list of reservations done by userXX
POST/reservations/Creates reservations for a given userX

From functional stand point this is how simplistic the service would look like JHowever, from ‘Cloud Native‘ architectural standpoint, this is how our implementation would span out which includes application services (boxes with bold borders) and infrastructure services (boxes with dotted lines as borders) !

 

 

Technology Stack

It will be an all Spring technology stack that I will be using for implementing the example

  1. Spring Boot
  2. Spring Cloud
  3. Spring Integration

Actual source code of example can be availed at my Github account and detailed information on the implementation along with its brief description can be referred within its README file

Note – The implementation is an as is adaptation from Josh Long‘s session on ‘Cloud Native Java‘ conducted during Spring One Platform 2016 along with some additional infrastructure service in the form of ‘Microservices Dashboard’.

7 thoughts on “Understanding Cloud Native Architecture with an example

  1. With micro services you still didn’t talk about events, circuit breakers and CQRS.
    Doesn’t that complete the micro services macro aspiration? Or is it an add-on?

    1. In the example that I have implemented, instead of events I have used messages (and messaging infrastructure) to realize eventual consistency whenever Reservations are created. Messaging approach has its own limitations, and hence one may resort to Event Store based mechanism which mainly tracks state of Entities and maintain its stream of events. This ensures semantic consistency of application which ultimately helps in making the application eventually consistent.

      Circuit Breaker is already implemented within ReservationClient (snippet of code copied below) –
      public Collection fallback() {
      return new ArrayList<>();
      }

      @HystrixCommand(fallbackMethod = “fallback”)
      @RequestMapping(method = RequestMethod.GET, value = “/names”)
      public Collection names() {
      return this.reservationReader.read()
      .getContent()
      .stream()
      .map(Reservation :: getReservationName)
      .collect(Collectors.toList());
      }

      In principle, circuit breaker needs to be implemented whenever there is inter service communication to ensure graceful handling of failure of dependent services

      CQRS is an architectural pattern within the parlance of DDD and as such Microservice Architecture is realized with DDD (i.e. Bounded Context, Context Map, Sub Domain etc) as fundamental design principle. It can be a candidate for next article 🙂

  2. Nicely written !
    This is what Martin Fowler says about communication between services (https://martinfowler.com/articles/microservices.html):

    “The microservice community favours an alternative approach: smart endpoints and dumb pipes. Applications built from microservices aim to be as decoupled and as cohesive as possible – they own their own domain logic and act more as filters in the classical Unix sense – receiving a request, applying logic as appropriate and producing a response.”

    “In a monolith, the components are executing in-process and communication between them is via either method invocation or function call. The biggest issue in changing a monolith into microservices lies in changing the communication pattern. A naive conversion from in-memory method calls to RPC leads to chatty communications which don’t perform well. Instead you need to replace the fine-grained communication with a coarser -grained approach.”

    1. Thanks Gaurav!
      Very true and hence defining boundaries of microservices with right granularity is the key within Microservice Architecture. Thanks to Eric Evans’s DDD which can be used for identifying them 🙂

  3. Some more:

    “Semantic monitoring can provide an early warning system of something going wrong that triggers development teams to follow up and investigate.
    This is particularly important to a microservices architecture because the microservice preference towards choreography and event collaboration leads to emergent behavior. While many pundits praise the value of serendipitous emergence, the truth is that emergent behavior can sometimes be a bad thing. Monitoring is vital to spot bad emergent behavior quickly so it can be fixed.
    Monoliths can be built to be as transparent as a microservice – in fact, they should be. The difference is that you absolutely need to know when services running in different processes are disconnected. With libraries within the same process this kind of transparency is less likely to be useful.”

    1. Very true and hence in Microservice Architecture, observability is one of the key characteristics. So distributed tracing within Microservice Architecture becomes inevitable and in the example that I have implemented, the same is realized via Zipkin Service

Leave a Reply