from lamp to lnnp
DESCRIPTION
A Brief overview on how to leave the good old LAMP stack in favour of a Linux Nginx NoSql stackTRANSCRIPT
From LAMP to LNNP
A Transition from
Linux Apache Mysql (mod_)PHP
to
Linux (what else?) Nginx Nosql PHP(-FPM)
Giorgio Cefarohttp://giorgiocefaro.com
@giorrrgio
L → Lfrom Linux to...Linux
(intentionally blank)
A → Nfrom Apache to Nginx
Vs
From Wikipedia:
Nginx uses an asynchronous event-driven approach to handling requests which can provide more predictable performance under high loads,
in contrast to the Apache HTTP server model that defaults to a threaded or process-oriented approach to handling requests
PHP Hello world benchmarks
Concurrency Level: 10Time taken for tests: 31.796 secondsComplete requests: 50000Failed requests: 0Write errors: 0Keep-Alive requests: 0Total transferred: 8450000 bytesHTML transferred: 550000 bytesRequests per second: 1572.54 [#/sec] (mean)Time per request: 6.359 [ms] (mean)Time per request: 0.636 [ms] (mean, across all concurrent requests)Transfer rate: 259.53 [Kbytes/sec] received
Concurrency Level: 10Time taken for tests: 18.646 secondsComplete requests: 50000Failed requests: 0Write errors: 0Keep-Alive requests: 49509Total transferred: 12928406 bytesHTML transferred: 550000 bytesRequests per second: 2681.54 [#/sec] (mean)Time per request: 3.729 [ms] (mean)Time per request: 0.373 [ms] (mean, across all concurrent requests)Transfer rate: 677.11 [Kbytes/sec] received
Ab -k -n 50000 -c 10 http://10.0.0.3/test.php
Load average: 4.38, 1.29, 0.46 Load average: 3.00, 0.89, 0.32
PHP Hello world benchmarks
Concurrency Level: 100Time taken for tests: 28.143 secondsComplete requests: 50000Failed requests: 0Write errors: 0Keep-Alive requests: 0Total transferred: 8450000 bytesHTML transferred: 550000 bytesRequests per second: 1776.66 [#/sec] (mean)Time per request: 56.285 [ms] (mean)Time per request: 0.563 [ms] (mean, across all concurrent requests)Transfer rate: 293.22 [Kbytes/sec] received
Concurrency Level: 100Time taken for tests: 18.398 secondsComplete requests: 50000Failed requests: 0Write errors: 0Keep-Alive requests: 49573Total transferred: 12931199 bytesHTML transferred: 550000 bytesRequests per second: 2717.69 [#/sec] (mean)Time per request: 36.796 [ms] (mean)Time per request: 0.368 [ms] (mean, across all concurrent requests)Transfer rate: 686.39 [Kbytes/sec] received
Ab -k -n 50000 -c 100 http://10.0.0.3/test.php
Load average: 13.70, 3.54, 1.20 Load average: 38.49, 10.07, 3.41
PHP Hello world benchmarks
Concurrency Level: 1000Time taken for tests: 64.339 secondsComplete requests: 50000Failed requests: 474 (Connect: 0, Receive: 0, Length: 474, Exceptions: 0)Write errors: 0Non-2xx responses: 474Total transferred: 8522996 bytesHTML transferred: 626314 bytesRequests per second: 777.13 [#/sec] (mean)Time per request: 1286.778 [ms] (mean)Time per request: 1.287 [ms] (mean, across all concurrent requests)Transfer rate: 129.37 [Kbytes/sec] received
Completed 5000 requestsCompleted 10000 requestsCompleted 15000 requestsapr_socket_recv: Connection reset by peer (104)Total of 17522 requests completed
Ab -k -n 50000 -c 1000 http://10.0.0.3/test.php
Load average: 20.50, 7.13, 2.64 Load average: 36.86, 9.02, 3.03
Static HTML benchmarks
Concurrency Level: 10Time taken for tests: 14.023 secondsComplete requests: 50000Failed requests: 0Write errors: 0Total transferred: 10650000 bytesHTML transferred: 250000 bytesRequests per second: 3565.47 [#/sec] (mean)Time per request: 2.805 [ms] (mean)Time per request: 0.280 [ms] (mean, across all concurrent requests)Transfer rate: 741.65 [Kbytes/sec] received
Concurrency Level: 10Time taken for tests: 11.887 secondsComplete requests: 50000Failed requests: 0Write errors: 0Total transferred: 13950000 bytesHTML transferred: 250000 bytesRequests per second: 4206.43 [#/sec] (mean)Time per request: 2.377 [ms] (mean)Time per request: 0.238 [ms] (mean, across all concurrent requests)Transfer rate: 1146.09 [Kbytes/sec] received
ab -n 50000 -c 10 http://10.0.0.3/test.html
Static HTML benchmarks
Concurrency Level: 100Time taken for tests: 12.785 secondsComplete requests: 50000Failed requests: 0Write errors: 0Total transferred: 10650000 bytesHTML transferred: 250000 bytesRequests per second: 3910.97 [#/sec] (mean)Time per request: 25.569 [ms] (mean)Time per request: 0.256 [ms] (mean, across all concurrent requests)Transfer rate: 813.51 [Kbytes/sec] received
Concurrency Level: 100Time taken for tests: 11.875 secondsComplete requests: 50000Failed requests: 0Write errors: 0Total transferred: 13950000 bytesHTML transferred: 250000 bytesRequests per second: 4210.42 [#/sec] (mean)Time per request: 23.751 [ms] (mean)Time per request: 0.238 [ms] (mean, across all concurrent requests)Transfer rate: 1147.17 [Kbytes/sec] received
ab -n 50000 -c 100 http://10.0.0.3/test.html
Static HTML benchmarks
Concurrency Level: 100Time taken for tests: 12.785 secondsComplete requests: 50000Failed requests: 0Write errors: 0Total transferred: 10650000 bytesHTML transferred: 250000 bytesRequests per second: 3910.97 [#/sec] (mean)Time per request: 25.569 [ms] (mean)Time per request: 0.256 [ms] (mean, across all concurrent requests)Transfer rate: 813.51 [Kbytes/sec] received
Concurrency Level: 100Time taken for tests: 11.875 secondsComplete requests: 50000Failed requests: 0Write errors: 0Total transferred: 13950000 bytesHTML transferred: 250000 bytesRequests per second: 4210.42 [#/sec] (mean)Time per request: 23.751 [ms] (mean)Time per request: 0.238 [ms] (mean, across all concurrent requests)Transfer rate: 1147.17 [Kbytes/sec] received
ab -n 50000 -c 100 http://10.0.0.3/test.html
Static HTML benchmarks
Concurrency Level: 1000Time taken for tests: 4.915 secondsComplete requests: 10000Failed requests: 0Write errors: 0Total transferred: 2130000 bytesHTML transferred: 50000 bytesRequests per second: 2034.45 [#/sec] (mean)Time per request: 491.533 [ms] (mean)Time per request: 0.492 [ms] (mean, across all concurrent requests)Transfer rate: 423.18 [Kbytes/sec] received
Completed 1000 requestsCompleted 2000 requestsCompleted 3000 requestsCompleted 4000 requestsCompleted 5000 requestsCompleted 6000 requestsCompleted 7000 requestsCompleted 8000 requestsCompleted 9000 requestsapr_socket_recv: Connection reset by peer (104)Total of 9561 requests completed
ab -n 10000 -c 1000 http://10.0.0.3/test.html
M → Nfrom MySQL to NoSQL
NoSQL?
● SQL, tables, relations, JOINS...
● Just documents, graphs, key-value pairs.
● Really useful when working with a huge quantity of data
● Really useful when working with data that you want not staticly structured
● Really useful for statistical or real-time analyses for growing list of elements
My NoSql choice: MongoDB
● Data in MongoDB is stored in JSON-like documents
● horizontal scalability, auto-sharding to distribute data across many nodes (auto balancing, easy scaling)
● full consistency and transactional updates
● Data integrity is guaranteed through journalling and replication
● Supported by Doctrine2 through Mongo
● Warning: not fully ACID* compliant (missing some transactional use cases)
* atomicity, consistency, isolation, durability
P → Pfrom mod_Php to PHP-FPM
Apache with modphp works but...
● Every apache forked process is fat with all its modules loaded, though before-fork code is shared among processes
● PHP is part of the apache process itself
● You have to load PHP even when you serve static files (server memory footprint)
● You have to rely on a unique PHP version for all you apps
...we can do better: FastCGI PHP
● Multiple versions of PHP, each executed by a different user
● Reduces the memory footprint of your web server for static files
● PHP can be executed on a separate machine
We can do even better! PHP-FPM
● FastCGI Process Manager● PHP daemonization
pid file, log file, setsid(), setuid(), setgid(), chroot()● Adaptive process spawning
Dynamic number of processes, depending on the load● Worker level configuration
uid/gid/chroot/environment and different php.ini for each worker● Logging stdout and stderr● Forcing the completion of process if set_time_limit() fails
Workers, Daemons, WTF?
● At startup a configurable number of workers ar launched, waiting for requests
● Once requests arrive if needed workers are spawned
● Each worker serves a request
● You can fine tune the behaviour to adapt it to your machine
Wanna try?Let's get our hands dirty
Hot to install Nginx + PHP-FPM on Ubuntu
sudo add-apt-repository ppa:nginx/stable
sudo apt-get update
sudo apt-get install nginx
sudo apt-get install php5-fpm php5-cgi
● Version 1.1.19 of nginx is included in the standard ubuntu 12.04 repo
● Unofficial PPA for current stable and development versions
A simple nginx host configuration
#/etc/nginx/sites-available/default
server { listen 80; server_name localhost; index index.php; root /var/www; location ~* \.php$ {
#prevent cgi.fix_pathinfo=1 security hole if (!-f $request_filename) { return 404; } fastcgi_pass 127.0.0.1:9000; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SERVER_NAME $host; }}
Installing MongoDB
● Available through the standard Ubuntu repo● 10gen repositories have fresher stable versions
● Mongo is the 10gen-supported PHP driver for MongoDB● Missing phpMyAdmin? Try phpMoAdmin :-)
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 7F0CEB10
#add to /etc/apt/sources.listdeb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen
sudo apt-get update
sudo apt-get install mongodb-10gen
sudo apt-get install php5-mongo
Using Mongo: a simple example
Source: http://www.php.net/manual/en/mongo.tutorial.php
Useful links
Nginx:http://wiki.nginx.org/
Apache vs Nginx – deathmatchhttp://www.discusswire.com/apache-vs-nginx-deathmatch/
PHP-FPMhttp://php-fpm.org/about/#why
http://www.if-not-true-then-false.com/2011/nginx-and-php-fpm-configuration-and-optimizing-tips-and-tricks/
MongoDBhttp://www.mongodb.org/display/DOCS/Ubuntu+and+Debian+packages
PhpMoAdminhttp://www.phpmoadmin.com/
Mongohttp://php.net/manual/en/book.mongo.php