Microservices beyond the trench – Monolith – CommandBUS



Microservices beyond the trench – Monolith – CommandBUS

0 0


phptour2016-slides

Conf

On Github Domraider / phptour2016-slides

Microservices beyond the trench

Copier coller le sous titre

  • Etienne Roudeix
  • Vincent Vermersch

Monolith

VV: Un gros serveur HTTP qui gère tout les services Complexe à scaler : sessions, synchro data, un point tombe tout tombe ER: Exemple des enchéres : à heure précise jusqu'à 400 personnes qui rechargent toutes les secondes, pas de cache car les données doivent être à jour en live Grossir à 1000 ou 2000 avec un monolith est compliqué, il nous fallait pouvoir sortir ça

Microservices

IRL

Objectifs

  • Scalabilité
  • Résilience
  • Agilité
  • Transition progressive
On ajoute autant de serveurs que l'on a besoin survis quoi qu'il arrive, pas d'astreintes simple à déployer, mettre à jour et utiliser, minimaliste donc simple à tester et à documenter Et bien sur : transition simple avec l'existant et pouvoir garder des choses sur le monolith
ER: Côté PHP nous avons suivi le design pattern du

CommandBUS

  • Domain oriented
  • Separation of concerns
  • Abstract runtime
@todo peu de de dépendances 1. On gagne une cohérence avec le business 2. Simple à tester, réduit les cas de problèmes 3. Quel que soit où l'on soit on peut passer par là pour éxecuter : HTTP, Console, AMQP, ZMQ .. 4. à quoi ça ressemble, pour une participation à une enchère

Command

							
/**
 * @param float $amount
 * @param string $user_id
 * @param string $auction_id
 */
class AuctionRaiseCommand extends Command {
	public static $handlers = [
  		AddUserToAuction::class,
  		CheckBidAmount::class,
  		NotifyParticipants::class
	];
  	public function __construct(array $attributes = []) {
      	// Validation
  		parent::__construct($attributes);
	}
}
							
						

Handler

							
class AddUserToAuction {
  	protected $auction;
  	public function __construct(AuctionRepository $auction) {
  		$this->auction = $auction;
	}
	public function handle(AuctionRaiseCommand $command) {

	}
}
							
						

Bus

							
$bus = new SimpleBus();
$bus->handle(new AuctionRaiseCommand([
  'user_id'=> '',
  'auction_id'=>'',
  'amount' => ''
]));
							
						
Pour le rendre vraiment magic, les capacités et middlewares VV: Ce qui est bien c'est qu'il peut se transformer simplement via des middlewares, par exemple je veux que ma commande soit rééssayée plus tard si elle plante et qu'elle emette des événements lors de son éxecution

Capacities

							
class AuctionCommand implements RetryOnFail, IsHandledAsynchronously {
	public function getMaxRetry();
  	public function getWorker();
  	public function getRetryDelay($tried);
}
							
						
via des middleware simplement ajoutés au bus

Middleware

							
$bus = new SimpleBus();
$bus->appendMiddleware(new AsynchronousMiddleware());
$bus->appendMiddleware(new RetryOnFailMiddleware());
							
						
Plusieurs librairies dispo des plus simples : tactician et simplebus aux plus complexes : broadway et prooph

Raising

Au final notre processus d'enchère va devenir quelque chose comme ça Client envoit amount, auction et son id api valide, transfert à un worker et répond OK Le worker fait le travail demandé et notify les serveurs de websocket Chaque serveur websocket push à ses clients connectés le changement

Needed communications method

ER : les fléches c'est bien beau mais ça a jamais envoyé de paquet API : fpm donc pas de cnx persistente, délégue au worker qui lui dit OK quand il l'a reçu et peut le traiter Worker : envois aux pusher websocket sans s'occuper de la réception Pusher : envois a tous les navigateurs connectés

