Communication

Communication is the mechanism by which processes in a distributed system exchange information. The design of communication protocols and middleware shapes what is easy or hard to build.

Remote Procedure Call (RPC)

RPC makes a remote function call look like a local one. The caller does not need to know that the callee is on another machine.

Components:

  • Stub (proxy): client-side code that marshals arguments into a message and sends it.
  • Skeleton: server-side code that unmarshals the message, calls the actual function, and sends the result back.
  • Transport: the underlying network mechanism (TCP, UDP).

RPC lifecycle:

Client:   call f(args) -> stub serializes args -> send over network
Server:   receive -> skeleton deserializes -> call f(args) -> serialize result -> send back
Client:   deserialize result -> return to caller

Challenges: what happens if the network fails? The caller cannot tell whether:

  • The request was lost (function was not called).
  • The reply was lost (function was called once, result lost).
  • The server crashed after calling the function.

Semantics:

  • At-most-once: do not retry; accept possible non-delivery.
  • At-least-once: retry on timeout; server must be idempotent.
  • Exactly-once: deduplicate retries; hardest to achieve.

Modern RPC frameworks:

Framework Language Serialization Notes
gRPC Multi Protocol Buffers HTTP/2, streaming
Thrift Multi Thrift binary Apache; Facebook origin
JSON-RPC Multi JSON Simple; verbose
tRPC TypeScript TypeScript types Type-safe

gRPC

Google’s open-source RPC framework. Uses Protocol Buffers for serialization; HTTP/2 as the transport.

Advantages: strongly typed interfaces (.proto schema); efficient binary serialization; bidirectional streaming; multiplexed requests over one TCP connection.

Service definition:

service UserService {
  rpc GetUser (GetUserRequest) returns (User);
  rpc ListUsers (ListUsersRequest) returns (stream User);
}

message User {
  string id = 1;
  string name = 2;
  string email = 3;
}

Message Queues and Publish-Subscribe

Message queue: a buffer between producer and consumer. Decouples them in time and space. Producer puts messages in the queue; consumer retrieves them.

Properties: persistence (messages survive crashes), ordering (FIFO or priority), delivery guarantee (at-least-once, exactly-once), backpressure.

Publish-Subscribe (pub/sub): producers publish messages to topics; consumers subscribe to topics; the broker delivers messages to all subscribers. One-to-many communication.

Apache Kafka:

  • Distributed event streaming platform.
  • Topics are divided into partitions (parallelism and ordering unit).
  • Messages within a partition are ordered; no ordering guarantee across partitions.
  • Retention: messages are stored for a configurable period (days, weeks); consumers can replay.
  • Consumer groups: multiple consumers in a group share partitions (each partition assigned to one consumer); scales consumption linearly.
  • Replication: each partition has a leader and replicas; producers write to leader; followers replicate.
  • Use cases: event sourcing, stream processing, log aggregation, activity tracking.

RabbitMQ: traditional message broker. Implements AMQP. Flexible routing (direct, topic, fanout, headers exchanges).

AWS SQS: managed queue. Standard (at-least-once, best-effort ordering) or FIFO (exactly-once, ordered).

HTTP and REST

The dominant application-layer protocol for web services. Stateless; each request carries all necessary information.

RESTful API conventions:

  • Resources are nouns: /users, /orders/123.
  • HTTP methods express operations: GET (read), POST (create), PUT (replace), PATCH (update), DELETE (remove).
  • Status codes indicate outcome.
  • Stateless: no server-side session; authentication via tokens in headers.

Limitations for distributed systems:

  • Request-response only (no server push without workarounds).
  • Synchronous (client blocks waiting for response).
  • Verbose (HTTP/1.1 headers; mitigated by HTTP/2 and HTTP/3).

WebSocket

Full-duplex communication over a single TCP connection. Starts with an HTTP upgrade request.

Use cases: real-time applications (chat, collaborative editing, live dashboards, games).

Compared to HTTP polling: persistent connection; server can push data; lower latency; less overhead.

Service Mesh

Infrastructure layer that handles communication between microservices without requiring each service to implement it.

Features: service discovery, load balancing, TLS mutual authentication, retries, circuit breaking, distributed tracing, traffic shaping (canary deployments, A/B testing).

Sidecar proxy pattern: a proxy (Envoy) runs alongside each service and intercepts all network traffic.

Examples: Istio (uses Envoy proxies), Linkerd, Consul Connect, AWS App Mesh.

Serialization

Converting in-memory data structures to bytes for transmission or storage.

JSON: human-readable; language-independent; no schema by default; relatively verbose.

Protocol Buffers (protobuf): binary; requires .proto schema; compact; fast; strongly typed; backward/forward compatible with field numbers.

Apache Avro: binary; schema included in the message or in a schema registry; good for Kafka.

MessagePack: binary JSON; more compact than JSON; no schema.

Serialization performance (approximate): protobuf > MessagePack > JSON for size and speed.

Backpressure

When a consumer is slower than a producer, the queue grows. Backpressure is the mechanism by which a consumer signals to a producer to slow down.

TCP flow control: the receiver’s window size limits how fast the sender can transmit.

Application-level: explicit demand signals (Reactive Streams, gRPC flow control, Kafka consumer lag monitoring).

Without backpressure, a fast producer will exhaust memory and crash the system.