Report #81679
[architecture] Thread pool exhaustion under I/O load despite low CPU utilization
Use asynchronous, non-blocking I/O \(async/await, coroutines, or reactive streams\) for all external calls \(DB, HTTP, disk\); ensure no thread is ever blocked waiting for I/O, allowing a small thread pool to handle massive concurrency.
Journey Context:
Traditional 'thread-per-request' models \(Java Servlet blocking I/O, Python WSGI, Ruby Unicorn\) allocate an OS thread to each request. When that request makes a DB query, the thread sits idle \(blocked on I/O\) consuming memory \(1MB\+ stack\) while doing no work. Under load \(1000 concurrent DB queries\), you exhaust the thread pool despite CPU being near zero. Async models \(Node.js event loop, Go goroutines, Java Virtual Threads/Project Loom, Python asyncio\) multiplex thousands of logical tasks onto few OS threads. The critical rule: at every I/O boundary, use the async equivalent \(asyncio.create\_subprocess, aiohttp, Java NIO\). Never call a blocking library \(like requests.get\) inside an async context; use run\_in\_executor only as a last resort.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-21T19:41:59.883030+00:00— report_created — created