Skip to content

08. Networking and Distributed Systems: all exercises

Every exercise from every module, in one place, with its difficulty and a hint. The full "done when" criteria are in each module's section 6. Work them in module order; within a module, easy first. Suggested minimum before interviews: every easy and medium, plus the hard ones marked with a star (*), which produce something you can show or talk about.

Build everything on WSL Ubuntu 24.04 with g++ -std=c++17 -Wall -Wextra -Werror -pthread, or make in code/.

Module 01: How the internet moves bytes

# Level Exercise Hint
1 easy ip route get for loopback, the WSL gateway and 1.1.1.1; explain each decision Longest-prefix match on the routing table; loopback never leaves the host.
2 easy dig A records, TTLs and a CNAME chain (www.github.com) dig +noall +answer; follow the CNAME until an A record.
3 medium Capture a handshake and a request with tcpdump -w, read it in Wireshark Filter tcp.port == N; MSS is a TCP option in the SYN and SYN-ACK.
4 medium Bandwidth-delay product for 100 Mbit/s at 50 ms RTT vs a 64 KB window Bytes in flight = (bits/s / 8) x RTT; throughput cap = window / RTT.
5 hard Shell script diagnosing DNS, ping and TCP-port failures for a host:port Test layers bottom-up and stop at the first failure; getent, ping -c1 -W1, nc -zv -w2.

Module 02: TCP in depth

# Level Exercise Hint
1 easy Find who sent FIN first and confirm that side holds TIME_WAIT The active closer holds TIME_WAIT; ss -tan state time-wait.
2 easy Draw the TCP state machine from memory Separate the three-way open, active close and passive close paths.
3 medium Reproduce the Nagle plus delayed-ACK stall and fix with TCP_NODELAY Write-write-read pattern with small writes; loopback may hide it.
4 medium Reproduce CLOSE_WAIT, then fix the server to close on read() == 0 CLOSE_WAIT means your code has not called close.
5* hard Estimate and measure the max connection rate under TIME_WAIT, then try tcp_tw_reuse Ports in ip_local_port_range divided by the TIME_WAIT duration.
6 hard tc netem loss and delay on loopback; find fast retransmit and RTO retransmits Fast retransmit follows three duplicate ACKs; RTO shows as a long gap.

Module 03: Sockets API and a blocking server

# Level Exercise Hint
1 easy Run echo server and client, watch ss -tanp during and after Note LISTEN, ESTAB, and who ends in TIME_WAIT.
2 easy Remove SIGPIPE protection and kill the client mid-echo Exit status 141 = 128 + SIGPIPE (13).
3 medium Print each recv size for seq 1 100000 Sizes depend on segment arrival and buffer state, not on the sender's send calls.
4 medium connect_with_timeout with non-blocking connect, poll and SO_ERROR EINPROGRESS is success-so-far; read SO_ERROR when writable.
5 hard Winsock version m03_socket_win.hpp WSAStartup once, SOCKET is unsigned, closesocket, WSAGetLastError.
6 hard LD_PRELOAD library that histograms recv/read sizes dlsym(RTLD_NEXT, "recv"); print in a destructor function.

Module 04: Framing and protocol design

# Level Exercise Hint
1 easy Run parser tests and framing under ASan and UBSan Add -fsanitize=address,undefined -g.
2 easy Add KEYS <prefix> to the grammar and its reply formatter Reply is an array header *n followed by n bulk strings.
3 medium Incremental ReplyParser for + - : $ replies, tested with random splits Reuse the request parser's state-machine shape; compare byte-by-byte vs whole.
4 medium Tolerate multiple spaces and bare \n without breaking tests Decide what a bare \n inside a bulk value means before coding.
5 hard libFuzzer target that splits input at data-derived positions Use the first byte(s) of input as split offsets; build with clang.
6* hard One-page spec for a binary tcpkv Specify every field's size, byte order, and the error/status codes.

Module 05: Thread-per-connection and thread pools

# Level Exercise Hint
1 easy Two workers, three nc clients: see the third starve It sits in the accept queue or the task queue, depending on the design.
2 easy Observe the idle timeout firing Lower the timeout constant; check the counter at shutdown.
3 medium Per-connection command limit or token bucket with ERR_BUSY Reuse TokenBucket from m09_token_bucket.cpp.
4 medium Reproduce the slow-reader deadlock and the send timeout freeing it Watch Send-Q and Recv-Q both fill in ss -tanp.
5* hard Request-per-worker with an I/O thread per connection and ordered replies Tag each request with a per-connection sequence number; reorder on output.
6 hard SIGHUP config reload and SIGUSR1 counters dump Use signalfd or a self-pipe; never do real work in a signal handler.

Module 06: Non-blocking I/O, epoll and event loops

# Level Exercise Hint
1 easy Compare RSS and threads of epoll vs thread-pool server at 1000 connections ps -o rss,nlwp -p PID.
2 easy Break the edge-triggered drain rule and observe hangs ET reports a transition once; unread data never re-triggers.
3* medium Convert the epoll echo server into tcpkv One Parser and output buffer per Conn; replies appended to the buffer.
4 medium Non-blocking connect inside the loop with a 3 s timer Register EPOLLOUT, then SO_ERROR; use timerfd for the timeout.
5 hard Worker pool for SLOW commands posting replies back via eventfd Mutex-protected completion queue plus eventfd write to wake the loop.
6 hard Rewrite the echo server with Boost.Asio One io_context, async_read_some then async_write in a loop.

Module 07: RPC

