CertPrepNow
ConfluentCCDAK3 domains

CCDAK Exam Notes

Last-minute traps, must-know facts, and scenario tips for the Confluent Certified Developer for Apache Kafka exam.

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
Domain 140% of exam

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

TrapAssuming acks=all by itself guarantees no data loss
Realityacks=all only waits for the CURRENT ISR set. If min.insync.replicas=1 and the leader is the only ISR member (followers fell behind or unclean leader election happened), acks=all is satisfied by the leader alone — a leader crash right after still loses the message. You need acks=all AND min.insync.replicas>=2 AND unclean.leader.election.enable=false for real durability
TrapThinking enable.idempotence=true is enough for exactly-once end to end
RealityIdempotence only prevents duplicate writes from producer retries within one session. It does not make multi-topic writes atomic and does not survive a producer restart on its own. Exactly-once requires the FULL chain: idempotent producer + transactions (transactional.id, begin/commit) + downstream consumers reading with isolation.level=read_committed
TrapAssuming a consumer only sees committed transactional messages by default
RealityThe consumer default is isolation.level=read_uncommitted. A consumer reading a topic written by a transactional producer will see in-flight and even later-aborted messages unless isolation.level=read_committed is explicitly set. Forgetting this setting silently defeats exactly-once guarantees on the read side
TrapBelieving message ordering for a key is guaranteed forever regardless of topic changes
RealityOrdering is guaranteed only within a single partition for the lifetime of that partition assignment. Increasing partition count changes the murmur2 hash-to-partition mapping for existing keys, silently breaking the ordering guarantee for events produced before vs after the change
TrapThinking a slow-processing consumer will simply lag but stay in the group
RealityIf a poll() loop takes longer than max.poll.interval.ms (default 5 minutes) to return for the next poll, the group coordinator considers the consumer dead and triggers a rebalance — even though the consumer's background heartbeat thread is still alive. This is a classic 'why did my consumer get kicked out of the group' scenario
TrapAssuming CooperativeSticky and Sticky are the same protocol, just with different names
RealitySticky assignment still uses the EAGER protocol — all consumers revoke ALL their partitions and rejoin during any rebalance (stop-the-world), it just tries to minimize how much reassignment happens. CooperativeSticky uses the COOPERATIVE protocol — only the specific partitions that need to move are revoked, and unaffected consumers keep processing during the rebalance. The 'no stop-the-world pause' benefit belongs to CooperativeSticky specifically, not plain Sticky
TrapThinking max.in.flight.requests.per.connection greater than 1 breaks ordering whenever idempotence is enabled
RealityWith idempotence enabled, Kafka guarantees ordering even with up to 5 in-flight requests per connection because the broker tracks per-partition sequence numbers and rejects/reorders out-of-sequence batches. Ordering breaks only if idempotence is OFF and max.in.flight > 1, because a failed-then-retried batch can land after a later batch

Confusing Pairs

acksmin.insync.replicas

acks is a PRODUCER setting that decides how many acknowledgments to wait for before considering a send successful (0, 1, or all). min.insync.replicas is a TOPIC/BROKER setting that decides the minimum ISR size required for an acks=all write to succeed — if ISR shrinks below this number, the producer gets a NotEnoughReplicasException. They must be reasoned about together, never in isolation

Idempotent ProducerTransactional Producer

Idempotent producer (enable.idempotence=true) prevents duplicate writes to a SINGLE partition from retries, scoped to one producer session. Transactional producer (adds transactional.id) builds on idempotence to provide ATOMIC writes across MULTIPLE topics/partitions and survives restarts via producer fencing. Every transactional producer is idempotent under the hood, but not every idempotent producer uses transactions

Range AssignorRoundRobin Assignor

Range: assigns each consumer a contiguous block of partitions PER TOPIC — with multiple topics this can leave the same consumer over-assigned across all of them. RoundRobin: distributes partitions across ALL subscribed topics evenly in round-robin order, generally more balanced with multiple topics. Neither minimizes reassignment during a rebalance the way Sticky does

Sticky AssignorCooperativeSticky Assignor

Sticky minimizes partition movement on rebalance but still uses the EAGER protocol (all consumers pause and rejoin). CooperativeSticky uses the COOPERATIVE protocol — only reassigned partitions are revoked, unaffected consumers keep consuming, no global stop-the-world pause. CooperativeSticky is the modern recommended default

auto.offset.resetCommitted Offset

auto.offset.reset (earliest/latest/none) ONLY applies when the consumer group has NO existing committed offset for a partition (new group, or offset expired/deleted). If a committed offset already exists, the consumer resumes from it regardless of what auto.offset.reset says — this setting does not override an existing commit

Scenario Tips

If the question asks about:

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...

Answer:

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

Distractor to avoid:

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

If the question asks about:

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...

Answer:

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

Distractor to avoid:

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

If the question asks about:

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...

Answer:

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

Distractor to avoid:

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

If the question asks about:

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...

Answer:

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

