Showing posts with label passenger. Show all posts
Showing posts with label passenger. Show all posts

Thursday, August 20, 2009

Show Me the Numbers

‹prev | My Chain | next›

Show me the numbers!

Whenever I come up with some cool little algorithm that will certainly speed things up, a little voice in the back of my head starts screaming this at me. Actually, the voice is that of my friend and mentor, Mike Barry, who demanded this of me many a time when I was sure that I had devised a terribly clever optimization. Eventually I heard it so often that the voice is permanently embedded in my brain.

And I am hearing it right now.

Last night, I was able to get my Sinatra / CouchDB app running under nginx and passenger. I was really pleased with myself and ready to move on, until I heard that voice...

Prior to switching to nginx / passenger, I had the same application running in a cluster of 4 thin servers behind HAProxy. Is nginx / passenger really better than HAProxy / thin?

Show me the numbers!

OK! OK! Stupid little voice, I could be adding new features now!

The configuration for HAProxy / thin is fairly vanilla. I am running 4 thin servers behind the HAProxy, as described the other night.

Similarly, the configuration for nginx / passenger is very close to the default produced from the passenger / nginx install, as described last night. There are two worker_processes (I also tried 4, with similar results).

For both the nginx and HAProxy servers, I am going to access a recipe and image from the underlying Sinatra app. For both the recipe and the image, I will use a single process and 4 concurrent process. The apache benchmarking commands for these four scenarios are:
ab -n 100 http://beta.eeecooks.com/recipes/2008-08-04-popovers
ab -n 100 http://beta.eeecooks.com/images/2008-08-04-popovers/popover_0039.jpg
ab -n 100 -c 4 http://beta.eeecooks.com/recipes/2008-08-04-popovers
ab -n 100 -c 4 http://beta.eeecooks.com/images/2008-08-04-popovers/popover_0039.jpg
The results (requests per second) with both servers:
Configrecipeimagerecipe w/ 4 procsimage w/ 4 procs
nginx / passenger4.821.5912.691.96
HAProxy / thin5.451.6716.961.96

I have a couple of "takeaways" from this. First of all, I really need to institute some caching. 12 requests per second ain't gonna cut it. Also, I need to be careful when testing these things over my internet connection—the values for the 4 process image download saturated my DSL connection (which is why they are identical).

Most importantly, the HAProxy / thin combination is up to 33% faster than nginx / passenger. As cool as nginx / passenger sounds, I will have to stick with HAProxy / thin.

Good thing I listened to that little voice.

Wednesday, August 19, 2009

Rack Passenger

‹prev | My Chain | next›

As much fun as HAProxy and thin servers are, I think getting things running under nginx and passenger might be even more fun. So, first up is to install the passenger gem:
sh-3.2$ sudo gem install passenger
I then run through the passenger install wizard:
sh-3.2$ sudo /var/lib/gems/1.8/bin/passenger-install-nginx-module 
Welcome to the Phusion Passenger Nginx module installer, v2.2.4.

This installer will guide you through the entire installation process. It
shouldn't take more than 5 minutes in total.

Here's what you can expect from the installation process:

1. This installer will compile and install Nginx with Passenger support.
2. You'll learn how to configure Passenger in Nginx.
3. You'll learn how to deploy a Ruby on Rails application.

Don't worry if anything goes wrong. This installer will advise you on how to
solve any problems.

Press Enter to continue, or Ctrl-C to abort.
<Enter>

--------------------------------------------

Checking for required software...

* GNU C++ compiler... found at /usr/bin/g++
* Ruby development headers... found
* OpenSSL support for Ruby... found
* RubyGems... found
* Rake... found at /usr/bin/rake
* Zlib development headers... not found

Some required software is not installed.
But don't worry, this installer will tell you how to install them.

Press Enter to continue, or Ctrl-C to abort.
<Enter>

--------------------------------------------

Installation instructions for required software

* To install Zlib development headers:
Please run apt-get install zlib1g-dev as root.

