Wednesday, February 22, 2012

Apache 2.4 vs Nginx Benchmark Showdown

Disclaimer: This test was highly unscientific, with a +/- 10% fabricated margin of error.  No maths were performed to gather proper averages and statistics.  No effort was made to ensure consistency of the two Apache builds and no legitimate effort was made with regard to proper scientific rigor during this test.  This test does not take into account memory usage, responsiveness of the server under load, or any other relevant metric that would be of more use than this test.  I highly encourage you to do your own testing and draw your own conclusions.

How the tests were performed: 
I wanted to simulate a VPS environment similar to a basic Linode.  A base install of Ubuntu Server 10.04 was installed in VMWare with an older/slower 7200RPM sata drive for storage.  This drive was not in use by any other system during the test, nor were any other VMs active on the host.  The guest was given 512MB of RAM and 1 CPU core of the host's 8 cores.  The host's CPUs are dual Xeon X5365 @ 3Ghz.

Apache 2.2 was installed along with nginx 0.7.65, later Apache 2.4 was compiled on this same system.

Testing was performed using Apache JMeter on an 8 core Xeon workstation running Windows 7 and 32GB of RAM  with a 1Gb/s link to the VMWare host.  Requests per second were determined by rounding off the throughput displayed in the Summary Report listener.  Each test was run until the requests per second stabilized.

The Apache 2.2 server was only tested with the Prefork MPM, while the Apache 2.4 server was tested with both Prefork and Event.  Apache's KeepAlive setting was on throughout the testing and set at 2 seconds.

Update:
I received several requests to post memory usage statistics so I've updated the Jquery test with memory results.  Again, care was not taken to keep the Apache builds consistent.  It concerns me that the Prefork build of Apache 2.4 was using so much memory compared to the other Apache builds.  Take these results with a grain of salt, but trust that Nginx definitely uses significantly less memory than Apache.

Update 2 - Nginx 1.0.12:
I received some flak for using an older version of Nginx, so I tested with Nginx 1.0.12 and it was around 4% slower than the results shown here.

Test 1 - 21KB text file
HTTP Server Req/s
Apache 2.2 Prefork 2220
Apache 2.4 Prefork 2250
Apache 2.4 Event 2300
Nginx 2600


Test 2 - 2B text file consisting of a single period.
HTTP Server Req/s
Apache 2.2 Prefork 4400
Apache 2.4 Prefork 4700
Apache 2.4 Event 4810
Nginx 6650


Test 3 - jquery.min.js (92KB)

HTTP ServerReq/sMemory Usage
Apache 2.2 Prefork65012MB
Apache 2.4 Prefork77072MB
Apache 2.4 Event82020MB
Nginx10002MB


Test 4 - PHP output of phpinfo()
HTTP Server Req/s
Apache 2.2 Prefork 525
Apache 2.4 Prefork 575
Nginx FastCGI 450


Friday, February 3, 2012

Build Jasig CAS Server for Active Directory integration

This is a step by step guide to compiling Jasig CAS server on a Windows box for integration with Active Directory.  On a Linux or OSX box, just install maven, modify the CAS source files, and build.  Fully tested with Java 1.7, Maven 3.0.4, and CAS 3.4.11 

Install Java and Maven

Install the Java JDK

Download Maven (get the apache-maven-3.x.x-bin.zip file)

Extract Maven and place the inner maven directory somewhere.  This guide assumes you used c:\maven

You need to add environment variables for Java and Maven.  Open the system control panel (Winkey+pause), open advanced system settings, open Environment Variables on the Advanced tab.  We'll be adding everything as a User Variable.  Create a new variable for JAVA_HOME and set it to the jdk directory in c:\program files\java\.  So set JAVA_HOME to  C:\Program Files\Java\jdk1.7.0_02

Add a variable for M2_HOME and point it at your maven directory.  Add another variable for M2 and point it at %M2_HOME%/bin.  Add or update your User Path variable and add %M2%.

You should have added the following:
JAVA_HOME C:\Program Files\Java\jdk1.7.0_02
M2_HOME C:\maven
M2 %M2_HOME%\bin
Path %M2%
Open a cmd prompt and run mvn --version.  You should see Maven version along with the Java version and no errors.


