Running PHP on Nginx

54
Tips and tricks for high performance websites Harald Zeitlhofer Boost your website by running PHP on Nginx @HZeitlhofer [email protected]

Transcript of Running PHP on Nginx

Page 1: Running PHP on Nginx

1

Tips  and  tricks  for  high  performance  websites  

Harald  Zeitlhofer  

Boost  your  website  by  running  PHP  on  Nginx  

@HZeitlhofer  [email protected]  

 

Page 2: Running PHP on Nginx

2

• Technology  Strategist  at  Dynatrace  • Database  and  Web  Development  

• PHP  for  more  than  15  years  

• Love  to  discover  new  things  

Harald  Zeitlhofer  

Page 3: Running PHP on Nginx

3

Tips and tricks for high performance websites

Page 4: Running PHP on Nginx

4

Web  ApplicaIons  

Page 5: Running PHP on Nginx

5

Page 6: Running PHP on Nginx

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  

Page 7: Running PHP on Nginx

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!!!  

Page 8: Running PHP on Nginx

8

cached  content  

can  sIll  create  roundtrips    to  the  network!  

Page 9: Running PHP on Nginx

9

Web  Request  handling  

Page 10: Running PHP on Nginx

10

Web  Request  handling  

Page 11: Running PHP on Nginx

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    

 

Page 12: Running PHP on Nginx

12

PHP-­‐FPM  FastCGI  Process  Manager      

Available  since  5.3.3  

Stable  since  5.4.1  

     

Page 13: Running PHP on Nginx

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

Page 14: Running PHP on Nginx

14

HHVM  HipHop  Virtual  Machine  

Facebook's  PHP  engine  

JIT  compiler  

supports  PHP  and  Hack  

 

Page 15: Running PHP on Nginx

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

Page 16: Running PHP on Nginx

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  

Page 17: Running PHP on Nginx

17

Leading  among    top  100.000  websites  

Page 18: Running PHP on Nginx

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; }

Page 19: Running PHP on Nginx

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; }

}

Page 20: Running PHP on Nginx

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;

Page 21: Running PHP on Nginx

21

TransacIon  flow  

Page 22: Running PHP on Nginx

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 ...

Page 23: Running PHP on Nginx

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;

} }

Page 24: Running PHP on Nginx

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"]); ...

Page 25: Running PHP on Nginx

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; }

Page 26: Running PHP on Nginx

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 Application\n"; }

}

Page 27: Running PHP on Nginx

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

Page 28: Running PHP on Nginx

28

PHAR  execuIon  

Page 29: Running PHP on Nginx

29

Nginx  and  Caching  

Page 30: Running PHP on Nginx

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; }

Page 31: Running PHP on Nginx

31

FastCGI  cache  in  acIon  

Page 32: Running PHP on Nginx

32

FastCGI  cache  in  acIon  

<?php echo time()."\n"; ?>

Page 33: Running PHP on Nginx

33

FastCGI  cache  in  acIon  

<?php echo time()."\n"; ?>

Page 34: Running PHP on Nginx

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); ... ?>

Page 35: Running PHP on Nginx

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)); ... ?>

Page 36: Running PHP on Nginx

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; } }

Page 37: Running PHP on Nginx

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  se

c  

Page 38: Running PHP on Nginx

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; }

Page 39: Running PHP on Nginx

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;

Page 40: Running PHP on Nginx

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; }

}

Page 41: Running PHP on Nginx

41

• Methods  •  round-­‐robin  

•  least-­‐connected  (least_conn)  

•  session  persistence  (ip_hash)  

• Weighted  load  balancing  

• Health  checks  •  max_fails  

•  fail_Imeout  

Load  balancing  

Page 42: Running PHP on Nginx

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; }

Page 43: Running PHP on Nginx

43

news  from  the  NGINX  front  

Page 44: Running PHP on Nginx

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; ... }

Page 45: Running PHP on Nginx

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  

Page 46: Running PHP on Nginx

46

nginScript  –  js_set  http { js_set $hello_world " var str = 'Hello World!'; // JavaScript str; "; server { ... location /{ return 200 $hello_world; } } }

Page 47: Running PHP on Nginx

47

nginScript  –  js_run  

location / { js_run " var res; res = $r.response; res.status = 200; res.send('Hello World!'); res.finish(); "; }

Page 48: Running PHP on Nginx

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; } }

Page 49: Running PHP on Nginx

49

• easy  distribuIon  of  3rd  party  modules  to  end  users  

• migraIon  of  exisIng  modules  (rebuild)  

• only  cerIfied  modules  loadable  in  NGINX  Plus  

Dynamic  modules  

Page 50: Running PHP on Nginx

50

• Nginx  running  with  default  sepngs  

• Apache  •  AllowOverride  None  

•  MulI-­‐process  (prefork)  mode    to  allow  usage  of  mod_php  

Benchmarking  Nginx  vs  Apache  

Page 51: Running PHP on Nginx

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  respo

nse  Im

e  [sec]  

Page 52: Running PHP on Nginx

52

Performance  Monitoring  

Page 53: Running PHP on Nginx

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  

Page 54: Running PHP on Nginx

54

www.dynatrace.com  

Thank you !!!

Harald  Zeitlhofer  Performance  Advocate  #HZeitlhofer  [email protected]  blog.dynatrace.com  

Dynatrace  Free  Trial  Free  Personal  License  hDp://bit.ly/dDrial