Skip to content

Language: English | 简体中文

MiniKafka → Apache Kafka mapping

MiniKafka is a teaching model of Kafka's data plane, not a compatible broker. This guide separates mechanisms that preserve Kafka's essential contract from ones simplified for deterministic reading and testing.

The grades mean:

  • Equivalent — the observable invariant matches Kafka within this project's stated boundary.
  • Intentional simplification — the same idea is present, but protocol, persistence, scale, or background orchestration is reduced.
  • Semantically opposite — the implementation takes a path Kafka deliberately does not; do not transfer that behavior to production Kafka.

Log and storage

Grade MiniKafka module or mechanism Kafka concept / configuration / KIP Deliberate boundary
Equivalent core/record.py: binary key/value, headers, timestamps and tombstones Kafka record model; message.timestamp.type Uses Python value objects and a custom binary encoding.
Intentional simplification core/batch_codec.py: length-delimited batches with CRC32 Kafka record batch v2; KIP-98 producer fields MKB1 is not Kafka's wire or on-disk format.
Equivalent log/partition_log.py: append-only offsets and next-offset LEO Partition log and log end offset Ordering is partition-local and broker-assigned.
Equivalent log/segment.py: size-based rolling log.segment.bytes / topic segment.bytes Only size rolling is implemented; no time-based roll.
Intentional simplification log/index.py: sparse offset → byte-position index log.index.interval.bytes One compact index type; no time index or transaction index.
Intentional simplification No time index or offsetsForTimes API KIP-32 timestamps; ListOffsets / offsetsForTimes Timestamp lookup is absent.
Equivalent Recovery validates frame bounds and CRC, repairs only an active bad tail Kafka log recovery and CorruptRecordException boundary Closed-segment corruption is rejected rather than repaired.
Equivalent log/retention.py: continuous-prefix deletion of closed segments cleanup.policy=delete, retention.ms, retention.bytes Current code stops at the first non-expired segment, so it cannot create a middle hole.
Equivalent Compaction keeps the latest keyed record, tombstones for a grace period, and offset gaps cleanup.policy=compact, delete.retention.ms The logical record-selection contract matches; scheduling does not.
Intentional simplification LogCompactor + install_compacted_closed: sibling-directory build and two-step rename Kafka log cleaner, log.cleaner.* Each rename is atomic and exceptions roll back, but the pair is not one atomic exchange; a process crash between renames can leave only the backup directory.
Intentional simplification Batches are always uncompressed Producer compression.type; topic compression.type No gzip, snappy, lz4, or zstd flag/codec exists.
Intentional simplification PartitionLog.open scans every batch to recover max leader epoch leader-epoch-checkpoint; KIP-101 Startup cost is O(all batches), despite sparse offset indexes.
Intentional simplification PartitionLog.truncate_to reads retained batches, removes all segment files, and rebuilds one segment Kafka tail truncation during replica reconciliation O(all log) work and original segment boundaries are lost.
Equivalent Metadata and committed offsets use tmp + fsync + rename + parent fsync Kafka's durable checkpoint-file pattern File schemas and ownership are MiniKafka-specific.
Intentional simplification Producer identities use file fsync + atomic rename Kafka producer-ID allocation and broker metadata durability The local JSON store does not fsync its parent directory after rename.

Producer and acknowledgement path

Grade MiniKafka module or mechanism Kafka concept / configuration / KIP Deliberate boundary
Equivalent Keyed CRC32 partitioning and explicit partition selection Producer partitioner and partitioner.class Hash function is project-specific, not Kafka's default murmur2 compatibility contract.
Intentional simplification Sticky keyless partition plus per-partition accumulator KIP-480 sticky partitioner; batch.size, linger.ms, buffer.memory Flush scheduling is explicitly stepped for deterministic tests.
Equivalent acks=1 completes after the leader append Producer acks=1 It can lose an acknowledged leader-only tail, as in Kafka.
Intentional simplification acks=0 returns unknown offsets after the Direct API has already performed the leader append Producer acks=0 Kafka sends no broker response; MiniKafka can only model the caller's unknown outcome, not true fire-and-forget transport timing.
Intentional simplification acks=all precheck, captured-ISR waiter, and fail-fast Broker/topic min.insync.replicas; producer acks=all MiniKafka waits for every replica captured at append time; Kafka completion follows its replication/HW machinery as ISR changes.
Intentional simplification PID, producer epoch and sequence validation KIP-98 idempotent producer; enable.idempotence Identity allocation is a local JSON file, not broker coordination.
Intentional simplification Duplicate window stores exactly the latest batch Kafka retains five recent batches; max.in.flight.requests.per.connection <= 5 A retry of batch N arriving after N+1 was accepted becomes OutOfOrderSequence, not a duplicate hit.
Equivalent A newer producer epoch fences an older instance KIP-98 producer epoch fencing Applies to idempotent producers, not MiniKafka transactions.
Intentional simplification Producer.send is synchronous and returns an asyncio.Future KafkaProducer asynchronous send It must be called inside a running event loop.

Consumer and group coordination

