Building a Microservice Federation with Grails

Grails... microservices...

you must be crazy man!

About me

20 years Java

10+ years Spring

6+ years Groovy/Grails

PowerBuilder

C/C++

FORTRAN

1st career in aviation/aerospace

twitter: @jackfrosch                          linkedin: ../in/jackfrosch

email: jackfrosch@gmail.com         grails.slack.com: @jackfrosch

{ "about-me" :  

  { "experience" :  [ "20 years Java", 

                                  "6+ years Groovy/Grails",

                                  "PowerBuilder, C/C++, FORTRAN"

                                  "Aviation/Aerospace before Software Development"],

    "community" : [ "Gateway JUG founder and leader",

                                 "Past DFW GGUG Co-leader",

                                 "Always cookin' up something ..."],

    "contacts"      : [ {"twitter" : "@jackfrosch"}, 

                                 {"linkedin" : "../in/jackfrosch"},

                                 {"email" : "jackfrosch@gmail.com"},

                                 {"grails.slack.com":"@jackfrosch"}]

  } 

}

The Story I'm About to Tell You is True

  • Microservices are coming!
  • Grails plays well in a microservice architecture
  • Building a microservice federation with Grails

Demo

Microservices are coming

  • Foundational concepts
  • Microservice advantages
  • Microservice disadvantages

What are microservices?

Microservices are small, autonomous services that work together.

Sam Newman Building Microservices, O'Reilly Media

Small is key

Small in functional scope...

http://www.whattofix.com/images/ComplexERDExample.gif

Probably not small functional scope...

... not necesarily size

Smaller is simpler

Everything should be made as simple as possible, but not simpler*

* though attributed to Einstein, this simple quote is actually from 
Roger Sessions paraphrasing (and simplifying!) a statement by Albert Einstein

Simpler is better

A system that is hard to understand is hard to change.

— Eric Evans, Domain-Driven Design

Autonomy is key

Development autonomy*

*Caveat: You can't break my stuff

http://www.memes.com/meme/498049

Consumer Driven Contracts

http://bit.ly/thoughtworks-consumer-driven-contracts

Testing: How much & what kind?

http://famouswonders.com/wp-content/gallery/pyramids-of-egypt/pyramid-of-khafre.jpg

Data Autonomy

http://martinfowler.com/articles/microservices.html

Build/Deploy autonomy

http://www.openmakesoftware.com/images/ReleaseEngineer/CI-CD.png

Scale where the load is...

Operational Autonomy

https://media.licdn.com/mpr/mpr/p/8/005/083/1a8/257d716.jpg

All this sounds great, but...

...what about our monolith?

Identify bounded contexts...

... and divide along the seams

Favor choreography over orchestration

http://kennysilva.net/wp-content/uploads/2010/12/orchestra-conductor.jpg

Monolith

Microservice

class Passenger {
   String        accountNo
   String        firstName
   String        lastName
   Address       billingAddress
   Payment       paymentPreference
   List<Payment> paymentHistory
   Phone         home
   Phone         mobile
   Phone         work
   BloodType     bloodType
   ...
}
   

What about shared domain?

// For Trip Management
class Passenger {
   String accountNo
   String firstName
   String lastName
   Phone  mobile
   ...
}
   
// For Billing
class Passenger {
   String        accountNo
   String        firstName
   String        lastName
   Address       billingAddress
   List<Payment> paymentHistory
   Phone         home
   Phone         work
   ...
}
   

The evils of too much coupling between services are far worse than the problems caused by code duplication.

- Sam Newman, Building Microservices

Microservice Federation

  • Logging
  • Security
  • Metrics and monitoring

First, what's a federation?

an organization that is made by loosely joining together smaller organizations

http://www.merriam-webster.com/dictionary/federation

the formation of a political unity, with a central government, by a number of separate states, each of which retains control of its own internal affairs.

http://dictionary.reference.com/browse/federation

In our terms: The formation of an application, with central governance of common infrastructure concerns, by a number of separate microservices, each of which retains control of its own internal design and implementation.

Real world examples

The advancement and diffusion of knowledge is the only guardian of true liberty.

- James Madison, father of the US Constitution

Knowledge is power

Logging Tips

  • Use a Correlation ID
  • Use a consistent log message format
  • Use log aggregation

Logging Aggregators

"ELK Stack"

Security

  • None
  • At the gateway only
  • At every microservice

Security at the gateway only

"They're inside the room!"

"Yikes!"

"Mmm, you look tasty."

Perimeter security reminds me of the movie, Aliens

Security at every microservice

Metrics, Monitoring & More

  • Microservices need to report metrics
  • Resiliency requires monitoring & circuit breakers
  • Automatic service discovery
  • Gateway / reverse proxy
  • Load balancing

Spring Boot & Spring Cloud to the rescue!

Spring Boot includes metrics endpoint

There are many metrics out of the box, but you can create your own.

http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html

Spring Boot includes many endpoints

http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html

Spring Cloud provides monitoring
... and much more

Service discovery with Eureka

Gateway /Rev Proxy with Zuul

http://bit.ly/vignette2_wikia_nocookie_net_ghostbusters

Gateway /Rev Proxy with Zuul

Monitoring & Circuit Breakers w/ Hystrix

http://martinfowler.com/bliki/CircuitBreaker.html

