Fact-checked by Grok 2 weeks ago

C10k problem

The C10k problem is the scalability challenge in computer networking where a single server struggles to efficiently handle 10,000 simultaneous client connections, a limitation that became prominent as grew in the late 1990s. Coined by software engineer Dan Kegel in 1999, the term highlights the shift from hardware bottlenecks to software and operating system constraints in managing high concurrency on systems. At the time, early web servers like those handling traffic for sites such as cdrom.com could reach this threshold, but traditional architectures failed to scale without significant performance degradation. The core issues stem from inefficient I/O handling and in conventional designs, particularly the one-process-or-thread-per-connection model used by servers like . This approach incurs high overhead from process forking (e.g., approximately 200 microseconds latency on 2.6 kernels) and memory usage, leading to scheduler thrashing and cache inefficiencies when connections exceed a few thousand. Additionally, legacy system calls like select() are limited to 1,024 file descriptors, while poll() suffers from repeated array copying, exacerbating CPU waste on idle connections. These factors result in blocking operations that prevent the server from responding promptly to new requests, even on capable hardware with . To address the C10k problem, developers proposed event-driven architectures using non-blocking I/O and readiness notification mechanisms, such as level-triggered notifications with select() or poll(), though these were insufficient for large scales. More effective solutions include kernel-level interfaces like Linux's epoll (introduced in kernel 2.5), FreeBSD's kqueue, and edge-triggered notifications, which allow a single thread to multiplex thousands of connections without per-connection threads. Other strategies encompass asynchronous I/O via POSIX aio_, thread pools with pre-forking to cap resource use, and zero-copy techniques like sendfile() for efficient data transfer. These innovations, analyzed in detail by 2003, enabled servers to achieve O(1) scaling and handle 10,000 connections on modest hardware, influencing modern frameworks in languages like Go and Node.js.

Introduction

Definition and Scope

The C10k problem refers to the challenge of efficiently handling 10,000 simultaneous connections on a single server, particularly in the context of web servers where hardware advancements in the late —such as 1000 MHz CPUs, 2 GB RAM, and 1000 Mbit/sec Ethernet—made this scale feasible yet difficult to achieve without performance bottlenecks. The term was coined in 1999 by software engineer Dan Kegel, drawing from the real-world example of the FTP site cdrom.com, which served 10,000 clients concurrently over a Gigabit connection, highlighting the need for optimized software to match hardware potential. This problem's scope centers on I/O-bound network applications, such as web servers managing numerous concurrent client requests, rather than workloads dominated by computational intensity or memory-bound scenarios limited by constraints. Prior to the , typical implementations were restricted to hundreds of concurrent connections due to architectural limitations. Critical metrics for evaluating C10k solutions include low CPU utilization per connection (e.g., approximately 50 kHz to support 20,000 clients), minimized per connection to prevent resource exhaustion, and reduced context-switching overhead, which can become prohibitive in traditional multi-threaded designs. For instance, a using inefficient polling methods like select() may maintain 10,000 idle connections effectively but suffer up to 79% performance degradation under active load due to the overhead of scanning all file descriptors repeatedly.

Historical Context

In the pre-1990s era, early web servers such as the NCSA HTTPd and the initial versions of , released in 1995, relied on process-per-connection models that severely restricted , typically handling only around 100 to 1,000 concurrent connections due to memory and operating system constraints. These architectures, which forked a new process for each incoming request, were adequate for the nascent but quickly proved insufficient as demand grew. For instance, 's early configurations defaulted to a maximum of 256 client connections, reflecting the hardware and software limitations of the time. The internet boom, marked by explosive growth in usage from a few million to over 100 million users worldwide by decade's end, exposed these inherent limits in server architectures. This surge in traffic, driven by the commercialization of the and the popularity of browsers, placed immense pressure on existing systems. Discussions on began emerging in online forums as early as 1996, with developers on groups and mailing lists like comp.infosystems.www.servers debating ways to handle growing demands without system crashes. Between 1996 and , these conversations intensified on platforms such as and developer mailing lists, where engineers shared experiences of servers buckling under hundreds of simultaneous connections amid the dot-com expansion. A pivotal moment came in when Dan Kegel published his influential webpage at kegel.com/c10k.html, coining the term "C10k problem" to describe the challenge of efficiently supporting simultaneous connections on a single —a threshold that symbolized the next frontier for web infrastructure. Kegel's accompanying webpage at kegel.com/c10k.html quickly became a central repository for aggregating these early insights and resources on server scalability.