Delegate with ack

							
class Worker extends Console {
  protected $signature = 'worker {--bind=tcp://0.0.0.0:25001 listen on}';
  public function handle(Httpd $httpd) {
    $httpd->route('POST', '/', function(Request $request, Response $response) {
      	$response->send("OK")
          ->subscribeCallback(null, null, function() {
    		 SyncBus::handle($request->getCommand());
		  });
    })
    $httpd->listen($this->option('bind'));
  }
}
							
						
Plusieurs librairies dispo des plus simples : tactician et simplebus aux plus complexes : broadway et prooph

Push on worker

							
$push = $zmq->push("tcp://pusher.svc.domraider.com:23499");
$push->send(new AuctionRaisedEvent());
							
						

Pull on pusher

							
$pull = $zmq->pull("tcp://0.0.0.0:23499");
$pull->subscribeCallback(function(AuctionRaisedEvent $event) {
	foreach($this->webSocket->sessions as $session) {
  		$session->send($event);
	}
});
							
						
et pour la websocket allez voir thruway :)
Avantages : tout est au minimum doublé, résilience assurée. La charge s'allége grace aux websocket la mise à jour est plus rapide vv: Au total ces petits services deviennent nombreux, actuellement nous en avons 63 qui tournent en production, ce qui représente presque 400 process, les workers gèrent en moyenne 4k commandes par minute gérer un monolith de quelques vm c'est déjà du boulot alors 63 services sans aide c'est impossible
https://www.youtube.com/watch?v=9C6YeyyUUmI ou rancher ou swarn disponible openshift, google container engine

Orchestration et supervision

Gère la distribution des services et de leur réplicas limite de 1000 nodes si un service tombe le redémarre, si une machine tombe cherche une autre machine qui correspond lifeprobe pour vérifier que le pod tourne bien

Routing

  • Each pod has its own unique ip address
  • Each service has it's own unique dns entry (ttl <1s)
  • Service can load balance and manage failover
Mean no port problems, same host can use a lot of port 80 easy to address message to a service

scale

							
kubectl scale --replicas=5 rc AuctionWorker
							
						

Rolling update

  • Start a new pod with the new version
  • Wait for start to complete
  • Stop one pod from previous version
  • Continue until new version for all pods
Pareil pour revenir en arrière. Pendant un court instant les deux versions peuvent fonctionner ensemble
Le mariage sert à régler des problèmes que l'on aurait jamais eu si on était resté tout seul.

Sasha Gitry

Centralise Logs and bugs

L'enchère que l'on a vu tout à l'heure aura pu s'executer sur 3 machines, si je doit suivre sa trace en explorant les machines ça peut être long graylog, ou plein de services payants Sentry

Automate builds

							
composer install
cp docker/worker/Dockerfile .
cp docker/worker/.dockerignore .
docker build -t worker:$version .
docker tag latest worker:$version
docker push worker:$version
docker push worker:latest
							
						
Un codebase donne x builds dockers qui vont donner eux mêmes y replication controller dans kubernetes Besoin d'un build automatisé avec versionning une image docker par version, le build ne donne pas forcément lieu à un déploiement jenkins docker , circle ci

Monitor And alert

Besoin de comprendre ce qui se passe sur un service comme sur une machine, et d'être alerté quand quelque chose se passe mal Alertes métiers comme techniques InfluxDB et grafana, Tick, Prometheus : ou datadog
l'architecture ne résoud pas tous les problèmes, besoin d'avoir la compréhension complète du service et de ses problèmes avant de passer au microservice. Evolution très rapide des solutions sur lesquelles on travaille Les merdes sont plus simples à gérés (plus isolées) Coût pour rentrer dedans : docker, kubernetes, le pattern du command bus, des librairies matures de communication en PHP (ZMQ top, mais pas top en serveur HTTP), le travail en event (React, EV) Scalabilité et agilité au top, résilience on a encore des downtimes (même si résolu automatiquement) encore du monolith temps d'intégration d'un nouveau dev simple

RTFM

We hire

@Clermont Ferrand

image clermont ?