Distractor to avoid:

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

If the question asks about:

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...

Answer:

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)

Distractor to avoid:

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

1acks=0 (no ack, fastest, can lose data), acks=1 (leader only), acks=all/-1 (all ISR members, needs min.insync.replicas)
2Consumer isolation.level DEFAULT is read_uncommitted, NOT read_committed — you must set it explicitly for exactly-once reads
3Partition count: can only INCREASE, never decrease, on an existing topic
4max.poll.interval.ms default is 5 minutes (300000ms) — exceeding it while processing triggers a rebalance even with healthy heartbeats
5session.timeout.ms governs heartbeat-based failure detection; it is separate from max.poll.interval.ms, which governs poll-loop liveness
6CooperativeSticky = incremental rebalance, no stop-the-world. Eager (Range, RoundRobin, plain Sticky) = full stop-the-world on every rebalance
7Idempotence survives retries within a session; transactions (transactional.id) survive restarts via producer fencing/epoch bumping
8Schema Registry default compatibility mode = BACKWARD (new schema reads old data). NONE = compatibility checking disabled entirely
Domain 230% of exam

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

TrapAssuming any Kafka Streams join needs a window
RealityOnly KStream-KStream joins require a window. KStream-KTable and KTable-KTable joins are non-windowed lookups against the table's current state. Adding a window to a KStream-KTable join is not even a valid DSL option — this distinction is one of the single most tested Streams facts
TrapThinking GlobalKTable is just 'a KTable with a longer name' that behaves the same way
RealityGlobalKTable replicates the ENTIRE table to every application instance (no co-partitioning needed, but high memory cost). A regular KTable is partitioned like any other topic and requires co-partitioning for joins. Using GlobalKTable for a large, frequently-changing table can exhaust memory across every instance
TrapBelieving map() and mapValues() are interchangeable performance-wise
Realitymap() can change the key, so Kafka Streams marks the resulting stream for repartitioning if a downstream operation needs the key (join/aggregate/groupBy) — this creates an extra internal topic and adds latency/cost. mapValues() never changes the key, so no repartition topic is created. Prefer mapValues() whenever you are not actually changing the key
TrapAssuming session windows have a fixed, predictable width like tumbling or hopping windows
RealitySession window size is data-dependent — it grows or merges based on the actual gap between events for a given key. Two events 10 seconds apart with a 5-minute inactivity gap setting fall in the SAME session; the same events with a 3-second gap setting fall in DIFFERENT sessions. There is no single fixed window boundary to memorize
TrapThinking SMTs can perform aggregations or joins across multiple records
RealitySingle Message Transforms operate on ONE record at a time, independently — they cannot aggregate, join, or maintain state across records. For any cross-record logic in a Connect pipeline, you need Kafka Streams or ksqlDB upstream/downstream of Connect, not an SMT

Confusing Pairs

KStreamKTable

KStream: every record is an independent, immutable fact (an insert/event) — nothing is ever overwritten. KTable: every record is an upsert to a key — only the latest value per key is logically retained, like a changelog for a database table. This difference drives every join and windowing rule in Kafka Streams

KTableGlobalKTable

KTable: data is partitioned across Streams instances just like the source topic; joins with it require co-partitioning. GlobalKTable: the FULL dataset is broadcast to every instance; joins with it never require co-partitioning, at the cost of memory and startup time proportional to the whole topic, not just one partition's worth

Tumbling WindowSliding Window

Tumbling: fixed-size, non-overlapping, advances by exactly the window size — every event belongs to exactly one window. Sliding: windows are created based on the time difference between pairs of events (used for joins and some aggregations), not on a fixed clock-aligned grid — an event can trigger multiple, event-driven window boundaries rather than falling into pre-defined buckets

Standalone Connect WorkerDistributed Connect Worker

Standalone: one process, config via local properties files, no fault tolerance — if the worker dies every connector on it stops. Distributed: a cluster of workers coordinated via Kafka, config via REST API, connectors/tasks automatically rebalance onto surviving workers if one dies. Production deployments should always use distributed mode

Scenario Tips

If the question asks about:

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...

Answer:

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

Distractor to avoid:

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

If the question asks about:

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...

Answer:

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

Distractor to avoid:

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

If the question asks about:

A code snippet shows .map((key, value) -> KeyValue.pair(value.getUserId(), value)) immediately followed by .groupByKey().count() — the question asks what happens internally...

Answer:

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

Distractor to avoid:

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

If the question asks about:

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...

Answer:

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

Distractor to avoid:

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

1KStream-KStream = windowed join REQUIRED. KStream-KTable and KTable-KTable = non-windowed lookup/merge
2Co-partitioning required for KStream-KTable and KTable-KTable joins. GlobalKTable joins never need co-partitioning
3mapValues()/filter() = no repartition. map()/selectKey() + downstream key-based op = repartition topic created
4Session window = inactivity-gap based, variable size. Tumbling = fixed, no overlap. Hopping = fixed, overlapping. Sliding = event/time-difference based
5Tumbling window = special case of Hopping window where hop size = window size
6Streams parallelism ceiling = number of input topic partitions, regardless of num.stream.threads configured
7Source connector = external system → Kafka. Sink connector = Kafka → external system. Direction is always relative to Kafka
Domain 330% of exam

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