Grade MiniKafka module or mechanism Kafka concept / configuration / KIP Deliberate boundary
Equivalent Consumer position is separate from committed next offset; seek/replay/lag are partition-local enable.auto.commit, auto.offset.reset, committed offsets Fetch size controls and errors use the Direct API rather than Kafka requests.
Intentional simplification OffsetStore persists commits in one atomic JSON file Compacted internal topic __consumer_offsets Offset commits do not exercise this project's own log/compaction stack.
Equivalent Round-robin gives one stable-generation owner per partition RoundRobinAssignor; partition.assignment.strategy Only one deterministic assignor is supplied.
Intentional simplification Join immediately performs server-side assignment and becomes stable Classic JoinGroup/SyncGroup group-coordinator protocol No group leader, sync phase, rebalance timeout, or revocation barrier.
Intentional simplification Old local assignment remains until refresh_assignment() Eager rebalance and KIP-429 cooperative rebalance Before refresh, two local consumers may temporarily believe they own the same partition; stale commits are still fenced.
Equivalent Generation checked on heartbeat and commit; ownership checked on commit Classic group generation fencing; session.timeout.ms A stale generation cannot overwrite the new owner's committed offset.
Intentional simplification Heartbeat expiry is driven by an injected clock and explicit call session.timeout.ms, heartbeat.interval.ms; KIP-62 No background heartbeat thread or coordinator network timeout.
Intentional simplification Unknown group currently raises UnknownMember Kafka GROUP_ID_NOT_FOUND / UNKNOWN_MEMBER_ID distinctions Error taxonomy is collapsed and the name can be misleading.

Replication and failover

Grade MiniKafka module or mechanism Kafka concept / configuration / KIP Deliberate boundary
Equivalent Followers pull complete batches from leader LEO Kafka follower Fetch replication A method call replaces broker-to-broker networking.
Intentional simplification ISR requires time lag, offset lag, and coverage of current HW replica.lag.time.max.ms; historical replica.lag.max.messages Modern Kafka uses the time rule; the offset cap and HW gate make state transitions deterministic and safe in the mini model.
Equivalent Within one running replica-set instance, HW is the minimum LEO across current ISR and bounds normal reads Kafka partition high watermark HW is exclusive and advances monotonically while that in-memory leader instance runs.
Intentional simplification HW is not checkpointed; startup initializes it from all replica LEOs Kafka replication-offset checkpoint files A lagging replica can temporarily move restarted visibility below a previously consumed offset.
Equivalent Leader epoch is stored in metadata and batches and fences stale requests KIP-101 leader epochs Epoch is present, but divergence detection does not use its history.
Semantically opposite Promotion/rejoin/follower catch-up truncate at HW rather than epoch divergence KIP-101 and KIP-279 leader-epoch reconciliation This is pre-KIP-101-style reasoning and may discard a tail that epoch comparison would retain.
Semantically opposite promote() may truncate the newly selected leader itself to HW Kafka leader election: the new leader's LEO defines the endpoint and followers align to it This creates a MiniKafka-only loss window for data present on all ISR replicas before HW advancement.
Intentional simplification Promotion and failure detection are explicit calls Controller election, KRaft (KIP-500) No automatic election, controller quorum, or unclean election.
Intentional simplification Single process hosts all broker replicas Kafka brokers are separate failure domains Disk layouts are separate, but process, scheduler, and host failures are shared.

Transactions and visibility

Grade MiniKafka module or mechanism Kafka concept / configuration / KIP Deliberate boundary
Equivalent Transactional records plus commit/abort control markers and LSO-filtered read_committed KIP-98 transaction markers; consumer isolation.level Coordinator and journal are local and bounded.
Equivalent Transaction data and markers currently append with acks=all Kafka transactional production requires durable replication This was corrected in the pre-existing worktree changes reviewed alongside this document.
Intentional simplification Transaction writes use no idempotent PID/epoch/sequence state Kafka transactions build on idempotence and transactional.id zombie fencing (KIP-98) transactional_id and the transaction journal are separate from ProducerStateManager; acks=all alone is not Kafka's transaction protocol.
Equivalent Staged input offsets publish only after commit markers; abort discards them sendOffsetsToTransaction read-process-write pattern Atomicity is within one in-process coordinator, not arbitrary coordinator failover.
Intentional simplification Journal recovery completes PREPARE states locally Kafka transaction state log and transaction coordinator No replicated __transaction_state internal topic or coordinator migration.

API, runtime, and excluded systems

Grade MiniKafka module or mechanism Kafka concept / configuration / KIP Deliberate boundary
Intentional simplification BrokerCluster Direct API is normative Kafka request/response protocol It teaches domain state transitions without protocol version machinery.
Intentional simplification Newline-delimited JSON/TCP adapter Kafka binary wire protocol It proves adapter separation only; Kafka clients cannot connect.
Intentional simplification Replication, linger flushes, retention and expiry are manually stepped Broker and client background threads Determinism replaces wall-clock concurrency in tests and labs.
Intentional simplification Custom lifecycle and flush modes Kafka log flush / shutdown configuration No JVM page-cache or throughput equivalence is claimed.
Intentional simplification Elections, KRaft/ZooKeeper, security, quotas, rack awareness and tiered storage are excluded KIP-500, KIP-405, broker security and quota configs These are explicit non-goals, not partially implemented features.

How to read the mapping

Start with rows marked Equivalent to learn the invariant: partition-local order, next-offset boundaries, HW visibility, stable ownership, and fencing. Then read each adjacent simplification before transferring the idea to a real Kafka deployment. Rows marked Semantically opposite are warnings: the code is useful for exposing a failure boundary, but its failover truncation must not be treated as Kafka behavior.