SystemExpertsSystemExperts
Pricing

Open Source

10 items

Redis: In-Memory Data Structure Store

45mintermediate

Apache Kafka: Distributed Event Streaming Platform

40mintermediate

Kubernetes: Container Orchestration Platform

50mintermediate

Nginx: High-Performance Web Server and Reverse Proxy

40mintermediate

PostgreSQL: The World's Most Advanced Open Source Database

50madvanced

Apache Cassandra: Distributed Wide-Column Store

40madvanced

etcd: Distributed Reliable Key-Value Store

35madvanced

Apache ZooKeeper: Distributed Coordination Service

40madvanced

Envoy Proxy: Modern L7 Proxy and Communication Bus

40madvanced

Apache Hadoop: Distributed Storage and Processing

50madvanced
nginxweb-serverreverse-proxyload-balancerhttpperformancecachingintermediate

Nginx: High-Performance Web Server and Reverse Proxy

The event-driven web server that handles millions of concurrent connections - powering 34% of the web

C|21,000 stars|Updated January 2024|40 min read
View on GitHub

Summary

Nginx (pronounced "engine-x") solves the C10K problem - handling 10,000+ concurrent connections efficiently. Unlike Apache's process-per-connection model, Nginx uses an event-driven, non-blocking architecture where a single worker process handles thousands of connections using epoll/kqueue. This makes Nginx extremely memory-efficient (2.5MB per 10K idle connections vs 2.5GB for Apache). Beyond serving static files, Nginx excels as a reverse proxy, load balancer, and API gateway.

Key Takeaways

Event-Driven Architecture

One worker process handles thousands of connections using non-blocking I/O and event notifications (epoll on Linux, kqueue on BSD). No thread-per-connection overhead means predictable memory usage regardless of connection count.

Master-Worker Process Model

A master process manages configuration and worker lifecycle. Workers are independent - if one crashes, others continue serving. This enables zero-downtime configuration reloads and binary upgrades.

Modular Request Processing

Request handling is split into phases (post-read, rewrite, access, content, log). Modules hook into specific phases, enabling clean separation between authentication, caching, proxying, and logging.

Nginx was created by Igor Sysoev in 2002 to solve Rambler's (Russian search engine) scaling problems. At the time, Apache dominated the web server market but struggled with high concurrency - the C10K problem.

The C10K Problem: How do you handle 10,000+ simultaneous connections on a single server?

Apache's approach: one process (or thread) per connection - 10,000 connections = 10,000 processes - Each process: ~2-10MB memory overhead - Result: 20-100GB RAM just for connection handling - Context switching kills performance

Nginx's approach: event-driven, non-blocking I/O - 10,000 connections = 1 worker process - Memory: ~2.5KB per connection - Result: ~25MB for 10,000 connections - No context switching between connections

Apache vs Nginx Connection Handling

Common use cases today:

  1. Static file server: Serve HTML, CSS, JS, images with minimal resource usage
  2. Reverse proxy: Forward requests to backend application servers
  3. Load balancer: Distribute traffic across multiple backends
  4. SSL/TLS termination: Handle encryption at the edge
  5. API gateway: Rate limiting, authentication, request routing
  6. Caching proxy: Cache responses to reduce backend load
  7. HTTP/2 and gRPC proxy: Protocol translation

Summary

Nginx (pronounced "engine-x") solves the C10K problem - handling 10,000+ concurrent connections efficiently. Unlike Apache's process-per-connection model, Nginx uses an event-driven, non-blocking architecture where a single worker process handles thousands of connections using epoll/kqueue. This makes Nginx extremely memory-efficient (2.5MB per 10K idle connections vs 2.5GB for Apache). Beyond serving static files, Nginx excels as a reverse proxy, load balancer, and API gateway.

Key Takeaways

Event-Driven Architecture

One worker process handles thousands of connections using non-blocking I/O and event notifications (epoll on Linux, kqueue on BSD). No thread-per-connection overhead means predictable memory usage regardless of connection count.

Master-Worker Process Model

A master process manages configuration and worker lifecycle. Workers are independent - if one crashes, others continue serving. This enables zero-downtime configuration reloads and binary upgrades.

Modular Request Processing

Request handling is split into phases (post-read, rewrite, access, content, log). Modules hook into specific phases, enabling clean separation between authentication, caching, proxying, and logging.

Efficient Static File Serving

Nginx uses sendfile() to transfer files directly from disk to network socket without copying to user space. Combined with memory-mapped files and open file caches, it achieves near-hardware-limit throughput.

Upstream Connection Pooling

When proxying, Nginx maintains persistent connections to backend servers. This eliminates TCP handshake overhead and enables efficient HTTP/2 multiplexing to backends that only support HTTP/1.1.

Shared Memory Zones

Workers share state through shared memory zones - used for caching, rate limiting, and session persistence. Lock-free data structures minimize contention between workers.

Deep Dive

Nginx was created by Igor Sysoev in 2002 to solve Rambler's (Russian search engine) scaling problems. At the time, Apache dominated the web server market but struggled with high concurrency - the C10K problem.

The C10K Problem: How do you handle 10,000+ simultaneous connections on a single server?

Apache's approach: one process (or thread) per connection - 10,000 connections = 10,000 processes - Each process: ~2-10MB memory overhead - Result: 20-100GB RAM just for connection handling - Context switching kills performance

Nginx's approach: event-driven, non-blocking I/O - 10,000 connections = 1 worker process - Memory: ~2.5KB per connection - Result: ~25MB for 10,000 connections - No context switching between connections

Apache vs Nginx Connection Handling

Common use cases today:

  1. Static file server: Serve HTML, CSS, JS, images with minimal resource usage
  2. Reverse proxy: Forward requests to backend application servers
  3. Load balancer: Distribute traffic across multiple backends
  4. SSL/TLS termination: Handle encryption at the edge
  5. API gateway: Rate limiting, authentication, request routing
  6. Caching proxy: Cache responses to reduce backend load
  7. HTTP/2 and gRPC proxy: Protocol translation

Trade-offs

AspectAdvantageDisadvantage
Event-driven architectureHandles 10K+ connections with minimal memory (2.5KB/conn vs 2MB/conn for process-per-connection)Long-running synchronous operations (like slow disk I/O) can block other connections in the same worker
Single-threaded workersNo locking overhead, predictable performance, simple debuggingCannot utilize CPU parallelism within a single connection; complex async code
Configuration languageDeclarative, easy to read, supports includes and variablesNot a full programming language - limited logic capabilities compared to Lua/OpenResty
Static configurationConfiguration is validated at reload time - no runtime config errorsDynamic upstream changes require reload or Plus subscription; no API for runtime changes in OSS
Shared memory zonesEfficient cross-worker state sharing for caching, rate limiting, sessionsFixed size at startup; running out of zone space causes errors
OSS vs PlusCore functionality is free and open sourceActive health checks, dynamic reconfiguration, advanced metrics require paid Nginx Plus

Premium Content

Sign in to access this content or upgrade for full access.