Microservice Architecture Advantages

  • Scalable
  • Adaptable
  • Resilient
  • Testable
  • More future-proof
  • More greenfield

Microservice Architecture Disadvantages

http://martinfowler.com/bliki/images/microservicePrerequisites/sketch.png

Microservice Architecture Disadvantages

  • Solid domain understanding
  • Development more complicated
  • More builds
  • More databases
  • Log aggregation is essential
  • Metrics, monitoring & more essential

Grails plays well

  • Grails full stack development
  • Grails REST
  • Grails plugin architecture

Full stack != monolith

Grails full stack development

Web UI, SQL / NOSQL Database Support, Spring, Hibernate, Security, REST, Java, Groovy...

Create App

$grails create-app HelloWorld

Hello World app... easy as 1 - 2 - 3

grails> create-controller demo.Hello
package demo

class HelloController {

    def index() { 
        render 'Hello SpringOne2GX 2015!'
    }
}

Full stack CRUD apps are about as easy...

1. Create controller

2. Make it do something

3. See it to believe it!

Create a Domain Class

Define demo.Person

package demo

class Person {
    String firstName
    String lastName
    String email
    String twitterHandle

    static constraints = {
        firstName blank:false, maxSize: 32
        lastName blank: false, maxSize: 64
        email blank: false, maxSize: 128, email:true
        twitterHandle nullable:true, maxSize:64
    }
}

Generate Scaffolding...

.. to bootstrap CRUD app

After generation

Run App

grails> run-app

Retrieve Persons List

Create Person form

Create a Person record

Show a Person record

Retrieve Persons List

Delete a Person record

Test Rest

$ curl -i -X GET http://localhost:8080/persons

[jfrosch@localhost demo]$ HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Content-Type: text/xml;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 07 Sep 2015 21:26:16 GMT

<?xml version="1.0" encoding="UTF-8"?><list />

$

Hmm... 200 OK good ... XML bad.

With an IDE...

Besides UI CRUD, what about REST?

package demo

import grails.rest.Resource

@Resource(uri='/persons')
class Person {
    String firstName
    String lastName
    String email
    String twitterHandle

    static constraints = {
        firstName blank:false, maxSize: 32
        lastName blank: false, maxSize: 64
        email blank: false, maxSize: 128, email:true
        twitterHandle nullable:true, maxSize:64
    }
}
grails create-app RestfulCrud

Grails content negotiation

$ curl -i -X GET http://localhost:8080/persons.json

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Content-Type: text/xml;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 07 Sep 2015 21:26:16 GMT

[]

$

200 OK good ... JSON good.

Grails content negotiation

$ curl -i -X GET --header "Accept:application/json" http://localhost:8080/persons

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Content-Type: text/xml;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 07 Sep 2015 21:26:16 GMT

[]

$

200 OK good ... JSON good.

Change @Resource to prefer JSON

package demo

import grails.rest.Resource

@Resource(uri='/persons', formats=['json', 'xml'])
class Person {
    String firstName
    String lastName
    String email
    String twitterHandle

    static constraints = {
        firstName blank:false, maxSize: 32
        lastName blank: false, maxSize: 64
        email blank: false, maxSize: 128, email:true
        twitterHandle nullable:true, maxSize:64
    }
}

Test Rest

$ curl -i -X GET http://localhost:8080/persons

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Content-Type: text/xml;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 07 Sep 2015 21:26:16 GMT

[]

$

200 OK good ... JSON good.

Test Rest

$ curl -i -X GET http://localhost:8080/persons.xml

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Content-Type: text/xml;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 07 Sep 2015 21:26:16 GMT

<?xml version="1.0" encoding="UTF-8"?><list />

$

200 OK good ... XML weird, but you wanted weird

Restfully create a Person...

... yields a 201 created response

Grails REST URI patterns

What if I want to do more than CRUD?

package demo

import grails.rest.RestfulController

class PersonController extends RestfulController<Person> {
    static responseFormats =['json', 'xml']

    PersonController() {
        super(Person)
    }

    def findPersonsWithLastNameLike(String likeness) {
        respond Person.findByLastNameLike("${likeness}%")
    }
}
class UrlMappings {

    static mappings = {
        "/persons"(resources:'person')

        "/persons/search/withLastNameLike/$likeness"(controller: 'person', 
                                                     action: 'findPersonsWithLastNameLike')
    }
}

Building a Grails microservice federation

Build a Eureka Server

Build a Eureka Server

Build a Zuul Server

/catalog acts as the root of the uri

Build a Zuul Server

Zuul Mappings

Finding Products Using Zuul

Finding Product 1 Using Zuul

Finding Product 3 Using Zuul

This is the default after error in recommendation engine

Hystrix Dashboard

Hystrix Dashboard

Hystrix Dashboard

Hystrix Dashboard

Hystrix Dashboard

... After killing recommendation engine ...

@HystrixCommand

Microservice Setup

Microservice Setup

Summary

  • Adaptable
  • Scalable
  • Resilient
  • Maintainable
  • Monitorable
  • Cloud ready

You'd be crazy to adopt a microservice architecture using Grails...

unless your application needs to be ...

 (even if your company isn't ready for the cloud yet)

Resources

  • http://projects.spring.io/spring-cloud/
  • http://cloud.spring.io/spring-cloud-netflix/
  • http://martinfowler.com/articles/microservices.html

Questions?