Technical Foundations

Traditional Server Architectures

In the late and early , traditional web servers predominantly employed the -per- model, where a master listened for incoming connections and used system calls like fork() to spawn a dedicated for each new HTTP request. This approach, rooted in the classical UNIX networking paradigm, allowed each to handle the entire lifecycle of a independently, including reading the request, ing it, and sending the response. However, the overhead of creation— involving duplication of the and initialization—proved significant under load, prompting optimizations such as pre-forking a pool of idle worker processes in advance. By the mid-1990s, the emerged as a more efficient alternative, leveraging multi-threading within a single process to assign a lightweight to each incoming . This shift was facilitated by the standardization of threads in 1995 (IEEE Std 1003.1c-1995), which provided a portable for thread creation and management across systems. In this model, a was often pre-allocated to avoid the costs of dynamic thread spawning, with each performing blocking I/O operations synchronously for its assigned . Early adopters included -based servers using the servlet specification (introduced in 1997), where the Java Virtual Machine's built-in threading support enabled one per request or . Both models incurred substantial resource demands, as each or required dedicated resources, including file descriptors for sockets and typically 1-8 MB of space per instance, leading to rapid memory exhaustion with thousands of concurrent . Processes consumed even more due to separate address spaces and higher context-switching costs compared to threads sharing the same process and segments. These architectures exemplified the limits that later defined the C10k problem, capping practical concurrent connections at around 1,000 on typical . Prominent implementations included the NCSA HTTPd server (released in ), which used a pre-forked model to serve early , and the original Apache 1.x series (starting ), employing a prefork multi-processing where a spawned child processes to handle individual connections in isolation.

Resource Limitations

In Unix-like systems prevalent during the 1990s, the default limit on open descriptors per process was , set by the ulimit mechanism and parameters such as fs.file-max. This constraint directly impacted server capacity, as each client connection typically required a dedicated , making it impossible to handle simultaneous connections without administrative tweaks like adjustments to raise the per-process or system-wide limits. The select() further amplified this limitation, as its fd_set bitmask was fixed at FD_SETSIZE= bits, restricting monitoring to at most descriptors per invocation. Memory resources on typical 1990s web servers were severely constrained, with hardware often limited to 64-256 of , as seen in early production setups like Google's 1998 servers equipped with 256 . In -per-connection models common to traditional server architectures, each incurred significant per-connection overhead, including a default size of around 2 per on 32-bit systems, leading to out-of-memory conditions at approximately 1,000 concurrent connections due to cumulative allocation pressures. CPU overhead from kernel scheduling became prohibitive with thousands of processes or threads, as each imposed costs ranging from tens to hundreds of microseconds, depending on parameters and workload. Standard Unix time slices of 10-100 ms exacerbated this for high-concurrency scenarios, while frequent switches among numerous threads caused thrashing—evidenced by thousands of additional CPU cycles per switch from TLB flushes and misses—consuming a substantial portion of available processing cycles. The network stack added further bottlenecks through limited TCP/IP buffer sizes, with defaults around 8-16 KB for receive and send buffers in systems like and early , insufficient for buffering data across thousands of active connections without frequent kernel-user space copies. Additionally, select() and poll() system calls exhibited O(n) inefficiencies for large sets, requiring linear scans of all monitored descriptors on each invocation, which scaled poorly beyond a few hundred connections and dominated in high-load environments.

Core Challenges

Connection Handling Bottlenecks