# Level Exercise Hint
1 easy Add a Ping method returning monotonic milliseconds New method id in the dispatch table; steady_clock.
2 easy Bump kVersion on the server only and get a clear error The side that reads the header detects it; reply with a status, not garbage.
3 medium Pipelined client: send_async and wait(id) Map of id to pending result; read replies until yours arrives.
4 medium Server-side in-flight limit per connection returning Overloaded Count outstanding ids per connection; decrement on reply.
5* hard Multi-threaded client with a demux reader thread and promises Writer mutex, one reader thread, timer thread failing promises on deadline.
6 hard Same service in gRPC; compare p50 latency Measure many calls after warm-up; explain HTTP/2 and protobuf costs.

Module 08: HTTP and REST

# Level Exercise Hint
1 easy Confirm keep-alive reuses one connection with tcpdump One SYN for two requests with curl url1 url2.
2 easy HEAD support, ETag and 304 Not Modified ETag = hash of the value; compare with If-None-Match.
3 medium Chunked request body decoding State machine: hex size line, data, CRLF, until size 0, then trailers.
4 medium If-Match on PUT with 412, plus a two-client race test Compare-and-set on the ETag under the store's lock.
5* hard HTTP server on the epoll loop, benchmark with wrk Per-connection parse state survives partial requests across reads.
6 hard TLS with OpenSSL SSL_CTX_new(TLS_server_method()), self-signed cert, SSL_accept.

Module 09: Client-server architecture and reliability

# Level Exercise Hint
1 easy Per-connection token bucket in tcpkv Burst 100, rate 50/s; -ERR_BUSY on empty.
2 easy backoff_ms schedule for ten seeds Full jitter: uniform in [0, min(cap, base * 2^attempt)].
3* medium Tested CircuitBreaker with an injectable clock Test each transition: closed to open, open to half-open, half-open to both.
4 medium X-Request-Id handling and JSON access log in the HTTP server Generate an id if absent; log after the response is written.
5 hard Connection pool for the RPC client Bounded size, acquire timeout, validate-on-borrow after idle, max lifetime.
6* hard Reliability review of your employer's request path One row per hop: timeout, retry, idempotency, pool, breaker, failure UX.

Module 10: Distributed systems fundamentals

# Level Exercise Hint
1 easy Explain one [RAW CLOCK WRONG] line from m10_hlc Identify which of the four receive branches fired from the printed l values.
2 easy Read your clock offset and frequency error from chrony ppm x 1e-6 = seconds of drift per second.
3 medium Add a Lamport clock beside the HLC; find concurrent events it orders Concurrent = neither happened-before the other; Lamport still gives them an order.
4 medium Consistency model needed by each banking screen Ask: what goes wrong if this read is one second stale?
5 hard Leaderless N=3 store with W, R, read repair and random failures Version every value; reader returns the highest version and repairs the others.
6* hard Unknown-outcome decision table for your posting RPC Four failure points times what client sees, server state, retry effect.

Module 11: Consensus: Raft in plain words

# Level Exercise Hint
1 easy Run m11_raft_election_sim with three seeds; compare first election and terms Terms grow with every election attempt, including split votes.
2 easy Four nodes partitioned 2-2 Majority of 4 is 3; neither side has it.
3 medium Remove timeout randomisation; observe split votes Set kElectionMin == kElectionMax; count terms before a stable leader.
4 medium Add check-quorum to the leader Track the last successful reply time per follower; step down without a recent majority.
5 hard Add pre-vote A PreVote round with term + 1 that does not change anyone's persistent state.
6* hard Single-server membership change with learners Configuration takes effect on append; promote a learner when caught up.

Module 12: Sharding, partitioning and distributed SQL

# Level Exercise Hint
1 easy Measure ring balance for 1, 5, 20, 500 virtual nodes Relative imbalance shrinks roughly as 1/sqrt(vnodes).
2 easy Choose shard keys for five tables Name the hot access path and the key's cardinality for each.
3 medium Add jump consistent hash and compare Jump hash needs no memory but only adds/removes buckets at the end.
4* medium YugabyteDB: compare EXPLAIN (ANALYZE, DIST) for two primary-key designs (account_no) HASH, txn_ts DESC vs txn_id HASH for "last 20 of one account".
5 hard 2PC simulation with coordinator crash, then a replicated decision record Participants that voted yes must wait; a majority-replicated decision unblocks them.
6* hard Sharding and colocation plan for a 12-table loan-origination schema Every hot query should touch one tablet per table, or say why not.

Module 13: High availability and operations

# Level Exercise Hint
1 easy Error budgets for 99.5/99.9/99.95% and a series availability 30 days = 43,200 minutes; series availabilities multiply.
2 easy Your employer's RTO and RPO and their mechanisms If you do not know, the mechanism tells you: backup interval, replication mode.
3* medium Kill a yugabyted node under load; measure the blip Expect a few seconds on tablets led by the dead node; zero lost commits.
4 medium Expand/contract plan for renaming a column under rolling deploys Never drop the old column in the release that stops reading it.
5* hard Runbook for "YugabyteDB node down" Start from the alert; exact commands; how to verify re-replication finished.
6 hard Chaos experiment on three tcpkv instances behind HAProxy kill -9 one, tc netem another; record errors and p99 per fault.

Module 14: System design interview walkthroughs

# Level Exercise Hint
1 easy Redo the estimates for all five walkthroughs on paper 1 M/day is about 12/s; multiply by a peak factor.
2 easy base62 encode and decode with round-trip asserts Divide by 62 repeatedly; decode multiplies and adds.
3* medium Present the loan-origination design aloud in 45 minutes Follow the method table; keep a timer visible.
4 medium Hybrid token-leasing rate limiter in one process Central TokenBucket::try_acquire(20) per lease; local counters spend it.
5 hard Design an exactly-once-per-business-date batch scheduler Exactly-once effect = lease + idempotent job keyed by (job, business date).
6* hard Turn the Raft simulation into a replicated KV store with client dedupe State machine keeps last request id per client; skip duplicates on apply.