Interview-Fragen zu Verteilten Netzwerken: CAP, Konsens und Systemdesign (2026)
Verteilte Netzwerke sind fundamental fuer moderne Systeme - von Microservices ueber Blockchain bis hin zu globalen CDNs. Das Verstaendnis dieser Konzepte ist entscheidend fuer Senior-Engineering-Positionen. Dieser Leitfaden behandelt die haeufigsten Interviewfragen mit ausfuehrlichen Antworten und praktischen Beispielen.
Grundlagen
1. Was ist ein verteiltes System?
Antwort: Ein verteiltes System ist eine Sammlung unabhaengiger Computer, die den Benutzern als ein einziges kohaerentes System erscheinen. Wichtige Merkmale:
- Nebenlaeufigkeit: Komponenten werden gleichzeitig ausgefuehrt
- Keine globale Uhr: Knoten haben unabhaengige Uhren
- Unabhaengige Ausfaelle: Komponenten koennen ausfallen, ohne andere zu beeintraechtigen
- Nachrichtenuebermittlung: Kommunikation ueber Netzwerknachrichten
Beispiele: Google-Suche, Netflix-Streaming, Bitcoin-Netzwerk.
2. Erklaeren Sie das CAP-Theorem
Antwort: Das CAP-Theorem besagt, dass ein verteiltes System nur zwei von drei Eigenschaften garantieren kann:
- Konsistenz: Alle Knoten sehen zur gleichen Zeit die gleichen Daten
- Verfuegbarkeit: Jede Anfrage erhaelt eine Antwort
- Partitionstoleranz: Das System funktioniert trotz Netzwerkausfaellen weiter
In der Praxis ist Partitionstoleranz erforderlich (Netzwerke fallen aus), daher waehlt man zwischen CP (Konsistenz) oder AP (Verfuegbarkeit):
CP Systems: MongoDB, HBase, Redis Cluster
- Sacrifice availability during partitions
- Strong consistency guarantees
AP Systems: Cassandra, DynamoDB, CouchDB
- Remain available during partitions
- Eventually consistent
3. Was ist Eventual Consistency?
Antwort: Eventual Consistency garantiert, dass alle Replikate schliesslich zum gleichen Wert konvergieren, wenn keine neuen Aktualisierungen vorgenommen werden. Es ist eine schwaechere Garantie als starke Konsistenz, ermoeglicht aber eine hoehere Verfuegbarkeit.
// Example: DNS propagation
// Update takes time to propagate globally
// Different users may see different values temporarily
// Eventually, all DNS servers have the same record
// Conflict resolution strategies:
// 1. Last-write-wins (LWW) - timestamp-based
// 2. Vector clocks - track causality
// 3. CRDTs - mathematically guaranteed convergence
4. Erklaeren Sie den Unterschied zwischen horizontaler und vertikaler Skalierung
Antwort:
| Aspekt | Vertikale Skalierung | Horizontale Skalierung |
|---|---|---|
| Methode | Ressourcen zu einer Maschine hinzufuegen | Mehr Maschinen hinzufuegen |
| Kosten | Teuer bei Skalierung | Standard-Hardware |
| Grenze | Hardware-Obergrenze | Theoretisch unbegrenzt |
| Komplexitaet | Einfach | Erfordert Verteilungslogik |
| Ausfallzeit | Normalerweise erforderlich | Null Ausfallzeit moeglich |
Konsens und Koordination
5. Was ist der Raft-Konsensalgorithmus?
Antwort: Raft ist ein Konsensalgorithmus zur Verwaltung eines replizierten Logs. Er wurde so konzipiert, dass er verstaendlich ist (im Gegensatz zu Paxos). Hauptkomponenten:
- Leader-Wahl: Ein Knoten wird zum Leader gewaehlt und bearbeitet alle Client-Anfragen
- Log-Replikation: Der Leader repliziert Eintraege an die Follower
- Sicherheit: Nur Knoten mit aktuellen Logs koennen Leader werden
Raft states:
1. Follower - Default state, responds to leader
2. Candidate - Requesting votes for leadership
3. Leader - Handles all client requests
Election process:
1. Follower timeout expires
2. Becomes candidate, increments term
3. Requests votes from peers
4. Majority votes = new leader
5. Sends heartbeats to maintain leadership
6. Was ist ein verteiltes Lock?
Antwort: Ein verteiltes Lock stellt sicher, dass nur ein Prozess ueber mehrere Knoten hinweg auf eine Ressource zugreifen kann. Implementierungsherausforderungen:
// Redis distributed lock (Redlock algorithm)
const Redis = require('ioredis');
async function acquireLock(redis, key, ttl) {
const token = crypto.randomUUID();
const result = await redis.set(key, token, 'NX', 'PX', ttl);
return result === 'OK' ? token : null;
}
async function releaseLock(redis, key, token) {
// Lua script for atomic check-and-delete
const script = `
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
`;
return redis.eval(script, 1, key, token);
}
// Usage
const token = await acquireLock(redis, 'my-resource', 30000);
if (token) {
try {
// Critical section
} finally {
await releaseLock(redis, 'my-resource', token);
}
}
7. Erklaeren Sie Vektoruhren
Antwort: Vektoruhren verfolgen die Kausalitaet zwischen Ereignissen in verteilten Systemen. Jeder Knoten verwaltet einen Vektor von logischen Zeitstempeln:
// Vector clock example with 3 nodes
// Initial: [0, 0, 0]
// Node A sends message: [1, 0, 0]
// Node B receives and sends: [1, 1, 0]
// Node C receives: [1, 1, 1]
// Comparison rules:
// V1 < V2 if all V1[i] <= V2[i] and at least one V1[i] < V2[i]
// V1 || V2 (concurrent) if neither V1 < V2 nor V2 < V1
class VectorClock {
constructor(nodeId, numNodes) {
this.nodeId = nodeId;
this.clock = new Array(numNodes).fill(0);
}
increment() {
this.clock[this.nodeId]++;
return [...this.clock];
}
update(received) {
for (let i = 0; i < this.clock.length; i++) {
this.clock[i] = Math.max(this.clock[i], received[i]);
}
this.clock[this.nodeId]++;
}
compare(other) {
let less = false, greater = false;
for (let i = 0; i < this.clock.length; i++) {
if (this.clock[i] < other[i]) less = true;
if (this.clock[i] > other[i]) greater = true;
}
if (less && !greater) return -1; // this happened before
if (greater && !less) return 1; // other happened before
return 0; // concurrent
}
}
Netzwerkprotokolle
8. Vergleichen Sie TCP und UDP fuer verteilte Systeme
Antwort:
| Merkmal | TCP | UDP |
|---|---|---|
| Verbindung | Verbindungsorientiert | Verbindungslos |
| Zuverlaessigkeit | Garantierte Zustellung | Best Effort |
| Reihenfolge | Geordnet | Keine Reihenfolge |
| Geschwindigkeit | Langsamer (Handshake) | Schneller |
| Anwendungsfaelle | HTTP, Datenbanken | DNS, Streaming, Gaming |
// When to use each:
// TCP: When you need reliability
// - Database connections
// - File transfers
// - API calls
// UDP: When speed matters more than reliability
// - Real-time gaming
// - Video streaming
// - DNS queries
// - Health checks
9. Was ist gRPC und wann wuerde man es verwenden?
Antwort: gRPC ist ein hochperformantes RPC-Framework, das Protocol Buffers und HTTP/2 verwendet:
- Binaerprotokoll: Kleinere Payloads als JSON
- Streaming: Unterstuetzung fuer bidirektionales Streaming
- Code-Generierung: Typsichere Clients/Server
- HTTP/2: Multiplexing, Header-Komprimierung
// user.proto
syntax = "proto3";
service UserService {
rpc GetUser(GetUserRequest) returns (User);
rpc ListUsers(ListUsersRequest) returns (stream User);
rpc CreateUser(User) returns (User);
}
message User {
string id = 1;
string name = 2;
string email = 3;
}
message GetUserRequest {
string id = 1;
}
10. Erklaeren Sie die Service-Mesh-Architektur
Antwort: Ein Service Mesh ist eine Infrastrukturschicht fuer die Service-zu-Service-Kommunikation. Komponenten:
- Datenebene: Sidecar-Proxys (Envoy) verarbeiten den Datenverkehr
- Steuerungsebene: Verwaltet die Proxy-Konfiguration
# Istio example - traffic splitting
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: my-service
spec:
hosts:
- my-service
http:
- route:
- destination:
host: my-service
subset: v1
weight: 90
- destination:
host: my-service
subset: v2
weight: 10
Vorteile: mTLS, Observability, Traffic-Management, Wiederholungsversuche ohne Code-Aenderungen.
Fehlertoleranz
11. Was ist das Circuit-Breaker-Pattern?
Antwort: Der Circuit Breaker verhindert kaskadierende Ausfaelle, indem er schnell fehlschlaegt, wenn ein Dienst nicht gesund ist:
class CircuitBreaker {
constructor(options) {
this.failureThreshold = options.failureThreshold || 5;
this.resetTimeout = options.resetTimeout || 30000;
this.state = 'CLOSED';
this.failures = 0;
this.lastFailure = null;
}
async call(fn) {
if (this.state === 'OPEN') {
if (Date.now() - this.lastFailure > this.resetTimeout) {
this.state = 'HALF_OPEN';
} else {
throw new Error('Circuit breaker is OPEN');
}
}
try {
const result = await fn();
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
onSuccess() {
this.failures = 0;
this.state = 'CLOSED';
}
onFailure() {
this.failures++;
this.lastFailure = Date.now();
if (this.failures >= this.failureThreshold) {
this.state = 'OPEN';
}
}
}
12. Erklaeren Sie das Bulkhead-Pattern
Antwort: Bulkhead isoliert Komponenten, damit Ausfaelle nicht kaskadieren. Wie Schiffskompartimente:
// Thread pool bulkhead
const criticalPool = new ThreadPool({ size: 10 });
const nonCriticalPool = new ThreadPool({ size: 5 });
// If non-critical service exhausts its pool,
// critical operations still have dedicated resources
// Semaphore bulkhead
class Bulkhead {
constructor(maxConcurrent) {
this.maxConcurrent = maxConcurrent;
this.current = 0;
this.queue = [];
}
async execute(fn) {
if (this.current >= this.maxConcurrent) {
throw new Error('Bulkhead full');
}
this.current++;
try {
return await fn();
} finally {
this.current--;
}
}
}
13. Was ist Byzantine Fault Tolerance?
Antwort: BFT behandelt Knoten, die sich beliebig verhalten (boeswillig oder aufgrund von Fehlern). Das Problem der Byzantinischen Generaele:
- Erfordert 3f+1 Knoten, um f byzantinische Fehler zu tolerieren
- Wird in Blockchain verwendet (PBFT, Tendermint)
- Aufwendiger als Crash-Fehlertoleranz
PBFT phases:
1. Pre-prepare: Leader proposes value
2. Prepare: Nodes broadcast prepared messages
3. Commit: Nodes commit after 2f+1 prepares
4. Reply: Send result to client
Requires 2f+1 matching messages at each phase
Lastverteilung und Routing
14. Vergleichen Sie Lastverteilungsalgorithmen
Antwort:
// Round Robin - Simple rotation
class RoundRobin {
constructor(servers) {
this.servers = servers;
this.current = 0;
}
next() {
const server = this.servers[this.current];
this.current = (this.current + 1) % this.servers.length;
return server;
}
}
// Weighted Round Robin - Based on capacity
class WeightedRoundRobin {
constructor(servers) {
// servers: [{ host: 'a', weight: 3 }, { host: 'b', weight: 1 }]
this.servers = [];
for (const s of servers) {
for (let i = 0; i < s.weight; i++) {
this.servers.push(s.host);
}
}
this.current = 0;
}
}
// Least Connections - Route to least busy
class LeastConnections {
constructor(servers) {
this.connections = new Map(servers.map(s => [s, 0]));
}
next() {
let min = Infinity, selected;
for (const [server, count] of this.connections) {
if (count < min) {
min = count;
selected = server;
}
}
return selected;
}
}
// Consistent Hashing - For caches/sharding
// Minimizes redistribution when nodes change
15. Erklaeren Sie Consistent Hashing
Antwort: Consistent Hashing verteilt Daten ueber Knoten, waehrend die Umverteilung beim Hinzufuegen/Entfernen von Knoten minimiert wird:
const crypto = require('crypto');
class ConsistentHash {
constructor(replicas = 100) {
this.replicas = replicas;
this.ring = new Map();
this.sortedKeys = [];
}
hash(key) {
return crypto.createHash('md5')
.update(key)
.digest('hex')
.substring(0, 8);
}
addNode(node) {
for (let i = 0; i < this.replicas; i++) {
const hash = this.hash(`${node}:${i}`);
this.ring.set(hash, node);
this.sortedKeys.push(hash);
}
this.sortedKeys.sort();
}
removeNode(node) {
for (let i = 0; i < this.replicas; i++) {
const hash = this.hash(`${node}:${i}`);
this.ring.delete(hash);
this.sortedKeys = this.sortedKeys.filter(k => k !== hash);
}
}
getNode(key) {
const hash = this.hash(key);
for (const nodeHash of this.sortedKeys) {
if (hash <= nodeHash) {
return this.ring.get(nodeHash);
}
}
return this.ring.get(this.sortedKeys[0]);
}
}
Messaging und Warteschlangen
16. Vergleichen Sie Message-Queue-Patterns
Antwort:
- Point-to-Point: Ein Producer, ein Consumer (Task-Warteschlangen)
- Pub/Sub: Ein Producer, mehrere Consumer (Event-Broadcasting)
- Request/Reply: Synchrones Messaging-Pattern
Delivery guarantees:
- At most once: May lose messages (fastest)
- At least once: May duplicate (requires idempotency)
- Exactly once: Most complex, often needs transactions
Technologies:
- RabbitMQ: Traditional message broker, AMQP
- Kafka: Distributed log, high throughput
- Redis Streams: Simple, built into Redis
- AWS SQS: Managed, scalable
17. Was ist das Outbox-Pattern?
Antwort: Das Outbox-Pattern stellt zuverlaessiges Message-Publishing mit Datenbanktransaktionen sicher:
// Instead of:
await db.transaction(async (tx) => {
await tx.insert('orders', order);
await messageQueue.publish('order.created', order); // Can fail!
});
// Use outbox pattern:
await db.transaction(async (tx) => {
await tx.insert('orders', order);
await tx.insert('outbox', {
event_type: 'order.created',
payload: JSON.stringify(order),
created_at: new Date()
});
});
// Separate process polls outbox and publishes
async function processOutbox() {
const events = await db.query(
'SELECT * FROM outbox WHERE processed = false LIMIT 100'
);
for (const event of events) {
await messageQueue.publish(event.event_type, event.payload);
await db.update('outbox', { id: event.id }, { processed: true });
}
}
Observability
18. Was ist Distributed Tracing?
Antwort: Distributed Tracing verfolgt Anfragen ueber Service-Grenzen hinweg:
// OpenTelemetry example
const { trace } = require('@opentelemetry/api');
const tracer = trace.getTracer('my-service');
async function handleRequest(req) {
const span = tracer.startSpan('handleRequest');
try {
span.setAttribute('user.id', req.userId);
// Child span for database call
const dbSpan = tracer.startSpan('database.query', {
parent: span
});
const result = await db.query('...');
dbSpan.end();
return result;
} catch (error) {
span.recordException(error);
span.setStatus({ code: SpanStatusCode.ERROR });
throw error;
} finally {
span.end();
}
}
// Trace context propagation
// W3C Trace Context header: traceparent
// Format: version-trace_id-span_id-flags
// Example: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
19. Erklaeren Sie die drei Saeulen der Observability
Antwort:
- Logs: Diskrete Ereignisse mit Kontext
- Metriken: Numerische Messungen ueber Zeit
- Traces: Anfragefluss ueber Services hinweg
Logs: What happened?
- Structured JSON logs
- Correlation IDs
- Log levels (debug, info, warn, error)
Metrics: How is the system performing?
- Counters: request_count
- Gauges: active_connections
- Histograms: request_duration
Traces: Where did the request go?
- Spans with timing
- Parent-child relationships
- Cross-service context
Sicherheit
20. Wie sichert man die Service-zu-Service-Kommunikation?
Antwort:
- mTLS: Gegenseitige TLS-Authentifizierung
- Service Mesh: Automatisches mTLS (Istio, Linkerd)
- API-Schluessel: Einfach, aber weniger sicher
- JWT: Zustandslose Authentifizierung
# Istio PeerAuthentication for mTLS
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: my-namespace
spec:
mtls:
mode: STRICT
System-Design-Fragen
21. Entwerfen Sie einen verteilten Rate Limiter
Antwort:
// Token bucket with Redis
class DistributedRateLimiter {
constructor(redis, options) {
this.redis = redis;
this.capacity = options.capacity;
this.refillRate = options.refillRate; // tokens per second
}
async isAllowed(key) {
const now = Date.now();
const script = `
local key = KEYS[1]
local capacity = tonumber(ARGV[1])
local refillRate = tonumber(ARGV[2])
local now = tonumber(ARGV[3])
local bucket = redis.call('HMGET', key, 'tokens', 'lastRefill')
local tokens = tonumber(bucket[1]) or capacity
local lastRefill = tonumber(bucket[2]) or now
-- Refill tokens
local elapsed = (now - lastRefill) / 1000
tokens = math.min(capacity, tokens + elapsed * refillRate)
if tokens >= 1 then
tokens = tokens - 1
redis.call('HMSET', key, 'tokens', tokens, 'lastRefill', now)
redis.call('EXPIRE', key, 60)
return 1
else
return 0
end
`;
return await this.redis.eval(script, 1, key,
this.capacity, this.refillRate, now);
}
}
22. Wie wuerden Sie einen verteilten Cache entwerfen?
Antwort: Wichtige Ueberlegungen:
- Partitionierung: Consistent Hashing ueber Knoten
- Replikation: Primaer-Replikat fuer Fehlertoleranz
- Eviction: LRU-, LFU- oder TTL-basiert
- Konsistenz: Write-Through, Write-Behind oder Cache-Aside
Cache-aside pattern:
1. Check cache
2. If miss, read from database
3. Update cache
4. Return data
Write-through pattern:
1. Write to cache
2. Cache writes to database
3. Ensures consistency but adds latency
Write-behind pattern:
1. Write to cache
2. Cache async writes to database
3. Better performance, eventual consistency
Fazit
Verteilte Systeme sind komplex, aber das Verstaendnis dieser Kernkonzepte - Konsens, Fehlertoleranz, Netzwerke und Observability - wird Sie auf Senior-Engineering-Interviews vorbereiten. Konzentrieren Sie sich auf Kompromisse: Es gibt selten eine perfekte Loesung, nur Kompromisse, die fuer bestimmte Anforderungen angemessen sind.