Microservices: Packs small, plays BIG!
Stephan Hochdörfer // 24.01.2015
About me
Stephan Hochdörfer
Head of Technology , bitExpert AG (Mannheim, Germany)
S.Hochdoerfer@bitExpert.de
@shochdoerfer
#PHP, #DevOps, #Automation
The curse of the monolith
Intimidating "old" codebase
Complex code is hard to understand; overloaded IDE, development slowes down
Increases the likelyhood to make errors
Does not allow us to move fast (agile)
Small change, big impact
Every single small change needs a full rebuild. Takes a long time (Long test cycle, long deployment phase).
Obstacle for frequent changes and deployments. No continious deployment!
Long-term commitment
Commitment to an "old technology". Hard to bring in the "new stuff".
What about a rewrite?
Changing the tech stack implies a complete rewrite. There`s no partial rewrite. Rewrite will fail.
Netscape 4 Rewrite - Fail (IE won)
Borland dBase - Fail (Access won)
Borland Quattro Pro - Fail (Excel won)
Microsoft always won (because they made no real rewrites - or at least not with the whole team)
The legacy truth
Treat it with respect: Keep it and "modernize" it in the best possible way.
The solution?
« [...] This is the Unix philosophy: Write programs that do one thing and do it well. » - Doug McIlroy
Doug McIlroy, inventor of the Unix pipe
Programs need to cooperate
« [...] Write programs to work together. Write programs to handle text streams, because that is a universal interface. » - Doug McIlroy
Doug McIlroy, inventor of the Unix pipe
What are Microservices?
« [...] approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms. » - James Lewis, Martin Fowler
Small problem domain
Bounded Context in DDD terms
The same way we do it when structuring classes or methods.
Single Responsibility
« A class should have one, and only one, reason to change. » - Robert C. Martin
We split a "big problem" into smaler parts and solve them independently.
"Isolated process"
Docker
Docker is an open platform for developers and sysadmins to build, ship, and run distributed applications.
Microservices platform
Alternatives:
https://tsuru.io/
https://flynn.io/
Deployment Automation
Alternatives:
http://deployer.org/
http://rocketeer.autopergamene.eu/
http://kohkimakimoto.github.io/altax/
Built and deployed in isolation
Owns its data storage
MySQL, PostgreSQL, NoSQL database, Filesystem, ...
Own datastore makes it easier to scale.
Simple communication layer
Standardized protocols, e.g HTTP
Smart endpoints, dumb pipes
« Be of the web, not behind the web. » - Ian Robinson
SOA: Dump endpoints and smart pipes
Open/closed principle
« You should be able to extend a classes behavior, without modifying it. » - Robert C. Martin
Counts for the service logic as well the as data structures used for request and response.
JSON extensibility could be a problem, XML might be a better solution
Data structures evolution
{
"id" : 123 ,
"name" : "My Product" ,
"categories" : [{
"id" : 12 ,
"name" : "My category"
}],
"price" : 12.34
"currency" : "EUR"
}
{
"id" : 123 ,
"name" : "My Product" ,
"categories" : [{
"id" : 12 ,
"name" : "My category"
}],
"price" : [ 12.34 , 14.26 ]
"currency" : [ "EUR" , "USD" ]
}
Open/closed principle applies also for your datastructures!
Data structures evolution
{
"id" : 123 ,
"name" : "My Product" ,
"categories" : [{
"id" : 12 ,
"name" : "My category"
}],
"prices" : [{
"price" : 12.34 ,
"currency" : "EUR"
}, {
"price" : 14.26 ,
"currency" : "USD"
}]
}
Open/closed principle applies also for your datastructures! Plan ahead!
You build it, you own it
With microservices, the old IT mindset just doesn't work. Each microservice is different, and unique skillsets are required to understand, manage, and deploy them. A centralized IT department cannot possibly cover the wide array of technologies spanning all microservices.
Why Microservices?
« Microservices are organised around business capabilities. » - Martin Fowler
Old: Focus on technolgy (UI team, DBA team)
New: Focus on business capabilities (inventory management, ...)
The OODA loop
OODA: Observe - Orient - Decide - Act
The faster you can get around this loop, the faster you learn something new about your customer and the market, the more agile and competitive you get. Enterprises that do this often find improvement in quality of their products and their ability to learn.
Team organization
Fundamental truth: It`s not about code, it`s about working together.
Microservices is much more about about team organization rather than software architecture. Architecture and team organization is always heavily coupled together.
Small Focused Teams
"Two pizza teams", Jeff Bezos (Amazon)
http://99u.com/articles/7255/the-jeff-bezos-school-of-long-term-thinking
Empower developers
Trusting developers, and promoting a culture of freedom with responsibility reduces software delivery times and increases success rates.
Pick the right tool for the job
Replace it if it does not work
Replace your service if it does not work
Liskov substitution principle
« Derived classes must be substitutable for their base classes. » - Robert C. Martin
Easy scaling
Microservices are small. Small services are easier to scale than a monolith.
Increase development speed
...but choose a healthy pace!
Try out new ideas...
Microservices Challenges
« There ain’t no such thing as a free lunch. » - Robert A. Heinlein
Robert A. Heinlein, The Moon Is a Harsh Mistress, 1966
What does "small" mean?
Microservices, Nanoservices - size not matter.
Interface Segregation
« Make fine grained interfaces that are client specific. » - Robert C. Martin
Size does not matter, functionality does.
Standardise in between
Standardize deployment, monitoring/logging, interfaces, error handling
Standardise in the gaps between services - be flexible about what happens inside the boxes.
Monitoring and Logging
Microservices monitoring must be instantly responsive, able to detect failure or situations requiring rollback, in seconds, and must be completely automated, no human intervention required at any time. The tooling must enable this, provisioning agent-based logging and allowing services to be deployed with all monitoring hooks and logging facilities prewired and ready to go. As with most things microservices-related, doing this correctly results in more complexity and overhead in the tooling.
Avoid distributed transactions
Avoid distributed transactions if at all possible.
Avoid cascading failures
Use timeouts, circuit breakers and bulk-heads to avoid cascading failure.
Design for failure
Chaos Monkey - Randomly terminates one of the systems in a group
Janitor Monkey - Clean up AWS instances
Conformity Monkey - Looks for instances that are not conforming to predefined rules for the best practices.
Release early, release often!
Don’t let changes build up - release as soon as you can, and preferably one at a time.
Automate all the things!
Automation is the glue that holds everything together.
In a world where microservices come and go, grow and shrink, and migrate around racks and data centers in seconds - there's absolutely no room for manual intervention. All aspects of deployment, monitoring, testing, and recovery must be fully automated. For example, monitoring a service should occur instantly and automatically by virtue of it being deployed, not requiring a separate manual step.
Dependency Inversion
« Depend on abstractions, not on concretions. » - Robert C. Martin
Lookup services to not explictily communicate with a specific instance!
Service Discovery
Service discovery and configuration made easy. Distributed, highly available and datacenter aware.
Service Discovery (e.g. mysql, web), Key/Value Store for application configuration.
Service Discovery Example
{
"require" : {
"sensiolabs/consul-php-sdk" : "1.0.*@dev"
}
}
< ?php
require_once __DIR__. '/vendor/autoload.php' ;
$sf = new SensioLabs\Consul\ServiceFactory ();
$kv = $sf -> get ( 'kv' );
$kv -> put ( 'test/foo/bar' , 'bazinga' );
$kv -> get ( 'test/foo/bar' , [ 'raw' => true]);
$kv -> delete ( 'test/foo/bar' );
Document your APIs!
Document your changes!
Treat your API consumers as customers!
Tools: https://apiblueprint.org, http://swagger.io,
Microservice Example
Microservice Example
{
"require" : {
"silex/silex" : "~1.2@stable"
}
}
< ?php
require_once __DIR__. '/vendor/autoload.php' ;
$app = new Silex\Application ();
$app -> register ( new MyApp\Service\SearchServiceProvider ());
$app -> get ( '/search/{term}' , function ( $term ) use ( $app ) {
$result = $app [ 'search' ]-> search ( $term );
return $app -> json ( $result );
});
$app -> run ();
Acts as an abstraction for 3rd party services using search. Does not matter if in the first place a PostgreSQL database with full-text search capabilities is used or later on elasticsearch. The "interface" stays the same. Makes things easier to change.
Composing your microservice
The idea is that the HTTP request is passed to a callable which returns a HTTP response. You compose these in a number of ways to build an application.
Microservice Example
< ?php
require_once __DIR__. '/vendor/autoload.php' ;
$app = new Silex\Application ();
$app -> register ( new MyApp\Service\SearchServiceProvider ());
$app -> get ( '/search/{term}' , function ( $term ) use ( $app ) {
$result = $app [ 'search' ]-> search ( $term );
return $app -> json ( $result );
});
$app = new Alsar\Stack\IpRestrict ( $app , [ '127.0.0.1' ]);
$app -> run ();
Quite a few middlewares available: HttpCache, OAuth, Basic Auth, CORS, CookieGuard, ...