performance modifications

Sean Chittenden sean at
Mon Mar 14 15:15:16 PST 2005

> | There are better web servers than Apache for demanding loads;
> | ones that used a non-forking, event-driven I/O model.
> | Aolserver and thttpd come to mind.
> I tried thttpd a number of years ago, but due to its limited cgi  
> support (at
> least at the time) I didn't do too much with it.  It did seem fast,  
> however.

thttpd is a favorite of mine because of the time I've spent in its guts  
rewriting it for clients, but embedding PHP into it will never work  
well because of the way the code is written and organization.  Recently  
I've been playing around with lighttpd and am very impressed.  It's BSD  
licensed (3 clause) and has quickly become my new webserver of choice  
(*mutters something about Rails*).  It even supports keep-alives well,  
which is something that thttpd doesn't do too well.  Here are some  
benchmarks put out by a commercial webserver company, Lite Speed.

The lightspeed webserver guys are keen to point out that their  
webserver is the fastest on the block, but I'm skeptical of their  
results given the utility they're using for testing.  I'm in the midst  
of writing a kqueue(2)/pthreads(3) backed web-benchmark program that  
will hopefully show that the gap between lighttpd and lite speed is  
smaller than the above benchmarks point out (if there's any difference  
at all).  Any testing utility that's select(2) backed is going to suck  
up more resources than the server.... but I digress.  If you're doing  
PHP, lighttpd should work very well for you and certainly be orders of  
magnitude better than Apache.

Having skimmed through the lighttpd code, the areas that it could  
improve are:

*) pre-forking a pool of backends for CGI requests (lighttpd gets  
crushed by litespeed here)
*) mmap(2)'ing buffers to reduce the overhead of writev(2)'ing data out  
over the network (ie: reduce copying of userland data to the kernel)
*) use Boehm GC or make use of a memory pools that stay around longer  
than a connection.  Right now every connection gets its own memory pool  
which is a problem in non-keep-alive connections.  At the beginning and  
end of a connection, a pool gets allocated and free'ed.  Free'ed memory  
from other connections is only reused by malloc(3), not by the OS.
*) A better method of appending data to buffers (ie, use the same idea  
from Boehm's Cord library to reduce the costs of appending strings of  
data).  Right now it uses memcpy(3) and it should just add a pointer to  
an array and realloc(3) the pointer array when the pointer array gets  
full instead of copy'ing data around.
*) Divvy out requests to a pool of worker threads much the same way  
that Cherokee does (a thttpd based webserver that's been adapted to use  
pthreads... ie, thttpd on steroids) 

The improvement should come with threaded processing and dispatching of  
requests.  Right now that's serialized and is the difference between  
litespeed pro and litespeed.  That's also one of the ways that Cherokee  
makes its speed improvements over other webservers.


Sean Chittenden

More information about the freebsd-performance mailing list