Microservices: Klein, aber oho!
Stephan Hochdörfer // 15.10.2015
Über mich
Stephan Hochdörfer
Head of Technology , bitExpert AG Mannheim
S.Hochdoerfer@bitExpert.de
@shochdoerfer
#DevOps, #Automation, #unKonf
Der Fluch des Monolithen
Einschüchternde Codebasis
Komplexer Code der schwer zu verstehen ist, überladene IDE, viele Klassen, viele Methoden, Benennung die
keinen Sinn ergeben
Entwicklung langsam, erhöht die Wahrscheinlichkeit Fehler zu machen (Natur der Sache)
Verhindert dass wir schnell vorhan kommen (Agilität leidet)
Fragiles System
Jede noch so keine Änderung sorgt für einen kompletten Rebuild. Dauert lange (langer Test-Zyklus,
Integrationstests, Deployment)
Hintert uns daran oft Änderungen zu machen und zu deployen! Continious Deployment nicht wirklich
machbar!
Langfristige Verpflichtung
Wir sind an "alte" Technologien gebunden die vor 10 Jahren "aktuell" waren. Schwer neues zu integrieren.
Versuch eines Rewrites?
Den Tech-Stack auszutauschen heißt ein komplettes Rewrite versuchen. Es gibt kein partielles Rewrite und
das Rewrite wird mit ziemlich großer Wahrscheinlichkeit nach hinten los gehen.
Netscape 4 Rewrite - Misslungen (IE hat gewonnen)
Borland dBase - Misslungen (Access hat gewonnen)
Borland Quattro Pro - Misslungen (Excel hat gewonnen)
Die Legacy Wahrheit
Behandle den Legacy Code / den Monolithen mit Respekt: behalte ihn und "modernisiere" ihn langsam nach
und nach.
Die Lösung?
« [...] This is the Unix philosophy: Write programs that do one thing and do it well. »
- Doug McIlroy
Doug McIlroy, inventor of the Unix pipe
Zusammenarbeit
« [...] 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
Was sind 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
Blogpost geschrieben im März 2014
Unternehmen die verstärkt auf Microservices setzen: Amazon, Netflix, Soundcloud, ...
Kleine Problemdomäne
Bounded Context in DDD Sprache
Gleiches Vorgehen dass wir verwenden um Klassen und Methoden zu strukturieren.
Single Responsibility
« A class should have one, and only one, reason to change. » - Robert C. Martin
"Großes Problem" aufsplitten in kleinere Stücke und diese unabhängig davon lösen.
Isolierter Prozess
Nicht ein Applikation-Server auf dem alles läuft, sondern ein Applikation-Server für eine Applikation.
Docker
Docker is an open platform for developers and sysadmins to build, ship, and run distributed
applications.
Microservices Plattform
Alternativen:
https://tsuru.io/
https://flynn.io/
Deployment Automatisierung
Alternatives:
http://deployer.org/
http://rocketeer.autopergamene.eu/
http://kohkimakimoto.github.io/altax/
Build + Deployment isolieren
Sicherstellen dass es beim Bau und Deployment nicht zu Seiteneffekten kommt.
Idealerweise wenige dependencies, idealerweise keine Dependencies unter den Services
Separater Datenspeicher
MySQL, PostgreSQL, NoSQL Datenbank, Dateisystem, ...
Separater Datenspeicher macht das spätere Skalieren viel einfacher.
Einfache Kommunikation
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
Gilt nicht nur für die Logik in den Services, genau so auch für die Datenstrukturen die ausgetauscht
werden
Datenstruktur-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 gilt auch für Datenstrukturen
Datenstruktur-Evolution
{
"id" : 123 ,
"name" : "My Product" ,
"categories" : [{
"id" : 12 ,
"name" : "My category"
}],
"prices" : [{
"price" : 12.34 ,
"currency" : "EUR"
}, {
"price" : 14.26 ,
"currency" : "USD"
}]
}
Vorrausschauend planen / arbeiten. Ähnlich wie bei REST Schnittstellen, ggf. mit Versionierung arbeiten,
kann aber Wartung verkomplizieren!
Bauen, Deployen, Supporten
You build it, you run it!
Keine Trennung zwischen Entwickung und Operations - DevOps. Jeder Micoservice ist anders, benutzt andere
Technologien. Eine zentrale IT Abteilung kann das nicht mehr leisten, auch nicht das permante Deployment
von Entwicklungen durch mehrere Teams.
Warum Microservices?
« Microservices are organised around business capabilities. » - Martin Fowler
Alt: Technologische Trennung bei den Teams (UI team, DBA team)
Neu: Fokus auf Business Prozesse
Observe, Orient, Decide, Act
OODA: Observe - Orient - Decide - Act
Macht jedes Unternehmen, direkt oder indirekt. Je schneller man den Zyklus durchlaufen kann desto größer
ist der Vorteil gegenüber Mitbwerbern. Man lernt schneller was Kunden wollen, wie der Markt aussieht
und ist dadurch entsprechend stärker im Wettbewerb aufgestellt. Unternehmen die den Zyklus durchlaufen
verbesseren die Qualität der Software.
Team Organisation
Fundamentale Wahrheit: Es geht hier nicht um Code, es geht um die Optimierung der Zusammenarbeit.
SW-Architektur und Team Organisation hängen stark zusammen - Conways Law
Any organization that designs a system (defined broadly) will produce a design whose structure is a copy
of the organization's communication structure
Kleine, fokussierte Teams
"Two pizza teams", Jeff Bezos (Amazon)
Mehr Macht den Entwicklern!
Vertraue deinen Entwicklern. Entwickle eine Kultur von Freiheit und Verantwortung, dies wird die
Software verbessern, Deployment-Zeiten minimieren und die Erfolgsrate erhöhen.
Nutze das "passende" Tool...
Backend: Austausch einfacher, da nach "außen" ja nur HTTP Requests / Responses eine Rolle spielen
Frontend: Ggf. schwieriger wenn Frontend-Framework fixe HTML Strukturen vorsieht (bsp. Sencha)
...oder tausche es aus!
Ersetze Tools / Frameworks die nicht so funktionieren wie sie sollen.
Liskov substitution principle
« Derived classes must be substitutable for their base classes. » - Robert C. Martin
Skalierung wird einfacher!
Microservices sind klein, kleine Services sind einfacher zu skalieren als ein großer Monolith.
Einzelne Services können unabhängig von einander skaliert werden!
Entwicklung wird schneller...
...je nach Bedarf!
A/B Testing für Services
Feature toggles
Herausforderungen
« There ain’t no such thing as a free lunch. » - Robert A. Heinlein
Robert A. Heinlein, The Moon Is a Harsh Mistress, 1966
Was heißt denn "klein"?
Microservices, Nanoservices - Größe spielt keine Rolle!
Interface Segregation
« Make fine grained interfaces that are client specific. » - Robert C. Martin
Größe spielt keine Rolle, Funktionalität ist wichtig!
Standardisierung notwendig!
Entwickler haben die Freiheit zu entscheiden wie Services gebaut werden, welche Frameworks, Tools,
Datastores verwendet werden.
Alles andere muss standardistert werden: Deployment, Monitoring/Logging, Fehlerbehandlungen, Errorcodes
Monitoring und Logging
Monitoring und Logging ist wichtiger denn je. Es muss direkt sichtbar sein wenn ein Miroservice ein
Problem verursacht und ich muss nachverfolgen können woher das Problem stammt (Microservice-übergreifend
Logfiles analysieren können!). Wie vieles im Kontext von Microservices ist das nicht einfach und
resultiert in einem komplexeren Setup was die eigene Infrastruktur und das Tooling angeht!
Keine verteilte Transaktionen!
Verteilte Transaktionen verhindern!
Keine kaskadierende Fehler!
Intensiv mit Timeouts und circuit breakers arbeiten um kaskadierende Fehler vermeiden.
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.
Resilience
Port of Nextflix Hystrix to PHP.
Früh und oft releasen!
Don’t let changes build up - release as soon as you can, and preferably one at a time.
Automatisierung FTW!
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 explicitly 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 Beispiel
{
"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' );
Dokumentation FTW!
Änderungen dokumentieren!
API Konsumenten wie Kunden behandeln!
Tools: https://apiblueprint.org, http://swagger.io,
Microservices Beispiel
Microservices Beispiel
{
"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.
Microservices Beispiel
< ?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, ...