Confused LEMP vs LAMP same vps hardware LEMP is slower?

We encourage users to post events happening in the community to the community events group on https://www.drupal.org.
gateway69's picture

My Nginx setup, granted very basic start to it, no real caching set up yet... LAMP has really no special additions to it kinda a out of the box install.

Drupal sets ups are clones on both systems.

command for testing on both ab -c10 -n1000 http://localhost/

nginx result

Server Software:        nginx/1.0.9
Server Hostname:        localhost
Server Port:            80

Document Path:          /
Document Length:        3255 bytes

Concurrency Level:      10
Time taken for tests:   78.190 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Non-2xx responses:      1000
Total transferred:      3602000 bytes
HTML transferred:       3255000 bytes
Requests per second:    12.79 [#/sec] (mean)
Time per request:       781.900 [ms] (mean)
Time per request:       78.190 [ms] (mean, across all concurrent requests)
Transfer rate:          44.99 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   1.0      0      16
Processing:    75  781 631.6    709    8783
Waiting:       75  781 631.5    709    8782
Total:         75  781 632.2    709    8794

Percentage of the requests served within a certain time (ms)
  50%    709
  66%    752
  75%    770
  80%    778
  90%    805
  95%   1690
  98%   2690
  99%   3732
100%   8794 (longest request)

Apache2 Results

Server Software:        Apache/2.2.14
Server Hostname:        localhost
Server Port:            80

Document Path:          /
Document Length:        3283 bytes

Concurrency Level:      10
Time taken for tests:   25.926 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Non-2xx responses:      1000
Total transferred:      3671000 bytes
HTML transferred:       3283000 bytes
Requests per second:    38.57 [#/sec] (mean)
Time per request:       259.258 [ms] (mean)
Time per request:       25.926 [ms] (mean, across all concurrent requests)
Transfer rate:          138.28 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   2.3      0      39
Processing:   155  259  43.7    250     751
Waiting:      155  246  41.2    238     731
Total:        155  259  43.8    250     751

Percentage of the requests served within a certain time (ms)
  50%    250
  66%    255
  75%    259
  80%    269
  90%    298
  95%    305
  98%    317
  99%    354
100%    751 (longest request)

im a bit confused because from everything im reading nginx should be faster..

any thoughts? I know its hard to debug but just my first steps starting from scratch..

Comments

There are many things to consider

perusio's picture

you cannot make such blanket statements. I would look to your config of both Nginx and php-fpm. Your Nginx version is also old. My advice is always to use the "development" branch. It's also the advice of the developers in general. There are API changes in 1.1.x. But is also there that the new things get added.

Your version doesn't have keepalive to backends, for example.

yea my next steps where to

gateway69's picture

yea my next steps where to compile from source, I know its not apples to apples, but it was my first sorta get something up and run a test.. im in NO way indicating a is better than b, im just trying to understand how I can get the most performance from the nginx+php-fpm combo that im fairly new to.

I've thought about moving to

brianmercer's picture

I've thought about moving to the dev branch, but then they had that change a few weeks ago with proxy pass that broke a bunch of sites and now I think I'll stick with the stable branch for now.

There are some nice things coming down the pike, though.

You can fix that

perusio's picture

just set:

proxy_pass http://upstream$request_uri;

See: http://mailman.nginx.org/pipermail/nginx/2011-December/031087.html

My point is that the nginx

brianmercer's picture

My point is that the nginx devs are not afraid of making significant and site-breaking changes in the dev branch.

What is loading when you call

wipeout_dude's picture

What is loading when you call http://localhost/ ??

Please try the same test again but call a static file.. So the command would be..

ab -c10 -n1000 http://localhost/index.htm
or
ab -c10 -n1000 http://localhost/image.jpg
or
ab -c10 -n1000 http://localhost/something.js

Leave php out of the equation in the first instance.. Get the web sever tuned and optimised and then introduce php processing in which case you can then look at tuning php knowing the web server is already setup correctly..

hitting a basic html page,

gateway69's picture

hitting a basic html page, with just hello in it.. kaboom ..!

Nginx

netcom@vm-ubuntu2:/var/www$ ab -c10 -n1000 http://localhost/hello.html
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        nginx/1.0.9
Server Hostname:        localhost
Server Port:            80

Document Path:          /hello.html
Document Length:        316 bytes

Concurrency Level:      10
Time taken for tests:   0.151 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      526000 bytes
HTML transferred:       316000 bytes
Requests per second:    6614.50 [#/sec] (mean)
Time per request:       1.512 [ms] (mean)
Time per request:       0.151 [ms] (mean, across all concurrent requests)
Transfer rate:          3397.68 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        1    1   0.1      1       1
Processing:     0    1   0.1      1       1
Waiting:        0    0   0.2      0       1
Total:          1    1   0.1      1       3

Percentage of the requests served within a certain time (ms)
  50%      1
  66%      1
  75%      1
  80%      2
  90%      2
  95%      2
  98%      2
  99%      2
100%      3 (longest request)

apache

netcom@contentsteve:/var/www$ ab -c10 -n1000 http://localhost/hello.html
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        Apache/2.2.14
Server Hostname:        localhost
Server Port:            80

Document Path:          /hello.html
Document Length:        316 bytes

Concurrency Level:      10
Time taken for tests:   0.350 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      593000 bytes
HTML transferred:       316000 bytes
Requests per second:    2854.00 [#/sec] (mean)
Time per request:       3.504 [ms] (mean)
Time per request:       0.350 [ms] (mean, across all concurrent requests)
Transfer rate:          1652.76 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    2   0.7      2       4
Processing:     1    2   0.6      2       4
Waiting:        0    1   0.8      1       3
Total:          3    3   0.1      3       5

Percentage of the requests served within a certain time (ms)
  50%      3
  66%      3
  75%      3
  80%      3
  90%      4
  95%      4
  98%      4
  99%      4
100%      5 (longest request)

That's more like what I would

wipeout_dude's picture

That's more like what I would expect to see.. :)

If you want to optimise more for static content you may want to increase the number of requests and more importantly concurrency.. Of course it depends on the type of traffic you are expecting on your site.. I would say 6614.50 req/s with 10 concurrent hits would be plenty for all but the busiest sites.. :)

The reason you were seeing Apache faster initially is because mod_php is really still the fastest way to run php.. The issue is that the Apache request handling processes are huge because mod_php is loaded for every request, even static content.. Also you have to run Apache with the prefork MPM because mod_php is not thread safe..

In order to run Apache in a threaded model you have to switch to the worker MPM and boot out mod_php and choose php-cgi, fcgid or fastcgi.. None of these process php as fast as mod_php and all have issues with APC.. PHP-FPM is supposed to be the solution to closing the performance gap and also getting things like APC working..

I tested apache with the worker MPM against nginx and nginx was still faster for static content..

PHP processing in my tests was similar on both apache and nginx but since most pages are made up of php and a number of static files nginx should maintain its performance advantage in being able to deliver the static files much faster (using less memory as well)..

As for optimising PHP-FPM, a starting point is having enough spare threads for your average number of concurrent requests your are expecting or have measured so you are not constantly spawning and destroying php-fpm theads..

Then add APC and monitor it to see you have allocated enough memory to it so its not fragmenting..

Tuning mysql can improve things significantly..

Only then I would say its time to look at things like memcached, varnish, etc..

Bear in mind

perusio's picture

that ab is not adequate for benchmarking an event driven architecture like Nginx implements. As previously discussed here.

I would have to agree with

wipeout_dude's picture

I would have to agree with that..

It is a quick and easy basic tool that most have available to them though..

At the end of the day even a basic nginx setup would probably easily saturate the 100Mbps connections that most hosts provide and its probably Drupal and PHP that need far more tuning before the webserver itself becomes the bottleneck..

yep, you guys have to forgive

gateway69's picture

yep, you guys have to forgive me im just getting into switching from apache or looking to, seeing other options out, I have two projects im working on , for my day job im in charge of setting up a game server for an upcoming game we are working on, will have thousands of writes some reads, but not your typical drupal install aka no need for views, hitting the front page this is all done though services and our client communication though json.

the other project is my personal site which is trying to build a the uber social beer site (also we have an ios app working with it) this will have a decent amount of anon traffic looking at stuff, and i would assume decent amount of logged in users..

so kinda looking at this from 2 project types..

I have also started setting up jmeter for testing right now and setting up some plans for both projects, of course focusing on the video game server first :)

@gateway69 - From what I have

wipeout_dude's picture

@gateway69 - From what I have seen of nginx in the last month I have been using it you really cant go far wrong in choosing it as your webserver.. I came from over 10 years experience on Apache and after a learning curve of about a week or so to get a basic nginx setup running I haven't had any issues..

My reasons for changing were not actually to do with the webserver but rather that I wanted to get onto PHP-FPM and linking nginx to it is super simple plus it has the added benefits of being faster and using less memory.. So an all round winner there..

As I have mentioned PHP execution and MySQL are likely to be where you need to spend your time optimising before worrying about fine tuning the webserver.. Even sites like Facebook had to work hard on PHP execution and thats where Hip-Hop for PHP came from.. :)

Yea, I trust that Nginx is

gateway69's picture

Yea, I trust that Nginx is f*cking awesome as a web server I have no issues with it and will use it for another server we need to build where we just want to serve up static files only..

Today class, hah.. im teaching myself im going to dive into using jmeter test plans that I found and create some graphs.

http://www.metaltoad.com/blog/jmeter-test-plan-drupal
http://www.metaltoad.com/blog/plotting-your-load-test-jmeter

seem daily promising..

@wipeout_dude

So given the fact that well now I have to contend with php-fpm and mysql tuning any thoughts on where to start, Ill start with mysql and run it though the db tuner script as a first pass, but as far as getting ph-fpm to run like a mad demon im kinda at a loss.

Im testing on a few different vm solutions , our local vm boxes which Im the only one useing and a Linode standard 768 meg box..

@Gateway69 - Good

wipeout_dude's picture

@Gateway69 - Good question..

There are two aspects to what you are asking.. One being performance or "speed" and the other being scalability..

PHP's "speed" is directly proportional to processing power and how much you can optimise the code execution (Writing good PHP code is also a factor but as far as Drupal is concerned we assume the code is fixed and good).. The easiest option is installing an Opcode cache.. APC being the most recommended one.. Making sure APC has enough memory allocated to it is vital because when it gets fragmented the performance decreases, how much depends on what you are running.. Obviously the faster it can execute the code and take on the next request the more scalable it will be..

PHP scalability comes in with things like optimising the memory footprint by only loading needed modules etc.. This will determine how many php processes/threads can be running before the server runs out of memory..

MySQL tuning is is also application specific.. Depending on the amount of data you are dealing with and the size of the server resources will require you to tune it accordingly.. There are a lot of good resources on the internet.. Again it comes to how much memory you want the MySQL database to use and this comes to how you setup the buffers etc.. I use the following as a helper..

Allocated at atartup.
Global Buffers - key_buffer_size, innodb_buffer_pool_size, innodb_additional_memory_pool_size, innodb_log_buffer_size, query_cache_size.
Allocated depending on query complexity and activity.
Thread buffers - read_buffer_size, sort_buffer_size, read_rnd_buffer_size, tmp_table_size.

.. I am sure there are others as well..

I guess the obvious thing to remember is for any small to medium sized server memory is one of the biggest constraints in single server configurations.. You are sharing a specific pool of memory between the OS, web server, database server and PHP as well as all the caches and buffers that we need to speed things up.. How its divided up is down to the needs of the application and the experienced or expected loads..

The one thing you want to protect as much as possible is your MySQL server that's taking the "write" traffic because its the only part of the system that, as far as I know anyway, can't be scaled horizontally.. Everything else can..

There is one major rule to live by though which is not to worry about major performance tuning until its needed because you can sink a massive amount time in "tweaking" and that time would be far more productive in other areas.. :)

