Yielding higher-performance php

Ian Littman / @iansltx

php[tek] 2016

http://ian.im/tek16yield

We'll cover

  • FastCGI vs. no-FastCGI
  • Generators
    • In general
    • As coroutines
  • Event Loop Concepts
  • Raphple Four Ways
    • Standard Slim 3
    • Slim 3 + PHPFastCGI
    • Icicle
    • Aerys (AMPHP)
  • Demo + benchmarks!

We Won't Cover

  • Multiprocess options
  • "Clean" benchmarks
  • Other non-FastCGI servers
    • ReactPHP
    • php -S
    • mod_php

Story TIme

Standard nginx/FPM Request Model

Client (or Load Balancer)

Web Server (nginx)

FastCGI Daemon (php-fpm)

HTTP

FastCGI

Pros

  • Common
  • Safe
  • Multicore
  • Shared-nothing
  • Fast for static resources
  • Library support
    • Slim\Http Req\Res
    • Aura.Sql
  • Don't worry (much) about blocking the thread

Cons

  • No in-request parallelism
  • Could be faster
  • Not 12-factor
    • Process manager (runit)
    • nginx
    • php-fpm

Demo time: Basic App

nginx/phpfastcgidaemon Request Model

Client (or Load Balancer)

Web Server (nginx)

FastCGI Daemon (php-fastcgidaemon)

HTTP

FastCGI

Pros

  • Relatively few code changes
    • One line in index.php
    • Use RequestInterface
  • No per-req bootstrap time

Cons

  • Fragile (less so in PHP 7)
  • Single-threaded
  • Have to refactor requests
  • No async stuff
  • Still not 12-factor
    • Process manager (runit)
    • nginx
    • php CLI

Demo Time: PHPFASTCGIDAEMON

What about yielding?

Event Loops!

Important: Don't block the loop!

  • Async I/O
  • Don't do too much computation at one time

Event Loop Interaction Methods

  • Callbacks
  • Promises
  • Generators

Generators

  • Easier to follow
  • Less used/familiar
  • Cleaner exceptions
  • Cleaner message passing

Callbacks/Promises

  • Hard to follow execution flow
  • Very common
  • Error callback convention
  • Messages at function borders

What's a Generator?

  • Resumable function
  • Uses yield rather than (or in addition to) return
  • Values and Exceptions can be sent/thrown in
  • Incremental, iterable results
  • Behaves a bit like an Iterator

NoteS

If you call a function that yields, you will not execute that function. You'll get back a generator. To execute the function, you (or the event loop) will interact with that generator.

 

Also, "return" means something different for a generator than for a normal function. The yield keyword changes everything.

A Visual Example

Generator

Parent

$g = gen(1);

$a = $g->current();

2

$b = yield $arg1 + 1;

$c = $g->send($a + 1);

$d = yield $b + 2;

5

3

function gen($arg1)

$e = $g->send($c + 1);

6

return $d + 2;

null

echo $g->getReturn();

8

Yield From Flattens Stacked Generators

PHP < 7 Notes

  • Still have generators (>= 5.5)
  • No returning values in a generator
  • No generator delegation (yield from)

Using generators as coroutines

  • Generator::send(): emulate synchronous returns
  • Yield: stop execution until you get back a result
  • Yield from: stop execution until called generator is done
  • Return: use just like normal (PHP 7 only!)

Generators in an Event Loop

  1. Run until blocking I/O
  2. Yield promise representing blocking I/O
  3. Event loop skips coroutine until promise is resolved
  4. Event loop send()s promise result to coroutine
  5. Repeat from 1 until coroutine is complete (return)

Icicle Request Model

Client (or Load Balancer)

Application Server (PHP + Icicle)

HTTP

Look ma, twelve factor app!

Pros

  • No per-req bootstrap time
  • Fewer moving parts (12F app)
  • Async execution
  • Generator based (!pyramid)

Cons

  • Fragile (less so in PHP 7)
  • Single-threaded
  • Plenty to refactor
  • No async database access*

Demo Time: Icicle

Event Loop Extensions

  • Not required, but highly recommended
  • ev
  • php-uv (PHP 7)

Amphp/Aerys Request Model

Client (or Load Balancer)

Application Server (PHP 7 + Aerys)

HTTP

Pros

  • No per-req bootstrap time
  • Fewer moving parts (12F app)
  • Async execution
  • Generator based (!pyramid)
  • Async database access
  • Fast!

Cons

  • PHP 7 only
  • A little fragile
  • Requires host/port match
  • Single-threaded
  • Plenty to refactor

Demo Time: Aerys

Thanks! Questions?