If the aforementioned instructions didn't solve your problem, then please take
a look at the Users Guide:

/var/lib/gems/1.8/gems/passenger-2.2.4/doc/Users guide Nginx.html
Wow, that's nice. It would have taken me a little while to track down the exact library name in the Debian package repository, so I much appreciate the help offered here. Following passenger's instructions, I:
sudo apt-get install zlib1g-dev
Then, after re-running the installer, I get past the required software check and onto:
sh-3.2$ sudo /var/lib/gems/1.8/bin/passenger-install-nginx-module
...
--------------------------------------------

Checking for required software...

* GNU C++ compiler... found at /usr/bin/g++
* Ruby development headers... found
* OpenSSL support for Ruby... found
* RubyGems... found
* Rake... found at /usr/bin/rake
* Zlib development headers... found

--------------------------------------------

Automatically download and install Nginx?

Nginx doesn't support loadable modules such as some other web servers do,
so in order to install Nginx with Passenger support, it must be recompiled.

Do you want this installer to download, compile and install Nginx for you?

1. Yes: download, compile and install Nginx for me. (recommended)
The easiest way to get started. A stock Nginx 0.6.37 with Passenger
support, but with no other additional third party modules, will be
installed for you to a directory of your choice.

2. No: I want to customize my Nginx installation. (for advanced users)
Choose this if you want to compile Nginx with more third party modules
besides Passenger, or if you need to pass additional options to Nginx's
'configure' script. This installer will 1) ask you for the location of
the Nginx source code, 2) run the 'configure' script according to your
instructions, and 3) run 'make install'.

Whichever you choose, if you already have an existing Nginx configuration file,
then it will be preserved.

Enter your choice (1 or 2) or press Ctrl-C to abort: 1<Enter>
I am not much a fan of compiling my web server in addition to the passenger module, but hey, it's my personal site and it is the awesomeness of nginx + passenger. Continuing with the installer:
--------------------------------------------

Where do you want to install Nginx to?

Please specify a prefix directory [/opt/nginx]: <Enter>

Compiling Passenger support files...
...

--------------------------------------------

Nginx with Passenger support was successfully installed.

The Nginx configuration file (/opt/nginx/conf/nginx.conf)
must contain the correct configuration options in order for Phusion Passenger
to function correctly.

This installer has already modified the configuration file for you! The
following configuration snippet was inserted:

http {
...
passenger_root /var/lib/gems/1.8/gems/passenger-2.2.4;
passenger_ruby /usr/bin/ruby1.8;
...
}

After you start Nginx, you are ready to deploy any number of Ruby on Rails
applications on Nginx.

Press ENTER to continue.
<Enter>

--------------------------------------------

Deploying a Ruby on Rails application: an example

Suppose you have a Ruby on Rails application in /somewhere. Add a server block
to your Nginx configuration file, set its root to /somewhere/public, and set
'passenger_enabled on', like this:

server {
listen 80;
server_name www.yourhost.com;
root /somewhere/public; # <--- be sure to point to 'public'!
passenger_enabled on;
}

And that's it! You may also want to check the Users Guide for security and
optimization tips and other useful information:

/var/lib/gems/1.8/gems/passenger-2.2.4/doc/Users guide Nginx.html

Enjoy Phusion Passenger, a product of Phusion (www.phusion.nl) :-)
http://www.modrails.com/

Phusion Passenger is a trademark of Hongli Lai & Ninh Bui.
Those instructions work just as well for a Sinatra application with a rackup file. I currently have my application located in /var/www/eee-code, so my nginx configuration is (mostly from the default configuration from the passenger / nginx install):
worker_processes  2;


events {
worker_connections 1024;
}


