9 Web Servers, Application Servers & Architectural Patterns
9.1 Web Servers
9.1.1 What is a Web Server?
A web server is a dedicated server whose primary function is to serve web requests, typically using HTTP/HTTPS protocol.
9.1.2 Responsibilities
- Serve static content: HTML documents, images, CSS stylesheets, JavaScript files
- Handle HTTP requests: Process GET, POST, PUT, DELETE requests
- SSL/TLS termination: Handle HTTPS connections
- Load balancing: Distribute requests (when configured)
- Compression: Gzip, Brotli compression
- Caching: Cache static resources
9.1.3 Popular Web Servers
- NGINX: High-performance, event-driven, reverse proxy
- Apache HTTP Server: Feature-rich, module-based
- Microsoft IIS: Windows-based web server
- Caddy: Automatic HTTPS, modern features
9.1.4 Example: NGINX Configuration
server {
listen 80;
server_name example.com;
# Serve static files
location /static/ {
root /var/www/html;
expires 30d;
}
# Proxy to application server
location /api/ {
proxy_pass http://app_server:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
9.2 Application Servers
9.2.1 What is an Application Server?
An application server hosts and executes business logic and application code. It provides the runtime environment for applications to run.
9.2.2 Responsibilities
- Execute business logic: Process complex operations
- Manage application state: Session management, caching
- Database connections: Connection pooling, ORM
- Transaction management: ACID transactions
- Security: Authentication, authorization
- API endpoints: RESTful APIs, GraphQL
9.2.3 Environment Provided
Software:
- Runtime (Node.js, Java JVM, Python interpreter, .NET runtime)
- Frameworks (Express, Spring Boot, Django, ASP.NET)
- Libraries and dependencies
Hardware:
- CPU, memory allocation
- Network configuration
- File system access
9.2.4 Popular Application Servers/Frameworks
- Node.js: JavaScript runtime, event-driven
- Spring Boot (Java): Enterprise Java applications
- Django/Flask (Python): Web frameworks
- Express.js: Minimal Node.js framework
- ASP.NET Core: Microsoft’s web framework
- Ruby on Rails: Ruby web framework
9.2.5 Example: Express.js Application Server
const express = require('express');
const app = express();
// Middleware
app.use(express.json());
// Business logic endpoint
app.post('/api/orders', async (req, res) => {
try {
// Process order
const order = await processOrder(req.body);
// Save to database
await db.orders.insert(order);
// Send notification
await sendOrderConfirmation(order);
res.status(201).json(order);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(8080);9.3 Web Server vs Application Server
| Aspect | Web Server | Application Server |
|---|---|---|
| Primary Role | Serve static content | Execute business logic |
| Content | HTML, CSS, JS, images | Dynamic content generation |
| Protocol | HTTP/HTTPS | Multiple (HTTP, RPC, etc.) |
| State | Stateless | Can be stateful |
| Examples | NGINX, Apache | Node.js, Spring Boot |
| Performance | Very fast (static) | Depends on logic complexity |
9.3.1 Modern Architecture
In practice, they often work together:
Client → Web Server (NGINX) → Application Server (Node.js) → Database
↓
Static files served directly
9.4 Architectural Patterns
Architectural patterns define how components are organized and interact within a system.
9.4.1 1. Monolithic Architecture
Definition: Entire application is built as a single, unified component.
Structure:
┌────────────────────────────┐
│ Monolithic Application │
│ │
│ ┌──────────────────────┐ │
│ │ Presentation Layer │ │
│ └──────────────────────┘ │
│ ┌──────────────────────┐ │
│ │ Business Logic │ │
│ └──────────────────────┘ │
│ ┌──────────────────────┐ │
│ │ Data Access Layer │ │
│ └──────────────────────┘ │
└────────────────────────────┘
↓
Single Database
Characteristics:
- Single codebase
- Single deployment unit
- Shared database
- Tightly coupled components
Pros:
- ✅ Simple to develop initially
- ✅ Easy to test (everything in one place)
- ✅ Simple deployment
- ✅ No network latency between components
- ✅ Strong consistency
Cons:
- ❌ Hard to scale (must scale entire app)
- ❌ Tight coupling (changes affect everything)
- ❌ Long deployment cycles
- ❌ Technology lock-in (one stack for everything)
- ❌ Large codebase becomes unmanageable
When to use:
- Small applications
- Early-stage startups
- Simple requirements
- Small team
Example:
Traditional e-commerce application with all features (auth, catalog, cart, checkout, inventory) in one application.
9.4.2 2. Layered Architecture

Definition: Components organized into logical horizontal layers, each with specific responsibilities.
Typical Layers:
┌────────────────────────────┐
│ Presentation Layer │ ← UI, API endpoints
├────────────────────────────┤
│ Business Logic Layer │ ← Core logic, services
├────────────────────────────┤
│ Data Access Layer │ ← Database interaction
├────────────────────────────┤
│ Database Layer │ ← Persistent storage
└────────────────────────────┘
Rules:
- Each layer only communicates with adjacent layers
- Request flows top to bottom
- Each layer has specific responsibility
Pros:
- ✅ Clear separation of concerns
- ✅ Easy to understand structure
- ✅ Layers can be developed independently
- ✅ Testable (mock adjacent layers)
- ✅ Maintainable
Cons:
- ❌ Can become monolithic
- ❌ Performance overhead (through layers)
- ❌ Changes may ripple through layers
Example:
// Presentation Layer (Controller)
app.get('/users/:id', async (req, res) => {
const user = await userService.getUser(req.params.id);
res.json(user);
});
// Business Logic Layer (Service)
class UserService {
async getUser(id) {
const user = await userRepository.findById(id);
// Business logic
return user;
}
}
// Data Access Layer (Repository)
class UserRepository {
async findById(id) {
return await db.query('SELECT * FROM users WHERE id = ?', [id]);
}
}9.4.3 3. Service-Oriented Architecture (SOA)

Definition: Application structured as collection of services that communicate via well-defined interfaces.
Key Concepts:
- Services: Independent, reusable components
- Service Contract: Interface definition (WSDL, API spec)
- Service Registry: Directory of available services
- Enterprise Service Bus (ESB): Communication middleware
Characteristics:
- Coarse-grained services
- Services communicate via protocols (SOAP, HTTP)
- Shared database possible
- Enterprise-focused
Pros:
- ✅ Service reusability
- ✅ Location transparency
- ✅ Interoperability (cross-platform)
- ✅ Scalability
Cons:
- ❌ Complex infrastructure (ESB)
- ❌ Heavyweight protocols (SOAP/XML)
- ❌ Governance overhead
- ❌ Can be slow
Example Services:
- User Service
- Payment Service
- Notification Service
- Order Service
Communication:
<!-- SOAP Request -->
<soap:Envelope>
<soap:Body>
<getUserInfo>
<userId>123</userId>
</getUserInfo>
</soap:Body>
</soap:Envelope>9.4.4 4. Microservices Architecture

Definition: Application built as collection of small, independent services, each running in its own process (Newman 2021; Richardson 2018).
Key Principles:
- Single Responsibility: Each service does one thing well
- Independently Deployable: Deploy without affecting others
- Decentralized: No central coordination
- Smart endpoints, dumb pipes: Services own their logic
- Database per service: Each service has its own database
Characteristics:
- Fine-grained services
- Lightweight communication (REST, gRPC, messaging)
- Separate databases
- Organized around business capabilities
- Owned by small teams
Pros:
- ✅ Independent deployment
- ✅ Technology diversity (polyglot)
- ✅ Fault isolation (one service fails ≠ all fail)
- ✅ Scalability (scale services independently)
- ✅ Team autonomy
- ✅ Easier to understand (small services)
Cons:
- ❌ Complex infrastructure
- ❌ Distributed system challenges
- ❌ Network latency
- ❌ Data consistency issues
- ❌ Testing complexity
- ❌ Operational overhead
Common Components:
API Gateway
Role: Single entry point for clients
Responsibilities:
- Request routing
- Authentication/authorization
- Rate limiting
- Request/response transformation
- Aggregation of responses
Example:
Client → API Gateway → [User Service, Order Service, Product Service]
Service Discovery
Role: Services register and discover each other
Tools:
- Consul
- Eureka
- etcd
- Kubernetes DNS
Example:
// Service registers itself
serviceRegistry.register({
name: 'user-service',
host: 'localhost',
port: 8001
});
// Another service discovers it
const userService = await serviceRegistry.discover('user-service');Service Management
Responsibilities:
- Health monitoring
- Logging and tracing
- Configuration management
- Service mesh (Istio, Linkerd)
When to use Microservices:
- Large, complex applications
- Multiple teams
- Need for independent scaling
- Technology diversity requirements
- Frequent deployments
When NOT to use:
- Small applications
- Small team
- Unclear domain boundaries
- Tight coupling required
9.5 Comparison of Architectural Patterns
| Pattern | Complexity | Scalability | Deployment | Team Size | Best For |
|---|---|---|---|---|---|
| Monolithic | Low | Limited | Simple | Small | Simple apps, MVPs |
| Layered | Low-Med | Limited | Simple | Small-Med | Structured monoliths |
| SOA | High | Good | Complex | Large | Enterprise integration |
| Microservices | Very High | Excellent | Complex | Large | Large-scale, distributed |
9.6 Evolution Path
Many successful companies follow this evolution:
Monolithic → Modular Monolithic → SOA → Microservices
↓ ↓ ↓ ↓
Simple Better structure Services Full distribution
Don’t start with microservices unless you have:
- Clear domain boundaries
- Experienced team
- Need for independent scaling
- Resources for operational complexity
9.7 Best Practices
9.7.1 For All Architectures
- Start simple: Don’t over-engineer
- Clear boundaries: Define component responsibilities
- Loose coupling: Minimize dependencies
- High cohesion: Related functionality together
- Documentation: Architecture diagrams, API docs
9.7.2 For Microservices Specifically
- Domain-Driven Design: Identify bounded contexts
- API Versioning: Support backward compatibility
- Circuit Breakers: Handle service failures gracefully
- Distributed Tracing: Jaeger, Zipkin for debugging
- Centralized Logging: ELK stack, Splunk
- Container Orchestration: Kubernetes, Docker Swarm
- CI/CD Pipeline: Automated testing and deployment
9.8 Summary
Web Servers:
- Serve static content
- Handle HTTP requests
- Often used as reverse proxy
Application Servers:
- Execute business logic
- Provide runtime environment
- Handle dynamic content
Architectural Patterns:
- Monolithic: Simple, but limited scalability
- Layered: Organized, maintainable structure
- SOA: Service reusability, enterprise-focused
- Microservices: Highly scalable, complex
Choose based on:
- Application complexity
- Team size and expertise
- Scalability requirements
- Deployment frequency
- Operational capabilities
Start simple, evolve as needed. Premature optimization leads to unnecessary complexity.