In traditional server architectures employing blocking I/O, each connection ties up a or that blocks on operations such as read() or write(), causing the CPU to remain idle while awaiting network events. This inefficiency arises because the blocking call suspends the entire thread until data arrives or can be sent, preventing it from handling other connections during that time. As a result, scaling to thousands of concurrent connections requires proportionally more threads, leading to excessive resource consumption and poor CPU utilization at the C10k scale. The select() and poll() system calls, commonly used for I/O multiplexing in early network servers, introduce significant bottlenecks due to their time complexity, where n is the number of file descriptors monitored. Each invocation scans the entire set of descriptors to check for readiness, becoming computationally prohibitive beyond a few thousand connections; for instance, with 10,000 idle connections, throughput can drop by up to 79% compared to more efficient mechanisms. Additionally, select() imposes a hardcoded limit on the maximum file descriptors, typically bits in the fd_set structure, further constraining in high-connection scenarios. Context-switching overhead exacerbates these issues in multi-threaded or multi-process models, where each I/O event triggers frequent switches between user and modes to handle system calls. With increasing connection counts, the cumulative cost of saving and restoring states multiplies, consuming substantial CPU cycles and reducing overall responsiveness. This overhead is particularly acute in models assigning one per , as the must perform these switches for every readiness notification. Wake-up latency in multi-process connection handling manifests as the "thundering herd" problem, where multiple processes waiting on the same listening are simultaneously awakened upon a new arrival. In systems like 2.2 kernels, the accept() call invokes multiple wake-up functions that rouse all waiting processes, only for all but one to fail and return to sleep, wasting CPU resources on unnecessary context switches. At C10k scales, this contention severely degrades performance, tripling the overhead per event and limiting throughput.

Scalability Barriers

The C10k problem highlights systemic barriers to achieving high scalability on single machines, where vertical scaling—upgrading CPU, memory, or on one server—encounters fundamental limits that often necessitate horizontal scaling across multiple servers. Vertical scaling trade-offs include due to hardware constraints, such as single-core CPU bottlenecks in connection events, which cap throughput even on powerful systems. For instance, benchmarks on configurations show a single achieving a connection rate of approximately 4,000 per second under load, limited by CPU rather than . Horizontal scaling introduces its own challenges, primarily through load balancers that distribute traffic but add latency via routing decisions and potential connection inconsistencies. Hash-based load balancing can cause up to 1% violations in per-connection consistency, leading to packet rerouting and increased flow completion times by factors of 2–3x compared to optimized stateless designs. This latency overhead compounds in high-connection environments, where maintaining session affinity across servers requires additional , further straining resources and complicating . Garbage collection and pose significant pitfalls in managed languages like , where thread-per-connection models exacerbate issues under high loads. Each thread consumes substantial memory, such as 2 MB per stack frame, restricting a 1 GB to roughly 512 concurrent threads before exhaustion. During peak connection volumes, collection pauses can halt all threads for seconds—up to 3 seconds in multicore servers—disrupting and amplifying in systems. These stop-the-world pauses become more pronounced on multigigabyte heaps common in scalable servers, where minimizing throughput penalties while ensuring short pauses remains a core challenge for server-oriented collectors. Network congestion effects manifest as SYN flood-like behaviors when connection buildup overwhelms TCP backlog queues, particularly in kernel implementations prone to inefficiencies. In Linux kernels like 2.2.9, multiple threads waiting on the same TCP socket form a wait queue; upon a new connection, the kernel awakens all threads via wake_up_interruptible(), but only one accepts it, triggering the "thundering herd" problem that wastes CPU cycles and triples wake-up events per connection. This inefficiency scales poorly to 10,000 connections, causing backlog overflows and effective congestion even without external attacks, as excessive kernel activity mimics flood conditions and saturates processing resources. Real-world benchmarks illustrate these barriers, with high connection establishment rates, such as 10,000 SYN packets per second, saturating 100 Mbps links. On the CPU side, single-core systems reach saturation handling connection events; for example, a 1 GHz server running the achieves a SpecWeb99 score of around 800 under high load, limited by core processing rather than or I/O. These tests underscore how interactions across layers—software queuing, limits, and —collectively cap at the 10k threshold without architectural changes.

Proposed Solutions

Event-Driven Programming