So I started bench marking

gateway69's picture

So I started bench marking today with jmeter, I have a test set up that Im running on both Apache and Nginx, but when running the test on nginx and pulling a service api call aka to get some json data im seeing a 500 internal request error, now the data comes but seems to be in my nginx logs 500.. any ideas what might be up with this, something in the nginx config?

172.18.250.159 - - [31/Jan/2012:13:06:21 -0800] "POST /services/json HTTP/1.1" 500 57 "-" "Mozilla/5.

screen snippet from hitting that request from a browser

http://grab.by/bLxS

thoughts?

Your config

perusio's picture

is required. For going down the path of figuring out what's going on.

My vhost server {       

gateway69's picture

My vhost

server {
        server_name domain.tld;
        root /var/www; ## <-- Your only path reference.

        location = /favicon.ico {
                log_not_found off;
                access_log off;
        }

        location = /robots.txt {
                allow all;
                log_not_found off;
                access_log off;
        }

        # This matters if you use drush
        location = /backup {
                deny all;
        }

        # Very rarely should these ever be accessed outside of your lan
        location ~* .(txt|log)$ {
                allow 192.168.0.0/16;
                deny all;
        }

        location ~ ../..php$ {
                return 403;
        }

        location / {
                # This is cool because no php is touched for static content
                try_files $uri @rewrite;
        }

        location @rewrite {
                # Some modules enforce no slash (/) at the end of the URL
                # Else this rewrite block wouldn't be needed (GlobalRedirect)
                rewrite ^/(.)$ /index.php?q=$1;
        }

        location ~ .php$ {
                fastcgi_split_path_info ^(.+.php)(/.+)$;
                #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_intercept_errors on;
                fastcgi_pass unix:/tmp/phpfpm.sock;
        }

        # Fighting with ImageCache? This little gem is amazing.
        location ~ ^/sites/.
/files/imagecache/ {
                try_files $uri @rewrite;
        }
        # Catch image styles for D7 too.
        location ~ ^/sites/./files/styles/ {
                try_files $uri @rewrite;
        }

        location ~
.(js|css|png|jpg|jpeg|gif|ico)$ {
                expires max;
                log_not_found off;
        }
}

my nginx.conf

user www-data;
worker_processes 4;
pid /var/run/nginx.pid;

events {
        worker_connections 768;
        # multi_accept on;
}

http {

        ##
        # Basic Settings
        ##

        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;
        types_hash_max_size 2048;
        # server_tokens off;

        # server_names_hash_bucket_size 64;
        # server_name_in_redirect off;

        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        ##
        # Logging Settings
        ##

        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;

        ##
        # Gzip Settings
        ##

        gzip on;
        gzip_disable "msie6";

        # gzip_vary on;
        # gzip_proxied any;
        # gzip_comp_level 6;
        # gzip_buffers 16 8k;
        # gzip_http_version 1.1;
        # gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;


        upload_progress uploads 1m;

        ##
        # Virtual Host Configs
        ##

        include /etc/nginx/conf.d/.conf;
        include /etc/nginx/sites-enabled/
;
}

A 500

perusio's picture

error is an internal error. I suspect of the (gratuitous) PATH_INFO stuff. I could be wrong though. Create a debug log tracking the request for that URI and post it somewhere.

Here is one call to service

gateway69's picture

Here is one call to service api, to get user data from our server

http://pastie.org/private/hfvcial2vmlbzlwaixjcug

didn't wasn't to past the full thing here..

I cant really make heads or tails of this..

2012/02/02 12:22:56 [error]

brianmercer's picture

2012/02/02 12:22:56 [error] 28690#0: *177 FastCGI sent in stderr: "PHP Warning:  include_once(./includes/unicode.entities.inc): failed to open stream: No such file or directory in /var/www/includes/unicode.inc on line 339
PHP Warning:  include_once(): Failed opening './includes/unicode.entities.inc' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /var/www/includes/unicode.inc on line 339
PHP Fatal error:  require_once(): Failed opening required './sites/all/modules/cck/theme/theme.inc' (include_path='.:/usr/share/php:/usr/share/pear') in /var/www/sites/all/modules/cck/content.module on line 176" while reading response header from upstream, client: 172.18.250.159, server: domain.tld, request: "POST /services/json HTTP/1.1", upstream: "fastcgi://unix:/tmp/phpfpm.sock:", host: "172.18.250.247"

Looks like two, possibly unrelated, errors. Put them into google. A quick search brought up http://drupal.org/node/1028730 and http://drupal.org/node/616282.

Those types of errors should show in /var/log/nginx/error.log even without debugging on.

not sure those are related,

gateway69's picture

not sure those are related, seems like something I have seen b4 with pressflow and various config with just the required once failing for some reason.. still digging tho..

Hmm

perusio's picture
  1. You should hide the PHP version at least.

  2. The problem seems to be in PHP/fpm.

Does it work with the standard phpinfo() page? Or this just happens with the site? If it happens with phpinfo then definitely should be a PHP/fpm configuration issue.

EDIT: Have you looked at the php-fpm log?