Lakshya

Infrastructure & Reliability · Middleware — Web · Chapter 20 of 33

Web servers, reverse proxies and application servers, from zero

What happens between a customer pressing Log in and a database being asked a question — the tiers, the pools, and the two settings that decide whether the estate survives a busy morning.

10 min read2 diagramsAll 33 chapters

Start with one click. A customer opens the bank’s website and presses Log in. Before any business logic runs, that request crosses four or five pieces of middleware, each with a different job, and each able to fail in a way that looks, from the outside, exactly like every other failure: the page does not load.

The request, hop by hop

  • Name lookup. The browser asks the Domain Name System (DNS) which address serves the bank’s hostname. Covered in DNS.
  • Load balancer. The address usually belongs to a load balancer, not a server. It picks a healthy web server and forwards the connection. Covered in load balancing.
  • Web server. Terminates the encrypted connection, serves anything static, and passes everything else inward.
  • Application server. Runs the bank’s code: checks the password, calls the authentication service, builds the page.
  • Back-end systems. A database, a queue manager in front of the core banking system, or another service’s API.

What a web server actually does

The name undersells it. A modern web server does six jobs, and in a bank the first three matter most:

JobWhat it meansWhy a bank cares
Terminate TLSTransport Layer Security (TLS) encrypts the connection and proves the server’s identity with a certificate. The web server holds the certificate and does the decryption.The certificate is the bank’s identity on the internet; its private key is a crown jewel.
Reverse proxySits in front of the real servers and forwards requests to them, so the outside world only ever sees the proxy.Internal servers, their addresses and their software versions stay hidden.
FilterReject malformed requests, enforce size limits, hand traffic to a web application firewall that blocks known attack patterns.The first line against the attacks in web vulnerabilities.
Serve static contentImages, scripts and style sheets straight from disk or cache.Keeps expensive application servers for work that needs them.
Balance and routeSpread requests across application servers; send /cards to one cluster and /loans to another.Lets teams deploy independently behind one address.
LogRecord every request: who, what, when, how long, what status.Often the first evidence in an incident or a fraud investigation.

A reverse proxy is so called because it is the mirror of the proxy most people know: a forward proxy acts on behalf of clients going out to the internet, a reverse proxy acts on behalf of servers receiving traffic from it.

What an application server adds

An application server is a runtime for business code. In banks that code is overwhelmingly Java, and the application server is a long-running Java process — a Java Virtual Machine (JVM) — that hosts many applications and gives them a set of services so each does not have to build its own:

  • A request pipeline — the part that turns an HTTP request into a call to your code. In Java this is the servlet container; Apache Tomcat is only this part.
  • Connection pools to databases and message brokers, so an application borrows an open connection rather than opening a new one per request.
  • Transactions, including ones that span a database and a message queue and must succeed or fail together.
  • Messaging through a standard Java interface, so code can put a message on an IBM MQ queue without being written for IBM MQ specifically.
  • Security — logins, roles and single sign-on handled by the server, not re-implemented in every application.
  • Clustering and administration — many copies of the server managed as one, with a console, deployment tooling and monitoring.

The full set of these services is a published specification. It was called Java EE (Java Enterprise Edition) under Sun and then Oracle. Oracle handed it to the Eclipse Foundation in 2017, and in 2018 it was renamed Jakarta EE. A server that implements all of it — IBM WebSphere, Oracle WebLogic, Red Hat JBoss — is a full application server. Tomcat implements only the web part. That distinction drives both architecture and licence cost, and later chapters return to it.

THE CLASSIC BANK WEB ESTATE — FOUR ZONES, THREE FIREWALLS INTERNETDMZAPPLICATION ZONEDATA ZONE firewallfirewallfirewall Customerbrowser or mobile appLoad balancerspreads the trafficWeb serverTLS, static files, proxyApplication serverruns the bank's codeDatabasethe system of recordQueue managerIBM MQ, to the core a cluster of Java processes TLS usually ends here, then is re-encrypted going inward. Code, credentials and sessions live here — never in the DMZ. Everything upstream waits on these two. Untrusted by definition. Each firewall allows only the one hop to its right. A web server compromised in the DMZ should reach nothing but the app tier.
The shape almost every bank web estate shares. The demilitarised zone (DMZ) — a network segment between the internet and the internal network, reachable from both but trusted by neither — holds only what must face the internet. Each firewall permits one hop to the next zone and nothing else, so a compromised web server should reach nothing but the application tier.

The rule the diagram encodes

Nothing in the DMZ should hold anything worth stealing. No business logic, no database credentials, no customer data at rest. The web server there is a guarded doorway, and a doorway that is broken into should open onto one more locked door. When an audit finds application code or a database password on a DMZ host, this is the principle it has broken.

The two settings that decide a busy morning

Every application server has a thread pool — the maximum number of requests it will work on at once — and a connection pool for each database or broker it talks to. Most web-tier incidents that are not certificate expiries come down to one of these filling up, and the arithmetic that predicts it fits on one line.