Event-driven programming emerged as a foundational solution to the C10k problem by enabling servers to handle thousands of concurrent s efficiently within a single-threaded, non-blocking model. This approach utilizes an to multiplex and dispatch I/O events—such as incoming s, data arrivals, or readiness for writes—across multiple client sockets without dedicating resources to each individually. By avoiding the creation of a separate or per , it circumvents the memory and context-switching overheads that plague traditional multi-threaded architectures, allowing a single to manage to 10,000 or more clients. At its core, the paradigm relies on the , where an event demultiplexer monitors file descriptors for readiness, notifying an that then invokes registered callbacks or handlers to process the events synchronously and serially. Key components include the , which continuously awaits notifications; an event queue to hold pending events; and event handlers that encapsulate application-specific logic for read, write, or error events on connections. This structure ensures that the remains responsive, as operations like socket reads or writes are performed non-blockingly, returning control to the loop if no data is immediately available. Unlike traditional polling methods, which inefficiently scan all connections repeatedly and consume CPU cycles even on idle ones, event-driven multiplexing waits passively until events occur. A basic implementation of the can be illustrated with the following , demonstrating the 's role in demultiplexing and dispatching:
# Initialize the reactor
initialize_demultiplexer()  # e.g., select or poll setup
register_event_handlers()  # Associate handlers with file descriptors

# Main event loop
while application_is_running:
    ready_events = demultiplexer.wait_for_events(timeout)  # Block until events ready
    for event in ready_events:
        handler = get_registered_handler(event.file_descriptor)
        if event.type == READ_EVENT:
            handler.handle_read(event)
        elif event.type == WRITE_EVENT:
            handler.handle_write(event)
        # Handle other event types (e.g., errors, closes) similarly
    # Post-processing if needed (e.g., [timer](/page/Timer) events)
This loop scales by limiting active processing to only those connections with pending I/O, maintaining efficiency as connection counts grow. The advantages of this model are particularly pronounced in resource-constrained environments: each connection requires only a few kilobytes of memory for state storage and file descriptors, in contrast to megabytes per in multi-threaded designs, enabling servers to support far higher concurrency without exhausting . Additionally, CPU utilization remains largely constant and independent of the total number of connections, as the single idles efficiently during low activity and spikes only for , reducing overall load. Pioneering implementations in the early 2000s popularized this paradigm for practical use. The library, developed by Niels Provos starting around 2000, provided a portable C library for efficient event notification, abstracting multiplexing mechanisms to support high-concurrency network servers. In Python, the Twisted framework, initiated in 2002 by Glyph Lefkowitz and others, offered an extensible event-driven networking engine for building asynchronous applications, emphasizing non-blocking I/O for protocols like HTTP and . Dan Kegel, who coined the term "C10k problem" in 1999, actively advocated for event-driven techniques in his seminal online resource, highlighting their superiority for scalable servers and influencing subsequent developments in the field.

Asynchronous I/O Mechanisms

Asynchronous I/O mechanisms at the level address the C10k problem by enabling efficient monitoring and notification of I/O events across thousands of file descriptors without the linear scanning overhead of earlier methods like select(). These tools allow a single thread to handle high concurrency by notifying only when events are ready, reducing CPU utilization and improving scalability for network servers. epoll, introduced in the Linux kernel version 2.5.44 in 2002, provides a scalable interface for I/O event notification. It supports level-triggered (default) and edge-triggered modes (via the EPOLLET flag), with the latter notifying only when the file descriptor's state changes from non-ready to ready, minimizing redundant wake-ups. The API consists of three primary system calls: epoll_create() to allocate an epoll file descriptor representing the event structure; epoll_ctl() to add, modify, or delete file descriptors and specify interested events (e.g., EPOLLIN for readable data); and epoll_wait() to block until ready events are available, returning a list of them without rescanning the entire set. This design achieves O(1) time complexity for event readiness checks and modifications, independent of the total number of monitored descriptors. kqueue, developed by Jonathan Lemon and introduced in FreeBSD 4.1 in July 2000, offers a unified event notification system across BSD variants and macOS for monitoring files, sockets, signals, and other kernel objects. The API centers on kqueue(), which creates a kernel queue for event registration, and kevent(), a versatile call that both registers changes (via a changelist of kevent structures specifying filters like EVFILT_READ for input, flags, and data) and retrieves pending events (via an eventlist). Each kevent structure includes fields for identification (ident), filter type, flags (e.g., EV_ADD for adding events), file flags (fflags), data (e.g., for event counts), and user-defined data (udata), enabling flexible filtering and association with application context. Like epoll, kqueue supports edge-triggered notifications and scales efficiently for diverse event sources in a single interface. On Windows, I/O Completion Ports (IOCP), available since , facilitate asynchronous overlapped I/O by associating file handles (including sockets) with a completion port queue, allowing a pool of worker threads to process completions efficiently without busy-waiting. The core API includes CreateIoCompletionPort() to create the port and bind handles (specifying concurrent thread limits for load balancing); asynchronous operations via functions like WSASend() or ReadFile() with an OVERLAPPED structure for context; and GetQueuedCompletionStatus() to dequeue completion packets, which include bytes transferred, errors, and the original OVERLAPPED pointer. This model decouples I/O submission from completion handling, enabling thread pooling where threads block on the port until events complete, optimizing for multiprocessor systems. These mechanisms enable event-driven loops to manage 100,000+ connections with under 1% CPU utilization in idle scenarios, far surpassing select()'s O(n) complexity per call, where n is the descriptor count, as , , and IOCP operate in O(1) for ready event retrieval. For instance, benchmarks with 10,000 idle connections show select() and poll() throughput degrading by up to 79% due to repeated scanning, while remains largely unaffected, highlighting their role in overcoming C10k bottlenecks.

