General Exam Tips
- 1.Multiple-response questions give ZERO credit for a partial selection — if a question says 'select two' or 'select all that apply,' you must identify every correct option or you get nothing. Re-read the stem to confirm how many answers are expected
- 2.60 questions in 90 minutes is roughly 1.5 minutes per question, but code-analysis and multi-select questions eat more time — do not burn 4+ minutes on one config-trivia question. Flag and move on
- 3.There is no penalty for wrong answers, so never leave a question blank. If you are stuck, eliminate the two obviously wrong options and guess between the remaining two
- 4.Practice exams are widely reported as easier than the real exam. Scoring 70% on practice tests is NOT a green light — aim for 85%+ on at least two full practice exams before scheduling
- 5.When a question gives a specific numeric configuration (e.g., replication.factor=3, min.insync.replicas=2, one broker down), work through the actual mechanics step by step instead of pattern-matching to a memorized rule. The exam deliberately tests edge cases sitting right at a threshold
- 6.Application Design is 40% of the exam (~24 questions) — if your study time is limited, prioritize producer/consumer configuration, replication/ISR, and Schema Registry over ksqlDB or tiered storage trivia
- 7.Code-snippet questions test whether you can trace a Kafka Streams DSL chain or a producer/consumer config block line by line. Practice reading and writing small Java snippets, not just watching video lectures
- 8.Honorlock proctoring requires a fully clear desk, a single monitor, and Chrome only — do a dry run of the webcam/mic/ID check before exam day so you don't lose exam time to tech setup
- 9.When two answers both sound plausible for a Kafka Streams join or Schema Registry compatibility question, look for the word that flips the direction (BACKWARD vs FORWARD, source vs sink, windowed vs non-windowed) — that single word is usually the trap
Quick Navigation
Application Design
Must-Know Facts
- acks controls how many replicas must ACK before the producer considers a write successful; min.insync.replicas controls how many ISR members must exist for acks=all to succeed at all. They are two separate knobs that interact — you need both configured correctly for durability
- Idempotent producers (enable.idempotence=true) deduplicate retries using a Producer ID (PID) + per-partition sequence number, but ONLY within a single producer session. A producer restart gets a new PID, so idempotence alone does not survive a crash-and-restart
- Transactions require a stable transactional.id that survives restarts. On restart with the same transactional.id, the transaction coordinator fences (bumps the epoch of) any previous producer instance with that ID, preventing zombie writers
- isolation.level on the CONSUMER defaults to read_uncommitted — a consumer will see uncommitted (and even aborted) transactional messages unless you explicitly set isolation.level=read_committed. This default is a frequent trap
- The default partitioner hashes the record key with murmur2 to pick a partition. Same key always maps to the same partition AS LONG AS the partition count does not change — increasing partitions reshuffles the key-to-partition mapping and breaks historical ordering for existing keys
- Partition count can only be increased, never decreased, for an existing topic. Reducing partitions requires deleting and recreating the topic
- Consumer group rebalancing is triggered by: a consumer joining or leaving the group, a consumer crashing (detected via session.timeout.ms), a consumer exceeding max.poll.interval.ms while processing (treated as dead even if still sending heartbeats via the separate heartbeat thread), or a change in subscribed topic partition count
- Static group membership (group.instance.id set on the consumer) avoids triggering a rebalance during short-lived restarts (e.g., rolling deploys) — the group coordinator waits for the same member ID to rejoin instead of immediately reassigning its partitions
- Schema Registry's default compatibility mode is BACKWARD, applied per-subject. NONE disables all compatibility checks — dangerous in production because any schema change is accepted even if it breaks existing consumers
Common Traps
Confusing Pairs
Scenario Tips
A topic has replication.factor=3 and min.insync.replicas=2. The producer uses acks=all. Two of the three replicas (including the leader) go offline...
The write fails with NotEnoughReplicasException. Only 1 replica remains in the ISR, which is below min.insync.replicas=2, so acks=all cannot be satisfied even though the remaining replica is healthy
Do not assume the message is 'accepted with best effort' — Kafka fails the write outright rather than silently downgrading the durability guarantee. This is different from acks=1, which would still succeed on the single remaining leader
A question describes a consumer group where processing each record can occasionally take several minutes (e.g., calling a slow external API), and consumers keep getting unexpectedly removed from the group...
Increase max.poll.interval.ms to accommodate the longer processing time, or move the slow work off the polling thread. The consumer is being marked dead because poll() isn't called again within max.poll.interval.ms, not because of heartbeat failure
Increasing session.timeout.ms or heartbeat.interval.ms does not fix this — those govern the separate heartbeat thread, not how long you can go between poll() calls
A rolling deployment restarts consumer instances one at a time for a few seconds each, and the team wants to avoid a full group rebalance on every restart...
Configure group.instance.id (static membership) on each consumer so its identity persists across a brief restart. The coordinator will wait for the same instance to rejoin rather than immediately triggering a rebalance and reassigning its partitions
Switching to CooperativeSticky reduces the IMPACT of a rebalance but does not prevent the rebalance from being triggered in the first place — static membership addresses the root cause
A team needs strict exactly-once processing from a Kafka topic, through a Streams/producer transformation, and out to a downstream topic, but downstream consumers are still occasionally seeing duplicate or in-flight records...
Check that downstream consumers set isolation.level=read_committed. Idempotence and transactions on the producer side are necessary but not sufficient — the consumer default (read_uncommitted) will still expose uncommitted and aborted transactional records
Re-enabling enable.idempotence on the producer does nothing here if it is already on — the gap described is on the consumer side, not the producer side
A question asks which change is safe to make to a live topic without any application impact: increasing partitions, decreasing partitions, or changing the key schema...
Increasing partition count is the only one of these that Kafka supports directly on a live topic — though it still changes the key-to-partition mapping for future messages. Decreasing partitions is NOT supported (topic must be deleted/recreated)
Do not pick 'decreasing partitions is supported with a config change' — this operation does not exist in Kafka; some candidates confuse it with reassignment tools that only move existing partitions, not remove them
Last-Minute Facts
Development
Must-Know Facts
- KStream-KStream joins REQUIRE a join window (JoinWindows) because both sides are unbounded streams — without a time bound, the join would need infinite state
- KStream-KTable and KTable-KTable joins are NON-windowed — the KTable side acts as a lookup/materialized view holding the latest value per key, joined against whatever arrives on the KStream/KTable side right now
- KStream-KTable and KTable-KTable joins require CO-PARTITIONING: same number of partitions and same partitioning strategy/key on both input topics. GlobalKTable joins do NOT require co-partitioning because the full table is replicated to every Streams instance
- GlobalKTable trades memory for simplicity — every application instance holds a complete copy of the entire table. Appropriate only for small, mostly-static reference data (e.g., a currency lookup table), not high-cardinality or high-churn data
- map() and other key-changing operations trigger an internal repartition topic if followed by a key-based operation (join, aggregate, groupBy). mapValues() and other value-only transforms do NOT trigger repartitioning because the key, and therefore partition assignment, is unchanged
- Session windows are defined by an INACTIVITY GAP, not a fixed duration — two events that occur within the gap threshold of each other belong to the same (possibly merged) session, and the window's actual size varies per key
- A Tumbling window is mathematically a special case of a Hopping window where the hop/advance interval equals the window size (no overlap, no gap)
- Kafka Streams parallelism is capped by the number of input topic partitions — one stream task processes exactly one partition, so num.stream.threads beyond the partition count sits idle
- Source connectors read FROM an external system and write INTO Kafka; sink connectors read FROM Kafka and write INTO an external system. SMTs run on individual records in the pipeline: after production for source connectors, before delivery for sink connectors — they never touch aggregated or windowed data
Common Traps
Confusing Pairs
Scenario Tips
A Streams topology enriches a high-volume order stream with customer data from a KTable built off a compacted 'customers' topic, and the join silently produces no output for some orders...
Check co-partitioning first: the order topic and the customers topic must have the SAME partition count and be keyed/partitioned the same way. If either was created with a different partition count or a different key, matching records can land in different partitions and never meet in the join
Do not jump to 'add a window' — KStream-KTable joins are non-windowed by design. The missing-output symptom in this scenario points to co-partitioning, not timing
A topology needs to look up a small, rarely-changing table of ~50 country codes from every partition of a high-throughput click stream without worrying about partition alignment...
Use a GlobalKTable for the country codes. Its small size makes full replication to every instance cheap, and it removes the co-partitioning requirement entirely, simplifying the join
A regular KTable would technically work but forces you to co-partition the country-code topic with the click stream, which is unnecessary overhead for a tiny, mostly-static reference table
A code snippet shows .map((key, value) -> KeyValue.pair(value.getUserId(), value)) immediately followed by .groupByKey().count() — the question asks what happens internally...
Kafka Streams inserts an internal repartition topic between map() and groupByKey() because the key changed and the next operation (count via groupByKey) depends on key-based partitioning. Data is written to and re-read from this repartition topic before the aggregation runs
Do not assume this runs with zero extra I/O just because it's 'still the same topology' — any key-changing operation followed by a key-dependent operation forces a repartition topic, adding latency and storage overhead
A question asks which windowing type to use for grouping user activity into 'sessions' where a user might be idle for a variable amount of time between bursts of clicks...
Session windows. They are the only window type defined by an inactivity gap rather than a fixed duration, which matches variable idle time between bursts of activity
Hopping windows with a short hop interval might seem like a workaround, but they still use FIXED time boundaries and will artificially split or merge activity that doesn't align with clock time — session windows are purpose-built for this
Last-Minute Facts
Deployment, Testing, and Monitoring
Must-Know Facts
- TopologyTestDriver runs a Kafka Streams topology entirely in-memory with no broker — fast, deterministic unit tests of topology logic (routing, joins, windowing behavior) using synthetic input/output records
- EmbeddedKafka (and similarly, Testcontainers with a Kafka image) starts an actual in-process or containerized broker — slower, but validates real producer/consumer serialization, partitioning, and broker interaction end to end
- Consumer lag = latest partition offset minus the consumer's last committed offset. Rising lag with stable producer throughput points to a consumer-side bottleneck (slow processing, insufficient parallelism, GC pauses), not a producer or broker problem
- Under-replicated partitions (URP) is a top-priority broker health metric — a non-zero, persistent URP count means some replicas have fallen out of the ISR and the topic is running with reduced fault tolerance right now
- cleanup.policy=delete removes whole log segments once they age past retention.ms or exceed retention.bytes. cleanup.policy=compact instead retains only the LATEST record per key indefinitely (subject to compaction lag settings) — the two policies solve different problems and can be combined (compact,delete)
- A tombstone (a record with a null value for a given key) marks that key for deletion during compaction, but the tombstone itself is only physically removed after delete.retention.ms has passed — deleting a compacted key is not instantaneous
- SSL/TLS encrypts data in transit but provides authentication only if configured for mutual TLS (client certificates) — plain SSL alone authenticates the SERVER to the client, not the client to the broker. SASL (PLAIN, SCRAM, GSSAPI/Kerberos, OAUTHBEARER) is the standard way to authenticate clients
- ACLs are opt-in: without an authorizer explicitly configured on the brokers, there is no access control at all and any authenticated (or even unauthenticated on PLAINTEXT) client can read/write/create any topic
- security.protocol combines transport and auth: PLAINTEXT (neither), SSL (encryption, optional mTLS auth), SASL_PLAINTEXT (auth, no encryption), SASL_SSL (both encryption and auth) — SASL_SSL is the production-grade choice
Common Traps
Confusing Pairs
Scenario Tips
A question describes a compacted topic used to store 'current state per key' where a developer expects a key to disappear entirely after publishing a tombstone, but the key still shows up in a consumer read shortly after...
This is expected behavior — the tombstone marks the key for eventual removal, but physical deletion only happens after delete.retention.ms and the next compaction cycle. Immediately after producing a tombstone, consumers may still read the null value or even a stale prior value until compaction runs
Do not conclude the tombstone 'didn't work' or that compaction is broken — this is normal compaction timing behavior, not a bug
A cluster's under-replicated partitions metric spikes and stays elevated during a period of heavy write traffic...
Investigate immediately as a durability risk — followers are falling out of the ISR, likely because they can't keep up with the write rate (disk I/O, network, or replica.lag.time.max.ms too tight). This directly reduces the effective replication factor until it resolves
Do not dismiss a URP spike as 'just a monitoring blip' — of all the broker health metrics on the exam, URP is treated as one of the most actionable and safety-critical
A security review finds that a Kafka cluster uses security.protocol=SSL with client certificates NOT configured, and the team assumes clients are already authenticated...
They are wrong — without mutual TLS (client certs) configured, plain SSL only authenticates the broker to clients, not clients to the broker. Any client that can reach the broker over the network can connect. Add SASL or configure mutual TLS to actually authenticate clients
Simply enabling more cipher suites or a stronger TLS version improves encryption strength but does nothing to add client authentication
A team wants to write fast unit tests that run in CI on every commit without spinning up Docker, but also wants a separate integration test suite that validates real broker interaction before release...
Use TopologyTestDriver for the fast CI unit tests (no broker needed) and EmbeddedKafka or Testcontainers for the pre-release integration suite. This two-tier approach is the standard, exam-endorsed testing strategy for Kafka Streams applications
Relying on TopologyTestDriver alone for release confidence is a trap — it cannot catch real serialization, network, or partition-assignment bugs