TrapUsing TopologyTestDriver results as proof that the application will behave correctly with real Kafka
RealityTopologyTestDriver validates topology LOGIC only — it never touches real serialization edge cases, real partition assignment, real consumer group rebalancing, or real network/broker failure modes. Integration tests with EmbeddedKafka/Testcontainers are still required before shipping a Streams app
TrapTreating zero consumer lag as proof the pipeline is healthy
RealityZero lag can mean the consumer is fully caught up AND healthy, or it can mean nothing is being produced at all. Always cross-check lag against producer throughput/message rate before declaring the pipeline healthy
TrapAssuming cleanup.policy=compact means old messages disappear immediately once a new value for the key arrives
RealityCompaction runs periodically (governed by settings like min.cleanable.dirty.ratio and segment rolling), not on every write. Between compaction runs, the log's 'head' can contain multiple values for the same key — only the compacted 'tail' guarantees a single latest value per key
TrapThinking SSL alone authenticates the client the same way SASL does
RealityPlain SSL/TLS (without mutual TLS) only proves the broker's identity to the client, not the other way around — any client with network access can still connect. Client authentication requires SASL or mutual TLS with client certificates explicitly configured
TrapAssuming ACLs are enforced by default once Kafka is running
RealityACL enforcement requires an authorizer to be explicitly configured on the brokers (e.g., authorizer.class.name). Without it, Kafka has NO authorization layer at all — this is a commonly cited real-world production misconfiguration and a favorite exam scenario

Confusing Pairs

TopologyTestDriverEmbeddedKafka / Testcontainers

TopologyTestDriver: in-memory, no broker, fast unit tests of topology logic only. EmbeddedKafka/Testcontainers: spins up a real (embedded or containerized) broker, slower, validates true end-to-end producer/consumer/serialization behavior. Use TopologyTestDriver for fast iteration during development, integration tests for pre-release confidence

cleanup.policy=deletecleanup.policy=compact

delete: age/size-based removal of entire segments — used for event logs where you only care about a retention window (e.g., 7 days of clickstream). compact: key-based retention of only the latest value per key, kept indefinitely — used for changelog/state topics (e.g., 'current account balance per user'). They can be combined as compact,delete to compact AND still cap total retention

SSL/TLSSASL

SSL/TLS: primarily an ENCRYPTION mechanism for data in transit; authenticates the server by default, the client only with mutual TLS configured. SASL: an AUTHENTICATION framework (PLAIN, SCRAM, GSSAPI/Kerberos, OAUTHBEARER) for proving client identity; provides no encryption on its own. Production clusters typically combine both via SASL_SSL

AuthenticationAuthorization (ACLs)

Authentication (SASL/mTLS) answers 'who are you?' — it establishes a verified client identity/principal. Authorization (ACLs) answers 'what are you allowed to do?' — it decides whether that already-authenticated principal can read/write/create a specific resource. A cluster can have authentication configured with NO ACLs, meaning any authenticated user can do anything

Scenario Tips

If the question asks about:

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...

Answer:

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

Distractor to avoid:

Do not conclude the tombstone 'didn't work' or that compaction is broken — this is normal compaction timing behavior, not a bug

If the question asks about:

A cluster's under-replicated partitions metric spikes and stays elevated during a period of heavy write traffic...

Answer:

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

Distractor to avoid:

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

If the question asks about:

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...

Answer:

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

Distractor to avoid:

Simply enabling more cipher suites or a stronger TLS version improves encryption strength but does nothing to add client authentication

If the question asks about:

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...

Answer:

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

Distractor to avoid:

Relying on TopologyTestDriver alone for release confidence is a trap — it cannot catch real serialization, network, or partition-assignment bugs

Last-Minute Facts

1TopologyTestDriver = no broker, unit tests only. EmbeddedKafka/Testcontainers = real broker, integration tests
2Consumer lag = latest offset - committed offset. Always check against producer throughput before calling it healthy
3cleanup.policy=delete (age/size-based removal) vs compact (latest-value-per-key, kept forever) vs compact,delete (both combined)
4Tombstone = null-value record marking a key for deletion; physical removal is delayed until delete.retention.ms passes and compaction runs
5security.protocol: PLAINTEXT (neither), SSL (encryption, server-auth by default), SASL_PLAINTEXT (auth, no encryption), SASL_SSL (both) — production default is SASL_SSL
6ACLs require an authorizer to be explicitly enabled — no authorizer means no authorization layer at all, regardless of authentication
7Under-replicated partitions (URP) > 0 sustained = investigate immediately, treated as a durability risk on the exam

Feeling confident?

Put your knowledge to the test with a timed CCDAK mock exam.