Little’s law says that the number of requests in flight equals the rate at which they arrive multiplied by the time each one spends in the system. It holds for any stable queue — a bank branch, a call centre, a thread pool — and needs no assumptions about the pattern of arrivals.

LITTLE’S LAW: REQUESTS IN FLIGHT = ARRIVAL RATE × TIME EACH ONE TAKES AN ORDINARY MORNING 200 requests a second × 0.25 seconds each = 50 requests in flight 50 of 100 threads busy THE DATABASE SLOWS TO 2 SECONDS — NOTHING IS DOWN 200 requests a second × 2 seconds each = 400 requests in flight +300 queued, then timing out bar = the pool of 100 threads, drawn to scale; the queue beyond it is not THE DATABASE DID NOT FAIL. IT GOT SLOWER — AND THE WEB TIER RAN OUT OF THREADS. No “down” alert fires, because nothing is down. Customers see spinners, then errors — even on pages that never touch the database, because every request needs a thread first.
Slow is worse than down. A database that fails outright makes requests fail fast and frees their threads. A database that merely slows down holds every thread open, and the pool fills for everything — the same lesson as the latency experiments in chaos engineering.

The defences follow directly from the arithmetic:

  • Timeouts on every outbound call, set from the downstream system’s real latency, not a default of sixty seconds. If the database hangs rather than slows, each request's time in the system becomes the timeout: 200 a second × 60 seconds is 12,000 requests in flight; with a two-second timeout it is 400.
  • Timeouts that compose. If the load balancer gives up after 30 seconds but the application waits 60 for the database, the customer has gone and the thread is still working. Each outer timeout must be longer than the inner one it wraps.
  • Separate pools for separate dependencies (called bulkheads, after the watertight compartments in a ship), so one slow system cannot consume every thread.
  • Fail fast when a dependency is sick — a circuit breaker stops calling a system that is timing out, and returns an immediate error or a cached answer instead.

Sessions: why logging in is a middleware problem

HTTP is stateless: each request arrives with no memory of the last. A logged-in session is therefore an illusion maintained by the server — a cookie in the browser carries an identifier, and the server looks up what that identifier means. Where that lookup lives is an architectural decision with a visible consequence:

Where the session livesWhat happens when a server diesTrade-off
In one server’s memory, with sticky routing (the load balancer always sends a user back to the same server)Everyone on that server is logged outFast and simple; every failure and every patch is visible to customers
Replicated between servers in the clusterAnother server already holds a copySurvives failure; costs memory and network traffic, and replication has its own failure modes
In an external store (a database or an in-memory cache)Any server can pick the user upServers become interchangeable; the store must now be highly available itself
In a signed token the browser carriesNothing — the server holds no sessionNo server state at all; revoking a token before it expires is harder

A bank that sees customers logged out during every monthly patch has chosen the first row, whether or not anyone decided to.

Health checks and draining

A load balancer needs to know which servers to use. Two kinds of check matter. A liveness check asks whether the process is running at all. A readiness check asks whether it should be sent traffic now — it may be alive but still starting, or alive but unable to reach its database. Conflating the two sends customers to a server that is up but useless.

Draining is the other half: before a server is patched, the load balancer stops sending it new requests and lets the in-flight ones finish. A cluster patched without draining drops every request that happened to be on the node at the moment it stopped.

Check yourself

What are the hops between a browser and a bank's database?DNS lookup, load balancer, web server, application server, then the back-end system — database, queue manager or another API.
What is a reverse proxy?A server that receives traffic on behalf of the real servers behind it, so the outside world only sees the proxy — the mirror of a forward proxy, which acts for clients going out.
What does an application server provide that a web server does not?A runtime for business code, with request handling, connection pools, transactions, messaging, security and clustering.
What is the difference between Tomcat and WebSphere?Tomcat is a servlet container — only the web part of the Jakarta EE specification. WebSphere, WebLogic and JBoss implement the full specification.
Why must nothing valuable live in the DMZ?It is reachable from the internet and trusted by neither side; a compromised web server there should open onto one more locked door, not onto data or credentials.
State Little's law and apply it.In-flight requests = arrival rate × time in system. 200/s × 0.25 s = 50 in flight; if each takes 2 s, 400.
Why is a slow dependency worse than a dead one?A dead one fails fast and frees threads; a slow one holds every thread open, so the pool fills for all requests.
What does 'timeouts must compose' mean?Each outer timeout must be longer than the inner one it wraps, or the caller gives up while the work continues.
Why do customers get logged out during patching?Sessions live in one server's memory with sticky routing, and are neither replicated nor stored externally.
What is the difference between liveness and readiness?Liveness asks whether the process runs; readiness asks whether it should receive traffic now.
← Middleware: the layer between the application and everything elseThe web tier in a bank: real flows, real failures →