Modern Implementations and Impact

High-Performance Frameworks

Node.js, released in 2009 by Ryan Dahl, emerged as a prominent high-performance framework for addressing the C10k problem through its asynchronous, event-driven architecture. It leverages Google's V8 JavaScript engine for executing server-side JavaScript code and the libuv library to manage non-blocking I/O operations, allowing a single-threaded event loop to handle multiple concurrent requests efficiently without the overhead of traditional threading models. This design enables Node.js to scale to thousands of simultaneous connections, such as managing over 10,000 WebSocket connections in real-time applications like chat systems, where each connection remains open for persistent bidirectional communication. NGINX, developed in 2004 by , represents another foundational high-performance optimized for the C10k challenge with its event-driven core. It utilizes efficient I/O multiplexing mechanisms like on and on BSD systems to monitor and process a large number of file descriptors in a single thread, minimizing context switches and resource usage. Particularly suited for serving static content and acting as a , NGINX excels in high-traffic scenarios; for instance, it can maintain 10,000 inactive HTTP keep-alive connections using only about 2.5 MB of memory per worker process. Benchmarks demonstrate its capability to serve up to 100,000 requests per second on modest hardware with multiple workers, and modern configurations have evolved to support even the C100k problem by handling over a million concurrent connections through optimized load balancing and caching. Other frameworks have also adopted similar principles to achieve massive concurrency. Erlang/OTP, a runtime environment with built-in support for lightweight processes and the , facilitates handling tens of thousands of concurrent connections in distributed systems, as seen in and platforms requiring . In Go, introduced in 2009, goroutines serve as lightweight threads managed by the runtime scheduler, integrating seamlessly with to enable one goroutine per connection without the memory bloat of OS threads, effectively solving the C10k problem in networked applications. These frameworks, powered by primitives, underscore the shift toward scalable, non-blocking designs in post-2000 server technologies.

Ongoing Relevance

In the 2020s, the C10k problem remains pertinent in distributed systems like and applications, where WebSockets enable persistent connections for chat services and interactive features, often demanding to 100,000 or more concurrent users. further amplifies these demands, as deployments require efficient handling of persistent connections from devices behind NATs and firewalls, pushing cloud services to support millions of low-bandwidth, long-lived sessions without performance degradation. Evolving challenges encompass better multi-core utilization to distribute connection processing across hardware threads, addressing limitations in traditional single-threaded models. introduces overhead, such as Docker's default file descriptor limits of 1,024 per process, which can throttle concurrency in high-connection scenarios unless raised to 32,768 or higher via system configurations like /etc/security/limits.conf. Protocol transitions, including the shift to for reduced latency in , necessitate adaptations in connection state management to maintain scalability. The problem's influence extends to cloud infrastructure, where providers like AWS Application Load Balancers scale dynamically using Load Balancer Capacity Units (LCUs) rather than fixed connection caps, allowing architectures to exceed C10k thresholds through adjustable quotas up to 15,000 LCUs per . Serverless computing alleviates single-server C10k pressures via automatic distribution and pay-per-use scaling, yet it does not fully resolve needs in stateful, real-time workloads requiring optimized backends for persistent connections. Frameworks like persist in mitigating these issues within cloud-native and environments. Looking ahead to 2025 and beyond, hybrid approaches combining with multi-threading—such as kernel-bypass stacks achieving 2.5 million requests per second across multiple cores or techniques distributing I/O across 4–8 threads for up to 494% throughput gains—facilitate 1 million or more concurrent connections on commodity . Recent advancements, like io_uring's multishot receives introduced in 2025, further enhance scalability by enabling more efficient completion-based I/O without traditional event loops. These models, evaluated in benchmarks for interactive services, underscore ongoing innovations in messaging and scalability.

