Develop microservices
in PHP

by Enrico Zimuel
Senior Software Engineer
Rogue Wave Software Inc.


Codemotion 2018, Milan (Italy), 30th Nov

About me

Book: Sviluppare in PHP 7


www.sviluppareinphp7.it

pp. 352, Tecniche Nuove, 2017
ISBN 978-88-481-3120-9

in Italian

Microservice

...the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API

- Martin Fowler

Source: Introduction to microservices

Source: Introduction to microservices

Benefit

  • Separation of concerns
    • Modularity
    • Encapsulation
  • Scalability
    • Horizontally scaling
    • Workload partitioning

Cons

  • Network latency
  • Debugging
  • New architecture challenges:
    • Autodiscovery
    • Telemetry
    • Everything needs to be automated

PHP

Microservices in PHP

  • PHP is easy to deploy
  • PHP 7 is super fast!
  • Big community
  • Libraries/Frameworks
  • Async in PHP (Swoole, ReactPHP, ...)

The PHP framework for middleware applications

  • PSR-7 support (using zend-diactoros)
  • PSR-15 support and piping workflow (using zend-stratigility)
  • Features: routing, dependency injection, templating, error handling
  • Support of Swoole out-of-the-box

A basic web API


use Zend\Diactoros\Response\JsonResponse;
use Zend\Expressive\Application;

$container = require 'config/container.php';

$app = $container->get(Application::class);
$app->pipe('/api/ping', function($request) {
    return new JsonResponse(['ack' => time()]);
});
// $app->pipe('/api/ping', \App\Handler\PingHandler::class);
$app->run();

Request Handler


use Psr\Http\Message\ResponseInterface as Response; // PSR-7
use Psr\Http\Message\ServerRequestInterface as Request; // PSR-7
use Psr\Http\Server\RequestHandlerInterface as Handler; // PSR-15
use Zend\Diactoros\Response\JsonResponse;

class PingHandler implements Handler
{
    public function handle(Request $request) : Response
    {
        return new JsonResponse(['ack' => time()]);
    }
}

Middleware

Middleware

Example: Authentication


use Psr\Http\Server\MiddlewareInterface; // PSR-15

class AuthMiddleware implements MiddlewareInterface
{
  public function process(Request $request, Handler $handler): Response
  {
    $user = $this->auth->authenticate($request);
    if (null !== $user) {
      return $handler->handle($request->withAttribute(
        UserInterface::class,
        $user
      ));
    }
    return $this->auth->unauthorizedResponse($request);
  }
}

Example: Routing REST API


$app->route('/api/users[/{id}]', [
    Authentication\AuthenticationMiddleware::class,
    Authorization\AuthorizationMiddleware::class,
    Api\Action\UserAction::class
], ['GET', 'POST', 'PATCH', 'DELETE'], 'api.users');

// or route each HTTP method
$app->get('/api/users[/{id}]', ..., 'api.users.get');
$app->post('/api/users', ..., 'api.users.post');
$app->patch('/api/users/{id}', ..., 'api.users.patch');
$app->delete('/api/users/{id}', ..., 'api.users.delete');

Quick start

You can start using Expressive with composer:

composer create-project zendframework/zend-expressive-skeleton <dir>

Libraries for API

Swoole

  • Swoole is an async programming framework for PHP 7
  • PHP extension, install:
    
    pecl install swoole
    
  • Released under Apache license 2.0
  • More info at swoole.co.uk

Features

  • Event-driven, asynchronous programming for PHP
  • Async TCP / UDP / HTTP / Websocket / HTTP2 client/server side API
  • IPv4 / IPv6 / Unixsocket / TCP/ UDP and SSL / TLS support
  • High performance and scalable
  • Fast serializer / unserializer
  • Milliseconds task scheduler

Swoole vs. PHP-FPM

  • Forks a number of worker processes based on CPU core number
  • Fupports Long-live connections
  • Manage and reuse the status in memory
  • Executes Non-blocking code (async, coroutine)

HTTP Server


use Swoole\Http\Server;

$http = new Server("127.0.0.1", 9501);

$http->on("start", function ($server) {
    echo "Started at http://127.0.0.1:9501\n";
});
$http->on("request", function ($request, $response) {
    $response->header("Content-Type", "text/plain");
    $response->end("Hello World\n");
});

$http->start();

Test: 16K req/sec on CPU i5-2500, 16 GB RAM, PHP 7.2.12, Swoole 4.2.9

Expressive with Swoole

Install:


composer require zendframework/zend-expressive-swoole

Usage:


vendor/bin/zend-expressive-swoole start

Open your browser at localhost:8080

PHP + Expressive + Swoole

Run a web application from CLI

Simplify the deploy (only 1 container)

A web server (nginx) can be used as load balancer

Benchmark

2-4x faster than Nginx and Apache

Req/sec (mean)
Nginx 1418.23
Apache 1915.62
Swoole 4864.34

Testing environment:
Ubuntu 18.04, Expressive Skeleton 3.2.3, PHP 7.2.12, Nginx 1.14 + FPM,
Apache 2.4.29 + mod_php, Swoole 4.2.9, CPU i5-2500, 16 GB RAM, HD SSD

References

Thanks!

Contact me: enrico.zimuel (at) roguewave.com

Follow me: @ezimuel



Creative Commons License
This work is licensed under a
Creative Commons Attribution-ShareAlike 3.0 Unported License.
I used reveal.js to make this presentation.