The full picture
| Mechanism | Model | Sweet spot | Watch out |
|---|---|---|---|
| Pipe / FIFO | byte stream, kernel copy | parent↔child pipelines; ls | grep | unidirectional; 64KB buffer backpressure = your flow control |
| Unix domain socket | stream/dgram, kernel copy | local daemons, sidecars; can pass FDs! | still syscalls + copies; local only |
| TCP socket | stream over network | anything that may distribute | latency, partial reads, the network fallacies |
| POSIX MQ | discrete prioritized messages | embedded/RT patterns | rare in server land — Kafka/Redis took this niche |
| Shared memory + sems | zero-copy region | highest throughput/lowest latency (rings, buffer pools) | you own synchronization, layout, versioning, corruption |
- The core trade stated once: message passing pays a copy to keep isolation; shared memory drops the copy and the isolation together. Everything else is packaging.
- FD passing over Unix sockets (SCM_RIGHTS) is the underrated superpower — hand a connected socket to a worker process: how nginx/systemd socket activation and zero-downtime listeners work.
- Backpressure is built-in: a full pipe blocks the writer — sometimes exactly what you want (shell pipelines self-throttle), sometimes a distributed-deadlock seed (two processes both blocked writing to each other — always drain stdout/stderr of child processes; the classic
Process.waitForhang). - Modern default in practice: within a host, Unix sockets (or gRPC over UDS); across hosts, TCP/gRPC/queues; shared memory only with a profiler's blessing — and note that containers in a K8s pod can share
/dev/shm, which is how ML sidecars move tensors.