Skip to main content

Kafka

Apache Kafka uses a binary request-response protocol over TCP. Every request carries a header identifying the API being called and its version, followed by an API-specific body.

The protocol has no global version. Each API is versioned independently, and a client negotiates per API at connection time by issuing an ApiVersions request and using the highest version both sides support. DataStream negotiates in this way, so the exact wire layout depends on the broker.

Request Header

FieldTypeDescription
lengthint32Size of the request, excluding this field
api_keyint16Identifies the API being called
api_versionint16Version of that API
correlation_idint32Echoed in the response, to match the two
client_idnullable_stringOptional client identifier
tagged_fieldstagged_fieldsHeader v2 only

Three header versions exist. v0 ends at correlation_id, v1 adds client_id, and v2 adds the trailing tagged-fields buffer. Every API supporting flexible versions uses v2, so a capture decoded against v1 will mis-parse most modern requests.

Response Header

FieldTypeDescription
lengthint32Size of the response, excluding this field
correlation_idint32Matches the request
tagged_fieldstagged_fieldsHeader v1 only
bodyvariesDepends on the API. Most bodies open with throttle_time_ms

API Keys

The APIs DataStream exercises, producing or consuming:

API KeyNamePurpose
0ProduceSend records to a topic
1FetchRetrieve records from a topic
2ListOffsetsGet the earliest or latest offset for a partition
3MetadataGet topic and partition information
8OffsetCommitCommit consumer group offsets
9OffsetFetchRetrieve committed offsets
10FindCoordinatorLocate the group coordinator
11JoinGroupJoin a consumer group
12HeartbeatMaintain group membership
13LeaveGroupLeave a consumer group
14SyncGroupReceive the partition assignment
17SaslHandshakeSelect a SASL mechanism
18ApiVersionsDiscover the versions the broker supports
36SaslAuthenticateExchange SASL credentials

Primitive Types

TypeDescription
int8, int16, int32, int64Signed integers, big-endian
booleanA single byte, 0 or 1
float64IEEE 754 double, big-endian
uuid16 raw bytes
stringint16 length prefix, then UTF-8
nullable_stringAs string, with -1 meaning null
bytesint32 length prefix, then raw bytes
arrayint32 element count, then the elements
varint, varlongVariable-length integer, zigzag encoded
unsigned_varintVariable-length integer, not zigzag encoded
compact_stringunsigned_varint length prefix, then UTF-8
compact_arrayunsigned_varint element count, then the elements
recordsA record batch
tagged_fieldsunsigned_varint count, then tag, length and data triples

The compact forms and tagged_fields appear only on flexible-version APIs. Note that varint is zigzag encoded and unsigned_varint is not, despite the similar name.

Authentication

SASL is negotiated with SaslHandshake followed by SaslAuthenticate. The following mechanisms are supported:

MechanismDescription
plainUsername and password in the clear. Use with TLS
scram-sha-256Salted challenge-response
scram-sha-512Salted challenge-response with a stronger digest
gssapiKerberos

OAUTHBEARER and AWS_MSK_IAM are not supported.

Consumer Groups

Consumption uses consumer groups, with offsets committed explicitly rather than automatically. The partition assignment strategy is one of cooperativesticky, range, roundrobin or sticky. The names carry no hyphens: matching is case-insensitive but exact, and any other value — including the hyphenated spellings used elsewhere in the Kafka ecosystem — silently falls back to roundrobin rather than being rejected.