There are lots of reasons not to use a database for a web application. Sometimes a server's security profile rules out installing another daemon. Sometimes simplicity of administration is more important than query language. This toolkit gives you database-like features with a reduced software install
endif; ?>The World Wide Web started out as a collection of static pages linked to one another. Of course, this was not enough for long. Today (especially with the arrival of Web 2.0) is the era of the Web application. While static pages still abound, the most popular — and the most exciting — sites are dynamic.
The World Wide Web started out as a collection of static pages linked to one another. Of course, this was not enough for long. Today (especially with the arrival of Web 2.0) is the era of the Web application. While static pages still abound, the most popular — and the most exciting — sites are dynamic.
The typical dynamic site depends heavily on a relational database backend (although the most visited sites do not necessarily use this approach). The application builds pages by querying the database, and assembling the returned data into HTML documents. This is a complex process, often implemented in several software layers (N-tier architecture). The database, in particular, must be very robust. After all, the system’s state lives there. If the database goes down (or worse, becomes corrupted) the entire site can no longer function.
Very often, expensive hardware (frequently coupled with expensive software) and teams of database administrators must nurse the database. This scenario is common — even in systems where the rest of the application runs on Free/Open Source Software (FOSS) with generic hardware.
There are tools to help developers of dynamic sites deal with the resulting scalability problems. For example, you could use memcached — a distributed in-memory cache — as part of your application. This can greatly reduce the strain on the database. Caching proxies such as Squid ease the load on multiple layers of the system. Adding Squid to a live site may even compensate for some errors in design or implementation, allowing the application to perform sufficiently well with little change.
Yet, the standard architecture for dynamic sites may be less effective than its popularity suggests. First of all, the ubiquitous relational database management system (RDBMS) is not the best tool for text processing (see “One Size Fits All? — Part 2: Benchmarking Results” (PDF)). Programming for the Web, of course, is still primarily about text processing. Google does not use an RDBMS for this purpose, nor did the earlier search engines (such as Lycos and Inktomi).
Second, serving static pages remains the simplest and most effective solution. The article “Linux & Scaling: The Essentials” provides a fascinating account of how a surge of traffic crippled a dynamic site. Converting everything to static content restored the system. The creators of LiveJournal have also observed that static content is easy to handle (see page 30 of “Inside LiveJournal’s Backend” (PDF)).
From the above discussion, we may surmise that the paradigm of dynamically generating pages for every request is often wrong. On the Web, pure reads greatly outnumber writes. Clearly, it makes more sense to generate a page only when its contents change, then serve the static HTML file in response to all read requests. The site is effectively dynamic, but the Web server operates on plain HTML files. This “Relative Static” (with respect the Web server) approach is the focus of this article.
BoSStats and FlightFeather
FlightFeather is a FOSS project designed around the Relative Static technique. The goal of FlightFeather is “social networking for everyone”. Careful conservation of bandwidth and other resources should enable many people to run a popular social network of their own. Of course, even large companies are now in need of resource-thrifty software, as the exploding electricity consumption of ever larger server farms puts a limit on growth.
BoSStats is FlightFeather’s first application. It is a social networking site dedicated to improving the world of work. There, you can discuss what makes a good boss, or talk about office politics. Because this is a sensitive topic, BoSStats provides plenty of privacy protection. There are no cookies, no gathering of e-mail addresses, and full support for anonymous posting.
Good advice about problems on the job, how to manage one’s career, how to avoid being fired, is often very difficult to find, unless you have a close friend or relative with just the right experience. After all, it is still unacceptable to discuss certain realities of the workplace in “polite society”. BoSStats attempts to create a safe environment (hence the privacy protection) where the “Wisdom of Crowds” can work to collect the information that is vital to anyone who holds a job.
BoSStats should also help the continued development of FlightFeather, by providing real-world traffic with which to perfect the Relative Static methodology that is at the core of the system.
The next section covers the software components which underlie BoSStats and FlightFeather.
Choosing the components
The LAMP platform, in its canonical form, consists of Linux, Apache, MySQL and one of Perl, Python or PHP. LAMP is still an excellent core toolset, but you do not always need all the components.
Specifically, the “M” in this formula refers to an RDBMS, which a Relative Static solution does not use. So, we get the LAP platform, in which the application tries to capture as much system state as possible in plain HTML files, instead of storing it in a relational database.
In a LAP application, you will likely rely more on in-memory caches and state-keeping data structures than if you use an RDBMS. You can reconstruct this in-memory data from the HTML files when the application starts. An embedded database (such as Berkeley DB) can also assist with system state maintenance.
The “P” in FlightFeather’s case is Python. This language has a very clear, uncluttered structure, and readily supports advanced programming constructs. FlightFeather uses Version 2.5 of Python, which is the latest stable release at the time of writing.
FlightFeather uses Linux in the traditional way (such as it runs as a standard, user-space application) but the integration with Apache is less typical (see the next section for details).
Now that we have all the parts, we can build our Relative Static Web.
The Relative Static Web
FlightFeather stores most of its data in plain HTML files. Memory-based data structures keep track of this information. For example, each time a user votes for a post, FlightFeather stores the new vote count in RAM, and also updates the HTML file corresponding to that post. On startup, FlightFeather scans the HTML files (stored in several pieces on disk, as well as in fully assembled form) to rebuild the required state information in memory. Berkeley DB hashtables also hold some of FlightFeather’s data, such as user passwords.
The Relative Static approach requires extensive manipulation of flat files. Python Version 2.5 introduces the with statement, which is particularly helpful here. A “with” statement block uses a context manager, which allocates and releases resources. The context manager can take a different course of action depending on how control leaves the body of the “with” statement (normally or because of an exception).
Given the right context manager, you do not have to worry about resource cleanup in the body of the “with” statement. To handle multiple files in a clean manner, FlightFeather includes such a custom context manager.
There are many ways to use Apache in a LAMP (or LAP) application. For example you can use Python with the mod_python module, or Perl with mod_perl. These modules load Python and Perl, respectively, directly into Apache. FlightFeather, however, opts for a minimalist approach to Apache integration.
The FlightFeather server is a standalone, single-threaded Python program. Apache acts as a proxy, passing complete requests to FlightFeather for processing. FlightFeather, in turn, generates static HTML files, which Apache serves to clients. The static pages include JavaScript, which generates the requests to FlightFeather in response to user input. The requests, submitted via AJAX, travel through the Apache proxy to the FlightFeather server.
This configuration achieves concurrency with a very lightweight Apache configuration, avoids heavy use of threads in Python (which is inefficient), and generally minimizes context switches needed to handle a request. Effective concurrent programming actually strives to reduce the number of threads or processes in the system (see “Understanding Network I/O, Part 2”).
The approach also improves reliability, by separating simple read requests from more complex writes. Even if FlightFeather fails, Apache can serve the static pages generated earlier, so the site still satisfies the demands of most visitors (who only read the content).
The JavaScript part of FlightFeather focuses on usability and compactness, instead of heavy special effects. The scripts are only 11K in size, which adds very little overhead to the page. The protocol used in the AJAX calls is similarly compact, avoiding XML and even the more efficient JSON. For future extensibility, FlightFeather allows the easy replacement of its protocol components, on both the client (JavaScript) and server (Python) side.
While the Relative Static approach accelerates reads, it can also be very fast for writes. The application is close to its data — which provides many opportunities for optimization.
Even Web sites that focus primarily on data visualization (rather than text) can benefit from the Relative Static technique. In many cases, image-generating tools need only run when the underlying information changes. If the tools produce static graphics files (in PNG format, for example) the Web server can later deliver them in response to client requests (see related article on this approach.
Regardless of which method you ultimately choose for your dynamic site, do not make assumptions about performance. Test the system, starting from the earliest possible stage of development. ApacheBench (part of the Apache HTTPD project) is a FOSS benchmarking tool that is flexible and very easy to use — it takes just minutes to create a simple test. Remember, you cannot improve what you do not measure.