Download and modify the CAS source

Download the CAS source and extract it.  You will need to edit two files:
cas-server-webapp/pom.xml
cas-server-webapp/src/main/webapp/WEB-INF/deployerConfigContext.xml
Open pom.xml and add the following just after <dependencies> around line 12:

        <!-- LDAP support -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>cas-server-support-ldap</artifactId>
<version>${project.version}</version>
</dependency>
Open  deployerConfigContext.xml
Around line 77 you should find the section <property name="authenticationHandlers">
There should be two beans, leave the first one alone, and replace the second one:

<bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" />
Replace with the following and modify the searchBase accordingly.  You'll also want to change the ldap filter from uid to something like sAMAccountName or mail:

<!-- LDAP bind Authentication Handler -->
<bean class="org.jasig.cas.adaptors.ldap.BindLdapAuthenticationHandler">
<property name="filter" value="uid=%u" />
    <property name="searchBase" value="{your LDAP search path, e.g.: cn=users,dc=example,dc=com}" />
    <property name="contextSource" ref="LDAPcontextSource" />
    <property name="ignorePartialResultException" value="yes" /> <!-- fix because of how AD returns results -->
</bean>
Next, add the following before the last </beans> and add your AD server url, userDN, and password.  This should be a ready only AD user.

<bean id="LDAPcontextSource" class="org.springframework.ldap.core.support.LdapContextSource">
    <property name="pooled" value="false"/>
    <property name="urls">
        <list>
            <value>{URL of your AD server, e.g.: ldaps://ad.example.com}/</value>
        </list>
    </property>
    <property name="userDn" value="{your account that has permission to bind to AD, e.g.: uid=someuser, dc=example, dc=com}"/>
    <property name="password" value="{your password for bind}"/>
    <property name="baseEnvironmentProperties">
        <map>
            <entry>
                <key>
                    <value>java.naming.security.authentication</value>
                </key>
                <value>simple</value>
            </entry>
        </map>
    </property>
</bean>

 Build the CAS webapp WAR file


Navigate to the CAS source in your terminal.  We are only concerned with building the WAR file at this point, navigate to cas-server/cas-server-webapp and run:
mvn package install

If all went well you should find cas.war in cas-server/cas-server-webapp/target.  You can now deploy this WAR file to your application server.

Credits:
https://wiki.jasig.org/display/CASUM/Building+and+Deploying
http://stackoverflow.com/questions/6412468/single-sign-on-sso-how-to-use-active-directory-as-an-authentication-method-fo


Thursday, February 2, 2012

Install / Build CouchDB on RHEL 6 & CentOS 6

On RHEL you first need to enable the optional server repo, then install EPEL

Install the prerequisites:
yum install erlang libicu-devel openssl-devel curl-devel make gcc erlang js-devel libtool which
 Grab the CouchDB source from: http://couchdb.apache.org/downloads.html

Extract the source and enter the source directory
tar xvfz apache-couchdb-1.1.1.tar.gz
cd apache-couchdb-1.1.1

Configure make on x86_x64:
./configure --prefix=/usr/local --enable-js-trunk --with-erlang=/usr/lib64/erlang/usr/include

Configure make on i386:
./configure --prefix=/usr/local --enable-js-trunk
Compile CouchDB
make && make install
Add the CouchDB user and set the log file permissions:
adduser -r --home /usr/local/var/lib/couchdb -M --shell /bin/bash --comment "CouchDB Administrator" couchdb
chown -R couchdb: /usr/local/var/lib/couchdb /usr/local/var/log/couchdb /usr/local/etc/couchdb

*optional* Symlink the init script and config files to the standard locations:
ln -s /usr/local/etc/rc.d/couchdb /etc/init.d/couchdb
ln -s /usr/local/etc/couchdb /etc/couchdb
*optional* If you want to run CouchDB on anything other than 127.0.0.1 or change the port, edit /etc/couchdb/local.ini
port = 5984
bind_address = 0.0.0.0
Start CouchDB:
/etc/init.d/couchdb start
 *BROKEN* Proxy CouchDB through Apache with mod_proxy:  Edit the appropriate vhost and add something like:
AllowEncodedSlashes On
ProxyPass /couchdb http://127.0.0.1:5984 nocanon
ProxyPassReverse /couchdb http://127.0.0.1:5984
Note that I could not get any proxy config to pass all of the tests, possibly because I've been trying to proxy it through a /uri .  See this for more info: http://wiki.apache.org/couchdb/Apache_As_a_Reverse_Proxy


Thursday, November 3, 2011

Recursively compare two directories

I often need to recursively compare two directory structures to see what's different.  I found this great python script that does just that.

http://eggdrop.ch/blog/2008/02/17/compare-directories/

Wednesday, October 26, 2011

Batch convert PDFs to multipage TIFFs

Here's a powershell script that uses Ghostscript to convert a directory full of PDFs to multipage TIFF files.  This will convert all PDFs found in $input_path to a TIFF file that is placed in $output_path.  Note, the original file is then deleted.  Thanks to http://stackoverflow.com/questions/75500/best-way-to-convert-pdf-files-to-tiff-files/120316#120316

Set $tool to the correct path for Ghostscript and set $input_path and $output_path accordingly.



$tool = 'C:\Program Files (x86)\gs\gs9.02\bin\gswin32c.exe'
$input_path = 'C:\input\'
$output_path = 'C:\output\'
$pdfs = get-childitem $input_path -recurse | where {$_.Extension -match "pdf"}

foreach($pdf in $pdfs)
{

    $tiff = $output_path + $pdf.PSChildName.split('.')[0] + '.tiff'
    if(test-path $tiff)
    {
        "tiff file already exists " + $tiff
    }
    else        
    {   
        'Processing ' + $pdf.Name        
        $param = "-sOutputFile=$tiff"
        & $tool -q -dNOPAUSE -sDEVICE=tiffg4 $param -r300 $pdf.FullName -c quit
        Remove-Item $pdf.FullName
    }
}

Wednesday, October 19, 2011

Install Ruby on Rails on RHEL 6 with Apache

I couldn't find any decent guides on how to install Rails 3 on RHEL 6 so here it is.  This also works on Centos 6 of course. We'll be using Apache with Phusion Passenger (mod_rails). This is an apache module that will serve up Rails applications in a similar way to how PHP is handled. 

You can skip this on Centos, but for RHEL you need to log into RHN or your Satellite server and enable the optional server repo for your machine (required for ruby-devel and rubygems).

Install the required development packages.
yum install gcc gcc-c++ make curl-devel openssl-devel zlib-devel httpd-devel apr-devel apr-util-devel sqlite-devel

Install ruby, ruby-devel, and rubygems:
yum install ruby ruby-devel rubygems

Next, use gems to install Rails and Passenger. (Note this takes a while.)
gem install rails passenger

Build the Passenger apache module by running:
passenger-install-apache2-module

That will also give you some relevant instructions on how to configure Apache. Now let's create a test application.

cd /var/www/html
rails new railstest
cd railstest
Edit Gemfile and add:
gem 'therubyracer'
Run bundle install to install therubyracer javascript engine (takes a minute or two)
bundle install

Generate our hello world controller:
rails generate controller hello

Edit config/routes.rb and uncomment the next to last line
match ':controller(/:action(/:id(.:format)))'
Edit  app/views/hello/index.html.erb add some hello world text.

At this point you can test the application to make sure it works with the default rails server.  Run rails server and open http://hostaddress:3000/hello and you should see your hello world text.  Kill this and proceed with your apache configuration.

This assumes you have a default httpd install.  Change this accordingly if you already have other vhosts configured. (Note the RailsEnv option, you'll need to set this accordingly in the future)
Add the following to /etc/httpd/conf/httpd.conf
LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-3.0.9/ext/apache2/mod_passenger.so
PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-3.0.9
PassengerRuby /usr/bin/ruby

<VirtualHost *:80>
DocumentRoot /var/www/html/railstest/public
<Directory /var/www/html/railstest/public>
AllowOverride All
Options -MultiViews
RailsEnv development
</Directory>
</VirtualHost>
Restart apache, browse to http://hostaddress/hello and you should see your hello world text!

Saturday, October 8, 2011

tar exclude svn directories

To exclude svn folders when using tar, do:
tar czf tarball.tgz --exclude=.svn mydirectory