Client | Customer | |
---|---|---|
Server | Restaurant | |
Request | Order | |
Response | Food | |
Application | Chef | |
HTTP Daemon | Waiter/Waitress | |
Customer enters restaurant | ||
Waitress takes order | ||
Waitress creates chef and gives order | ||
Chef makes food | ||
Waitress gives food to customer | ||
Waitress brutally murders chef | ||
Don't kill the chef
What if our chef gets ill?
Kill the chefs before they have a chance to get ill
Use a better chef
What can cause our chef to get ill?
Chef never forgets some of the meals they have made
Chef can only remember so much
Chef's head explodes
Remove references to unrequired objects
Chef forgets how to use oven after a couple of hours
Chef needs oven
ERROR 2006: MySQL server has gone away
Chef encounters minor issue
Chef throws big tantrum
Distinguish between request errors and application errors
Let the application die if recovery is not possible
Chef brainwashed by evil customer
Chef tricked into poisoning other customers
Think like an attacker
Avoid static and global memory
Restaurant owner wants Chef with new recipes
Chef is pretty set in their ways
Restaurant owner forgets to kill old Chef
Chef keeps serving up old recipes
Remember to kill old Chef(s)
Leaving behind our restaurant...
CGI application must be executable by the web server
One instance of our application per request
HTTP request provided via environment variables
HTTP response written to standard output by application
Back in the day...
when I was 3
PHP was just a set of CGI binaries
We can still integrate PHP using CGI
We can also use native web server modules
We can also use PHP-FPM
PHP FastCGI Process manager
Like CGI... but faster
Wrap our communication in a protocol
Implement this protocol over a socket connection
Keep our application alive between requests!
Keeps the PHP interpreter alive between requests using FastCGI
We are still killing our chef
include 'lib/common.php';
include 'lib/database.php';
$escaped_url = mysql_real_escape_string($_SERVER['REQUEST_URI']);
$result = mysql_query(
'SELECT html ' .
'FROM pages ' .
'WHERE url=\'' . $escaped_url . '\''
);
if (false === $result || !($page = mysql_fetch_assoc($result))) {
header('HTTP/1.1 404 Not Found');
$page = get_404_page();
}
echo $page['html'];
use Symfony\Component\ClassLoader\ApcClassLoader;
use Symfony\Component\HttpFoundation\Request;
$loader = require_once __DIR__.'/../app/bootstrap.php.cache';
require_once __DIR__.'/../app/AppKernel.php';
$kernel = new AppKernel('prod', false);
$kernel->loadClassCache();
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
-> | FCGI_BEGIN_REQUEST | |
-> | FCGI_PARAMS | |
-> | FCGI_PARAMS | |
-> | ... | |
-> | FCGI_STDIN | |
-> | FCGI_STDIN | |
-> | ... | |
FCGI_STDOUT | <- | |
FCGI_STDOUT | <- | |
... | <- | |
FCGI_END_REQUEST | <- |
pack() unpack()
Or...
composer require "phpfastcgi/speedfony-bundle:0.6.*"
// app/AppKernel.php
// ...
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = array(
// ...
new PHPFastCGI\SpeedfonyBundle\PHPFastCGISpeedfonyBundle(),
);
// ...
}
// ...
php app/console speedfony:run --env=prod
php app/console speedfony:run --env=prod --port=5000
php app/console speedfony:run --env=prod --port=5000 --host=localhost
php app/console speedfony:run --env=prod [--max-requests=200]
How much faster is this?
500 page Symfony application
Single route which selects a random page from database
Renders using Twig
Clears entity repository after each request
VMWare Fusion - 2GB RAM - 4 cores (Intel Core i7, 3.4 GHz)
Ubuntu 64-bit Server 15.04
PHP 5.6.4
NGINX
'ab', 50000 requests, concurrency level of 20
OPcache enabled
PHP-FPM
6 worker processes
FastCGI protocol implemented in PHP userland
6 worker processes
FastCGI protocol implemented by PHP extension
PHPFastCGI is not yet production ready
No support yet for uploaded files
The Symfony kernel slowly leaks memory over multiple requests
Is your application fast enough already?
Why bother with the risk?
PHPFastCGI is a tool for high performance PHP applications
Well designed applications should not leak memory
Well designed applications should handle errors properly
PHPFastCGI is very easy to install
Consider long running processes when developing components and services
FastCGI is designed to allow applications to stay alive between requests
PHP is not designed to allow applications to stay alive between requests
That is possibly why no one has made a serious effort to do this
Used carefully, this can break performance boundaries
Thank you for listening
Any questions?
@AndrewCarterUK
http://phpfastcgi.github.io
http://github.com/PHPFastCGI/SpeedfonyBundle