References

  1. [1]
    The C10K problem - Dan Kegel
    The first time a server needs disk I/O, its process blocks, all clients must wait, and that raw nonthreaded performance goes to waste. This is what asynchronous ...The C10K problem · Book to Read First · I/O Strategies · Other tips
  2. [2]
    None
    ### Summary of the C10k Problem from "Scalable Network Programming" (2003-10-16)
  3. [3]
    [PDF] Comparing and Evaluating epoll, select, and poll Event Mechanisms
    By comparing results in Figures 3 and 5 one can see that the performance of select and poll degrade by up to 79% when the 10,000 idle connections are added. The ...
  4. [4]
    What to do after hitting the dreaded 256 max connections Apache Limit
    Feb 23, 2013 · By default, the MaxClients parameter has a compiled in hard limit of 256. This can be changed by recompiling Apache however.Apache 2.4 max concurrent users limit - Server FaultWhat limits the maximum number of connections on a Linux server?More results from serverfault.com
  5. [5]
  6. [6]
  7. [7]
    Typical models for high-performance servers
    ### Summary of Process-Per-Connection and Thread-Per-Connection Models in High-Performance Servers
  8. [8]
  9. [9]
    prefork - Apache HTTP Server Version 2.4
    This Multi-Processing Module (MPM) implements a non-threaded, pre-forking web server. Each server process may answer incoming requests, and a parent process ...Missing: x | Show results with:x
  10. [10]
    File Descriptor Requirements (Linux Systems)
    Linux systems limit the number of file descriptors that any one process may open to 1024 per process.Missing: Unix- like 1990s
  11. [11]
    The history of Dedicated Server CPU's till today | Webwerks
    1990s: Rack Mountable Web Server Gradually, when there were increase in ... 1998: First Google server was introduced with 256MB RAM and dual 200 Mhz CPUs.
  12. [12]
    The Effect of Context Switches on Cache Performance
    With the DECstation-5000, for example, the cost ranges from. 10 microseconds. (client-server benchmark) to 400 microseconds. (timesharing benchmark), and our ...
  13. [13]
    [PDF] TCP Buffering and Performance Over An ATM Network
    Mar 16, 1994 · SunGS 4.1.1 calculates TCP MSS as 9148 octets (i.e., 9188 minus the default TCP and IP header sizes) in our ATM network config-.
  14. [14]
    [PDF] Comparing and Evaluating epoll, select, and poll Event Mechanisms
    The performance of epoll2 with idle connections suffers similarly to select and poll. In this case, epoll2 suffers from the overheads incurred by making a large.
  15. [15]
  16. [16]
    LISA 2001 Paper
    ### Summary of Benchmark Examples Showing Saturation at Around 10k Connections
  17. [17]
    [PDF] A High-Speed Load-Balancer Design with Guaranteed Per ...
    Feb 27, 2020 · Abstract. Large service providers use load balancers to dispatch millions of incoming connections per second towards thousands of servers.
  18. [18]
    A performance study of Java garbage collectors on multicore ...
    Pauses of around 3 seconds can make a real-time system unusable and may disrupt the communication between nodes in the case of large-scale distributed systems.
  19. [19]
    A parallel, incremental, mostly concurrent garbage collector for servers
    The challenges for “server-oriented” GC include: ensuring short pause times on a multigigabyte heap while minimizing throughput penalty, good scaling on ...
  20. [20]
    25. LVS: Performance and Kernel Tuning - Huihoo
    My 100Mbps network will carry 10,000 SYN packets/sec when tested with Julian's testlvs program. The performance page calculates the ack as 50% or so of the ...
  21. [21]
    [PDF] reactor-siemens.pdf
    The Reactor design pattern handles service requests that are delivered concurrently to an application by one or more clients. Each service in an application ...
  22. [22]
    libevent
    The libevent API provides a mechanism to execute a callback function when a specific event occurs on a file descriptor or after a timeout has been reached.Libevent Documentation · Fast portable non-blocking... · Older Releases
  23. [23]
    Twisted Python
    An event-driven networking engine. Written in Python. Licensed under the open source MIT License. View Github View Documentation · Check PyPi download page.The Twisted documentation! · Developer Guides · Writing ServersMissing: C10k | Show results with:C10k
  24. [24]
    epoll(7) - Linux manual page - man7.org
    The epoll API can be used either as an edge-triggered or a level-triggered interface and scales well to large numbers of watched file descriptors. The central ...
  25. [25]
  26. [26]
    kqueue - FreeBSD Manual Pages
    The kqueue() system call provides a generic method of notifying the user when an event happens or a condition holds, based on the results of small pieces of ...
  27. [27]
    I/O Completion Ports - Win32 apps - Microsoft Learn
    Aug 8, 2022 · For example, it can be a network endpoint, TCP socket, named pipe, or mail slot. Any system object that supports overlapped I/O can be used.
  28. [28]
    CreateIoCompletionPort function (IoAPI.h) - Win32 apps
    Jan 7, 2021 · Any system objects that support overlapped I/O such as network endpoints, TCP sockets, named pipes, and mail slots can be used as file handles.
  29. [29]
    Node.js — About Node.js®
    ### Summary of Node.js Architecture, V8, libuv, and Concurrency/C10k
  30. [30]
    nginx
    ### Summary of NGINX Content
  31. [31]
    Tuning NGINX for Better Performance - CloudBees
    Here's how to tune an out-of-the-box instance of NGINX to get more out of an already high-performance web server with a few common NGINX tuning parameters.Establishing A Baseline · Worker Threads · Worker Connections<|separator|>
  32. [32]
    How NGINX's Event-Driven Architecture Handles Million Concurrent ...
    Mar 17, 2025 · In this article, we will learn how NGINX efficiently scales to handle millions of concurrent connections. We will explore different approaches and understand ...
  33. [33]
    Index - Erlang/OTP
    ### Summary of Erlang/OTP Concurrency Model and C10k Handling
  34. [34]
    The Go Programming Language
    ### Summary of Go Goroutines, Lightweight Threads, Async I/O, and High Concurrency
  35. [35]
    Go Tech Talk (1) - The Go Programming Language
    Mar 23, 2010 · Goroutines can't just be a C++ library on top of a thread library. Concurrent. Consider web servers ("the C10k problem"):. "Thread per ...<|separator|>
  36. [36]
    [PDF] Reliable Messaging to Millions of Users with MigratoryData - arXiv
    Dec 28, 2017 · The ability to sup- port 10,000 concurrent clients on a single server was informally de- fined as the C10K problem in the late 1990s. The ...
  37. [37]
    Scaling persistent connections for cloud services | Computer Networks
    Dec 24, 2015 · Kegel, The c10k problem, Available at http://www.kegel.com/c10k.html(2011). ... IoT · Persistent connections · Scalability. Qualifiers. Research ...
  38. [38]
    [PDF] Opening Up Kernel-Bypass TCP Stacks - USENIX
    Jul 9, 2025 · Concurrent TCP connections are common in the Internet servers, whose challenges are cited as. C10K or C10M problem [37, 42, 49]. ... The C10K ...
  39. [39]
    Increase file descriptors on Linux and Linux Docker containers
    Allow all users to modify their file descriptor limits from an initial value of 1024 up to the maximum permitted value of 32768 by changing /etc/security/limits ...Missing: concurrency | Show results with:concurrency
  40. [40]
    Quotas for your Application Load Balancers - Elastic Load Balancing
    ### Summary of ALB Limits for Connections, Concurrency, and Scalability
  41. [41]
    Now the World's #1 Web Server, NGINX Looks Forward to an Even ...
    Jun 10, 2021 · The challenge was referred to at the time as the C10K problem – handling 10,000 simultaneous connections to clients. Inspired by the design ...
  42. [42]
    Improving performance of multiple I/O threads for OpenShift ...
    Jul 31, 2025 · Red Hat OpenShift Virtualization 4.19 significantly improves performance and speed for I/O intensive workloads like databases.