http {
passenger_root /var/lib/gems/1.8/gems/passenger-2.2.4;
passenger_ruby /usr/bin/ruby1.8;

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

sendfile on;

keepalive_timeout 65;

server {
listen 80;
server_name beta.eeecooks.com;
root /var/www/eee-code/public;
passenger_enabled on;

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
I also have to update the default /etc/init.d/nginx script to point to the proper location for the pid file and the executable daemon:
#! /bin/sh

### BEGIN INIT INFO
# Provides: nginx
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts the nginx web server
# Description: starts nginx using start-stop-daemon
### END INIT INFO

PATH=/opt/nginx/sbin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/opt/nginx/sbin/nginx
#PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
#DAEMON=/usr/sbin/nginx
NAME=nginx
DESC=nginx

test -x $DAEMON || exit 0

# Include nginx defaults if available
if [ -f /etc/default/nginx ] ; then
. /etc/default/nginx
fi

set -e

case "$1" in
start)
echo -n "Starting $DESC: "
start-stop-daemon --start --quiet --pidfile /opt/nginx/logs/$NAME.pid \
--exec $DAEMON -- $DAEMON_OPTS || true
echo "$NAME."
;;
stop)
echo -n "Stopping $DESC: "
start-stop-daemon --stop --quiet --pidfile /opt/nginx/logs/$NAME.pid \
--exec $DAEMON || true
echo "$NAME."
;;
restart|force-reload)
echo -n "Restarting $DESC: "
start-stop-daemon --stop --quiet --pidfile \
/opt/nginx/logs/$NAME.pid --exec $DAEMON || true
sleep 1
start-stop-daemon --start --quiet --pidfile \
/opt/nginx/logs/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS || true
echo "$NAME."
;;
reload)
echo -n "Reloading $DESC configuration: "
start-stop-daemon --stop --signal HUP --quiet --pidfile /opt/nginx/logs/$NAME.pid \
--exec $DAEMON || true
echo "$NAME."
;;
*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
exit 1
;;
esac

exit 0
After stopping my HAProxy frontend to thin servers, I start the nginx server. To make sure that all is well, I check out the HTTP headers via telnet:
cstrom@jaynestown:~/repos/eee-code$ telnet beta.eeecooks.com 80
Trying 97.107.136.191...
Connected to beta.eeecooks.com.
Escape character is '^]'.
HEAD / HTTP/1.0

HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Connection: close
Status: 200
X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 2.2.4
Content-Length: 10167
Server: nginx/0.6.37 + Phusion Passenger 2.2.4 (mod_rails/mod_rack)

Connection closed by foreign host.
Nice. I think tomorrow I will start back with code to move the application out of beta. For now, I have gotten my Sinatra / CouchDB application running under nginx passenger, which is a fine place to be.

Saturday, June 6, 2009

Passenger and Rack

‹prev | My Chain | next›

Having played with Rack some, I think I have a firm grasp on the basics of middleware. There are two more things I would like to understand before moving on: running under Passenger and testing with Rack.

Happily, the Passenger documentation includes an entire section on running with rack so this ought to be easy.

First up, I add an entry to /etc/hosts that I will use to access the site under Passenger:
127.0.0.1       eee.local
When working locally with passenger, I like to keep the passenger configuration in my home directory for easy access. I tell apache where to find the local configuration by adding the following to /etc/apache2/apache2.conf:
Include /home/cstrom/repos/eee-code/passenger.conf
I then create home/cstrom/repos/eee-code/passenger.conf with the following contents, straight from the Passenger user's guide:
<VirtualHost *:80>
ServerName eee.local
DocumentRoot /home/cstrom/repos/eee-code/public
</VirtualHost>
I tend to think that public directory is required. Since tmp/restart.txt is used to restart passenger applications, I think the tmp directory is also needed:
cstrom@jaynestown:~/repos/eee-code$ mkdir public
cstrom@jaynestown:~/repos/eee-code$ mkdir tmp
Hopefully, an apache restart will do it:



