Chatty I/O
Chatty I/O makes many tiny remote or storage calls where a few batched ones would do, so latency scales with call count and exhausts connections and rate limits. Use batch and coarse-grained APIs, request coalescing, and caching to collapse round trips.
Chatty I/O is a communication pattern that exchanges a large number of small requests instead of fewer, larger ones. The functionality is correct, but every call carries fixed overhead — connection setup, TLS, serialization, authentication, latency — so the per-operation cost dominates and total time scales with the number of calls rather than the amount of data. It is the network-and-storage cousin of the N+1 query problem.
Why It Happens
Fine-grained APIs are natural to write: a method per entity, a call per item, getters that each fetch one field. Looping over a collection and calling a service once per element reads cleanly and works in development against localhost where latency is near zero. Object-relational and microservice boundaries encourage one-thing-at-a-time access. The cost only shows up over real network distance and at production volume.
Why It Hurts
If a single round trip is 5 ms, 200 of them in a loop is a full second of latency — even though the data could fit in one response. Each call also consumes a connection, a thread, and a slice of any rate limit, so chatty callers exhaust pools and trip throttling. Across a cloud network or the internet, the round trips dominate; the link is rarely the bottleneck, the count is. Chatty services also amplify failure: more calls mean more chances for one to fail or time out.
Warning Signs
- A loop whose body makes a network, RPC, or storage call.
- APIs that return one entity at a time with no bulk/batch variant.
- Traces showing hundreds of small spans to the same dependency per request.
- High request counts with tiny payloads; latency dominated by round trips.
Better Alternatives
- Batch / bulk APIs: fetch or write many items in one request (
GET /items?ids=..., bulk insert,mget). - Coarse-grained operations: return the aggregate a caller needs in one shot instead of forcing many gets.
- Request coalescing / DataLoader: collect per-item requests in a tick and issue one batched call.
- Caching of frequently read data to remove repeat round trips.
- GraphQL or projection queries to fetch exactly the needed shape in one call.
How to Refactor Out of It
Instrument a representative request and count calls per dependency. Where a loop drives the calls, replace it with a single batched request and reshape the downstream API to accept and return collections. Add bulk endpoints to chatty services. For per-item access scattered across code, introduce a coalescing layer (such as a DataLoader) that batches requests within a frame. Cache stable reads. Re-measure: latency should drop from N round trips to one or a few, and rate-limit pressure should fall sharply.