Designing a Server


Introduction

Much has been written about the benefits of client-server designs and why they work and work well. But far less has been written about where good servers come from--what kinds of processes make good servers and how they're constructed.

Much of the available literature comes from middleware vendors and standards organizations describing how to use some proprietary or public domain Application Programming Interface (API). APIs are important because they determine how easily (or difficult) your server is to access from clients. As importantly they also prescribe much about how your server is constructed and its capabilities.

This paper covers those topics by describing how a thin but dedicated API can simplify the accessibility and increase the scalability of your server, while at the same time allowing the designer to focus on the server--increasing its utility and reliability, without the distractions of an overbearing middleware component.

What makes a good server?

Before listing recipes, its a good idea to look at other successful servers and begin recognizing what they have in common, or what attributes they have that lend them to server processing.

Database Servers

One of the most obvious and familiar examples are database engines. Products from Sybase, Oracle, Informix and others are examples of servers. A single (or in some cases, multiple) process has singular control over a single (or pooled) resource.

Without going through and enumerating each benefit from the server side, lets imagine what it would be like without them:

Transaction Servers

Another popular server example is the transaction server. As unthinkable as it seems to embed database access into client processes, it has become to embed transaction logic. A client needs only know that it wants to deposit money to an account, should it have to know how that is accomplished?

X Windows

The last example is well known, but not well comprehended. The X windows system from MIT reverses the roles hardware plays in the client server drama. Where in most cases smaller client computers make requests of larger host computers, X extends the services of the user's display, mouse, and keyboard to a client process running on another machine. So the host is the user's equipment and the client is a program running elsewhere on the network.

If you've made it this far, you probably have a server in mind. Let's build it.

Server Design: Divide and Conquer

Traditional servers have two responsibilities: the service they provide and the housekeeping necessary to provide it. The service is whatever unique functionality your server was intended to do in the first place. A transaction server performs transactions. A stock quote server delivers stock quotes. A database server manipulates databases. Housekeeping, on the other hand, is the code that has little or nothing to do with your service but is necessary to the operation of your server; like network communications, threading, metering, logging and administration to name a few. All servers have housekeeping in common.

The more the programmer focuses on the service the better a service that gets provided. Servers are written because they offer a unique and reusable service to other processes. A server's first priority should be its unique processing. Its next priority should be the housekeeping required to maintain client connections. If you were to weigh the service code against the housekeeping code, it should weigh heavily in favor of the service.

Since all servers must do housekeeping, it is possible that multiple servers could re-use the same housekeeping code. Applying our client-server yardstick, housekeeping is itself a service and could be constructed as such. This is where middleware makes its niche.

Once the housekeeping code is created, it becomes more or less constant, and is itself reusable.

Do not eliminate a potential server candidate simply because you suspect it would be more trouble than its worth.

Focus for a minute just on the network. A server must be able to:

This list doesn't seem overwhelming until you begin to consider what's required to accomplish some of these items. Even competent network programmers must consider:

When most people think of client/server, they think of GUI applications accessing a databases through a network. Though this is an obvious client/server example, it is no longer a competitive one.

In distributed processing, a server provides a service to a client. Server processes may or may not be on the same machine as the client, and the function they perform for the client may not be faster than if the same function was performed by the client alone.

More importantly than knowing how to write a server is knowing why. By understanding why we can determine how to best exploit their strengths and mitigate drawbacks (and there are a few).

So you want to be a ...

It's important to understand the difference between throughput and speed.

Isectd

Isectd's design represents the result of all of these debates.

  1. Servers should focus on the why, not the how.

    Without some kind of communications framework like isectd provides, stand-alone servers must deal with both the business problem and the systems-level challenges of a robust messaging protocol.

  2. Processes are more flexible than threads.

Copyright © 1997, Isect