Hmmm... Not quite it would seem. Inspecting the apache error log, I find:
NoMethodError - undefined method `rewind' for #<IO:0xb71f84b8>:
config.ru:16:in `call'
/usr/lib/ruby/1.8/passenger/rack/request_handler.rb:65:in `process_request'
/usr/lib/ruby/1.8/passenger/abstract_request_handler.rb:163:in `main_loop'
/usr/lib/ruby/1.8/passenger/rack/application_spawner.rb:92:in `run'
/usr/lib/ruby/1.8/passenger/rack/application_spawner.rb:50:in `spawn_application'
/usr/lib/ruby/1.8/passenger/utils.rb:165:in `safe_fork'
/usr/lib/ruby/1.8/passenger/utils.rb:163:in `fork'
/usr/lib/ruby/1.8/passenger/utils.rb:163:in `safe_fork'
/usr/lib/ruby/1.8/passenger/rack/application_spawner.rb:48:in `spawn_application'
/usr/lib/ruby/1.8/passenger/utils.rb:165:in `safe_fork'
/usr/lib/ruby/1.8/passenger/utils.rb:163:in `fork'
/usr/lib/ruby/1.8/passenger/utils.rb:163:in `safe_fork'
/usr/lib/ruby/1.8/passenger/rack/application_spawner.rb:47:in `spawn_application'
/usr/lib/ruby/1.8/passenger/rack/application_spawner.rb:33:in `spawn_application'
/usr/lib/ruby/1.8/passenger/spawn_manager.rb:110:in `spawn_application'
/usr/lib/ruby/1.8/passenger/spawn_manager.rb:247:in `handle_spawn_application'
/usr/lib/ruby/1.8/passenger/abstract_server.rb:317:in `__send__'
/usr/lib/ruby/1.8/passenger/abstract_server.rb:317:in `main_loop'
/usr/lib/ruby/1.8/passenger/abstract_server.rb:168:in `start_synchronously'
/usr/lib/passenger/passenger-spawn-server:46127.0.0.1 - - [06/Jun/2009 21:48:43] "GET /meals/2002/04/21 " 500 30 0.0005
After some googling for passenger on 9.04, I find that I need to upgrade my passenger. I had been using the stock install for Ubuntu (2.0). It looks like 2.2.2 is out now:
cstrom@jaynestown:~/repos/eee-code$ sudo gem install passenger
Building native extensions. This could take a while...
Successfully installed passenger-2.2.2
1 gem installed
Restarting apache and reloading the web page, I get another error:
[Sat Jun 06 22:11:57 2009] [notice] Apache/2.2.11 (Ubuntu) DAV/2 Phusion_Passenger/2.0.3 configured -- resuming normal operations
**** Exception ArgumentError in spawn manager (The 'app_root' option must be given.) (process 29308):
from /usr/lib/ruby/gems/1.8/gems/passenger-2.2.2/lib/phusion_passenger/spawn_manager.rb:143:in `spawn_application'
from /usr/lib/ruby/gems/1.8/gems/passenger-2.2.2/lib/phusion_passenger/spawn_manager.rb:282:in `handle_spawn_application'
from /usr/lib/ruby/gems/1.8/gems/passenger-2.2.2/lib/phusion_passenger/abstract_server.rb:337:in `__send__'
from /usr/lib/ruby/gems/1.8/gems/passenger-2.2.2/lib/phusion_passenger/abstract_server.rb:337:in `main_loop'
from /usr/lib/ruby/gems/1.8/gems/passenger-2.2.2/lib/phusion_passenger/abstract_server.rb:187:in `start_synchronously'
from /usr/lib/ruby/gems/1.8/gems/passenger-2.2.2/bin/passenger-spawn-server:61
from /usr/bin/passenger-spawn-server:19:in `load'
from /usr/bin/passenger-spawn-server:19
Ew. That look scary.

After much googling and trying of various options, I finally look closer at the log output and notice that the backtrace is for Passenger 2.2.2, but apache is loading 2.0.3. That is not likely to be a good combination. So I cd into the passenger-2.2.2 gem directory and run the installer:
sudo ./bin/passenger-install-apache2-module
Once that is complete (and I have followed the instructions for configuring Apache), I restart Apache and find:



That was a little harder than I expected, but better to find out now than when I am deploying.