Running PHP on Nginx
- 1. 1
Tips
and
tricks
for
high
performance
websites
Harald
Zeitlhofer
Boost
your
website
by
running
PHP
on
Nginx
@HZeitlhofer
harald.zeitlhofer@dynatrace.com
- 2. 2
• Technology
Strategist
at
Dynatrace
• Database
and
Web
Development
• PHP
for
more
than
15
years
• Love
to
discover
new
things
Harald
Zeitlhofer
- 6. 6
Modern
Web
Pages:
lots
of
staIc
content
434
Resources
in
total
on
that
page:
230
JPEGs,
75
PNGs,
50
GIFs,
…
more
than
20MB
page
size
- 7. 7
Fifa.com
during
Worldcup
2014
hXp://blog.dynatrace.com/2014/05/21/is-‐the-‐fifa-‐world-‐cup-‐website-‐ready-‐for-‐the-‐tournament/
largest
item
on
page:
favicon.ico
with
370
KB!!!
but
also
some
heavyweight
CSS
and
JS
files
with
up
to
288
KB!!!
- 11. 11
PHP
run
modes
Apache
Module
– tradiIonal
approach
– used
for
most
PHP
environments
PHP-‐FPM
– fast
process
manager
– run
mulIple
PHP
worker
processes
to
serve
FastCGI
requests
HHVM
– Virtual
machine
for
HipHop
– fast
PHP
engine
– can
serve
FastCGI
requests
- 13. 13
• InstallaIon
• Pool
configuraIon
/etc/php5/fpm/pool.d/www.conf
PHP-‐FPM
[www]
user = www-data
group = www-data
listen = 127.0.0.1:9000 # for Unix socket: unix:/var/run/php5-fpm.sock;
root@hzvm01:/etc/nginx/sites-enabled# ps -ef | grep php
root 6435 1 0 14:39 ? 00:00:32 php-fpm: master process (/etc/php5/fpm/php-fpm.conf)
spelix 6439 6435 0 14:39 ? 00:00:00 php-fpm: pool batch
spelix 6440 6435 0 14:39 ? 00:00:00 php-fpm: pool batch
www-data 10576 6435 1 18:45 ? 00:00:48 php-fpm: pool www
www-data 10920 6435 1 18:47 ? 00:00:47 php-fpm: pool www
www-data 10927 6435 1 18:47 ? 00:00:46 php-fpm: pool www
sudo apt-get install php5-fpm
- 15. 15
• InstallaIon
• start
server
cd /your/root/folder
hhvm --mode server -vServer.Type=fastcgi -vServer.Port=9000
echo deb http://dl.hhvm.com/ubuntu trusty main | sudo tee /etc/apt/sources.list.d/hhvm.list
sudo apt-get update
sudo apt-get install hhvm
hhvm --mode server -vServer.Type=fastcgi –vServer.FileSocket=/var/run/hhvm.sock
- 16. 16
Nginx
Lightweight
HTTP
server
Event
based
request
handling
Open
Source
project
(BSD)
Development
started
in
2002
by
Igor
Sysoev
to
solve
the
c10k
problem
Commercial
version
NGINX
Plus
- 18. 18
/etc/nginx/nginx.conf
# max_clients = worker_processes * worker_connections
worker_processes 8; # number of CPUs
pcre_jit on; # enable JIT for regex
events {
worker_connections 1024;
multi_accept on;
}
- 19. 19
• StaIc
content
served
by
Nginx
• Dynamic
requests
sent
to
PHP
IntegraIon
server {
listen 80;
server_name www.yourdomain.com;
root /var/www/test;
index index.php index.html index.htm;
location ~* .(html|js|css|gif|jpg|jpe|jpeg|png|bmp|tif|pdf|ico)$ {
try_files $uri =404;
}
location / {
try_files $uri $uri/ =404;
}
location ~* .php$ {
fastcgi_index index.php;
fastcgi_pass 127.0.0.1;
include fastcgi_params;
}
}
- 20. 20
CommunicaIon
via
sockets
• TCP
vs
Unix
• Unix
slightly
faster
when
used
on
localhost
• Use
TCP
for
high
load
location ~* .php$ {
fastcgi_index index.php;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
fastcgi_pass unix:/var/run/php5-fpm.sock;
- 22. 22
hXp://www.mysite.com/news/browse/2014
è
to
be
processed
by
index.php
URL
rewrite
...
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php
...
- 23. 23
hXp://www.mysite.com/news/browse/2014
è
to
be
processed
by
index.php
URL
rewrite
upstream php {
server unix:/var/run/php5-fpm.sock;
}
server {
listen 80;
root /var/www;
index index.php index.html index.htm;
server_name www.mysite.com;
location / {
try_files $uri $uri/ @missing;
}
location @missing {
rewrite (.*) /index.php;
}
location ~ .php$ {
fastcgi_index index.php;
include fastcgi_params;
fastcgi_pass php;
}
}
- 24. 24
using
Nginx/PHP-‐FPM
there’s
a
beXer
way:
URL
rewrite
upstream php {
server unix:/var/run/php5-fpm.sock;
}
server {
listen 80;
root /var/www;
index index.php index.html index.htm;
server_name www.mysite.com;
location /images {
try_files $uri =404;
}
location /scripts {
try_files $uri =404;
}
location / {
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/index.php;
fastcgi_pass php;
}
}
<?php
$params = explode('/', $_SERVER["DOCUMENT_URI"]);
...
- 25. 25
• Easy
way
to
deploy
your
applicaIon
• All
source
files
packed
into
one
*.phar
file
PHAR
–
PHP
Archives
location ~* .(php|phar)$ {
fastcgi_index index.php;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/myapp.phar;
}
- 26. 26
PHAR
example
root@hzvm01:/var/www/app/src# ls -lrtR
.:
total 8
drwxrwxr-x 2 root root 4096 Oct 10 16:27 lib
-rw-r--r-- 1 root root 27 Oct 10 16:27 index.php
./lib:
total 4
-rw-r--r-- 1 root root 87 Oct 10 16:27 App.php
root@hzvm01:/var/www/app/src# cat index.php
<?php
$app = new App();
?>
root@hzvm01:/var/www/app/src# cat lib/App.php
<?php
class App {
function __construct() {
echo "Starting Applicationn";
}
}
- 27. 27
PHAR
example
location /myapp {
fastcgi_index index.php;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/myapp.phar;
}
root@hzvm01:/var/www/app# phar pack -f myapp.phar src
lib/App.php
index.php
root@hzvm01:/var/www/app# l myapp.phar
-rw-r--r-- 1 root root 6923 Oct 10 19:51 myapp.phar
- 30. 30
• Part
of
Nginx'
FastCGI
module
Nginx
FastCGI
cache
fastcgi_cache_path /etc/nginx/cache levels=1:2 keys_zone=APPKEY:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
location ~* .php$ {
fastcgi_index index.php;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_cache APPKEY;
fastcgi_cache_valid 200 60m;
}
- 34. 34
Full
page
cache
with
Memcached
<?php
...
function __construct () {
$this->c = new Memcached();
$this->c->addServer('localhost',11211);
}
function setCache ($key, $content) {
$this->c->set($key, $content);
}
...
// get HTML content
$html = $this->renderPage();
$this->setCache($_SERVER['REQUEST_URI'], $html);
...
?>
- 35. 35
Data
cache
with
Memcached
<?php
...
function __construct () {
$this->c = new Memcached();
$this->c->addServer('localhost',11211);
}
function setCache ($key, $content) {
$this->c->set($key, $content);
}
...
// get data structure
$newslist = $this->getNewsList();
$this->setCache('/data/news/getlist', json_encode($newslist));
...
?>
- 36. 36
• ngx_hXp_memcached_module
Full
page
/
data
cache
with
Nginx
and
Memcached
upstream php {
server unix:/var/run/php5-fpm.sock;
}
server {
location / {
set $memcached_key "$uri";
memcached_pass localhost:11211;
error_page 404 502 504 = @notincache;
}
location @notincache {
fastcgi_pass php;
}
}
- 37. 37
PHP,
5k
requests,
concurrency
100
0
1
2
3
4
5
6
7
8
Apache+PHP
Nginx+PHP
Nginx+Memcached
<?php
echo "Hello World";
?>
7,28
4,6
3,05
total
Ime
in
sec
- 38. 38
• set
HTTP
response
expires
header
Caching
StaIc
Content
location ~ .(html|js|css|gif|jpg|jpe|jpeg|png|bmp|tif|pdf|ico)$ {
expires 365d;
access_log off;
error_log off;
log_not_found off;
add_header Cache-Control "public";
try_files $uri =404;
}
- 39. 39
• keep
handlers
for
requested
staIc
files
open
Filehandle
Caching
open_file_cache max=1000 inactive=5m;
open_file_cache_valid 60s;
open_file_cache_min_uses 5;
open_file_cache_errors off;
- 40. 40
Load
balancing
upstream php {
ip_hash;
server unix:/var/run/php5-fpm.sock weight=5;
server 192.168.56.12:9000 weight=2;
server 192.168.56.13:9000;
server 192.168.56.14:9000 backup;
}
server {
listen 80;
root /home/www/test;
server_name test.hzvm01;
location / {
try_files $uri =405;
}
location ~ .php$ {
fastcgi_pass php;
fastcgi_index index.php;
include fastcgi_params;
}
}
- 41. 41
• Methods
• round-‐robin
• least-‐connected
(least_conn)
• session
persistence
(ip_hash)
• Weighted
load
balancing
• Health
checks
• max_fails
• fail_Imeout
Load
balancing
- 42. 42
more
performance
tuning
location ~ .(html|js|css|gif|jpg|jpe|jpeg|png|bmp|tif|pdf|ico)$ {
expires 365d;
access_log off;
error_log off;
log_not_found off;
add_header Cache-Control "public";
try_files $uri =404;
}
- 44. 44
• remove
the
spdy
parameter
from
all
listen
direcIves
!!!
HTTP/2
server {
listen 443 ssl http2 default_server;
ssl_certificate server.crt;
ssl_certificate_key server.key;
...
}
- 45. 45
• first
preview
announced
at
nginx.conf
2015
• custom
JS
engine
• one
VM
for
each
request
• JS
snippets
embedded
in
NGINX
configuraIon
• evaluated
at
runIme
nginScript
- 46. 46
nginScript
–
js_set
http {
js_set $hello_world "
var str = 'Hello World!';
// JavaScript
str;
";
server {
...
location /{
return 200 $hello_world;
}
}
}
- 47. 47
nginScript
–
js_run
location / {
js_run "
var res;
res = $r.response;
res.status = 200;
res.send('Hello World!');
res.finish();
";
}
- 48. 48
nginScript
–
request
parameters
http {
js_set $summary "
var a, s, h;
s += 'Method: ' + $r.method + 'n' + 'HTTP version: ' + $r.httpVersion + 'n';
s += 'Host: ' + $r.headers.host + 'n' + 'Remote Address: ' + $r.remoteAddress + 'n';
s += 'URI: ' + $r.uri + 'n';
s += 'Headers:n';
for (h in $r.headers) {
s += ' header "' + h + '" is "' + $r.headers[h] + '"n';
}
s += 'Args:n';
for (a in $r.args) {
s += ' arg "' + a + '" is "' + $r.args[a] + '"n';
}
s;
";
server {
listen 8000;
location /summary {
return 200 $summary;
}
}
- 49. 49
• easy
distribuIon
of
3rd
party
modules
to
end
users
• migraIon
of
exisIng
modules
(rebuild)
• only
cerIfied
modules
loadable
in
NGINX
Plus
Dynamic
modules
- 50. 50
• Nginx
running
with
default
sepngs
• Apache
• AllowOverride
None
• MulI-‐process
(prefork)
mode
to
allow
usage
of
mod_php
Benchmarking
Nginx
vs
Apache
- 51. 51
StaIc
HTML,
10k
requests
0
1
2
3
4
5
6
7
8
9
100
500
1000
2000
Apache/2.4.9
nginx/1.1.19
concurrency
Total
response
Ime
[sec]
- 53. 53
• Load
Generator
(Apache
Benchmark,
Selenium,
JMeter)
• Firebug,
Google
Developer
Tools
Dynatrace
Ajax
EdiIon
• Dynatrace
Free
Trial
• Free
trial
license
for
30
days
• Free
personal
license
for
developers
My
favorite
performance
tools
hXp://bit.ly/dXrial
- 54. 54
www.dynatrace.com
Thank you !!!
Harald
Zeitlhofer
Performance
Advocate
#HZeitlhofer
harald.zeitlhofer@dynatrace.com
blog.dynatrace.com
Dynatrace
Free
Trial
Free
Personal
License
hDp://bit.ly/dDrial