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
cominghere! - Grails 3 plays well in a microservice architecture
- Building a microservice federation with Grails
Demo
Microservices are here
- 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
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
- Solid domain understanding
- Development more complicated
- More builds
- More databases
- Log aggregation is essential
- Metrics, monitoring & more essential
Microservice Architecture Disadvantages
http://martinfowler.com/bliki/images/microservicePrerequisites/sketch.png
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
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')
}
}
Restfully create a Person...
... yields a 201 created response
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
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.
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
}
}
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.
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.
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
With an IDE...
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.
Building a Grails microservice federation
Demo
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 Product 1 Using Zuul
Finding Product 3 Using Zuul
This is the default after error in recommendation engine
Finding Products Using Zuul
Hystrix Dashboard
Hystrix Dashboard
Hystrix Dashboard
Hystrix Dashboard
Hystrix Dashboard
... After killing recommendation engine ...
Microservice Setup
@HystrixCommand
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?
NFJS Building a Microservice Federation with Grails
By Jack Frosch
NFJS Building a Microservice Federation with Grails
- 1,888