Skip to main content

Produce and consume messages between Kafka and Pulsar

StreamNative supports three data entry formats, kafka and pulsar. Each format has distinct characteristics:
  • kafka format: This provides the best performance; however, a Pulsar consumer cannot consume it unless a payload processor is employed.
  • pulsar format: This is the default data entry format on StreamNative cloud which supporting interoperability between Kafka and Pulsar clients, including Kafka client to Kafka client, and Pulsar client to Kafka client interactions, and vice versa. This means data between Apache Kafka and Apache Pulsar are interoperable. It is suitable for most scenarios where performance is not a critical consideration.
  • pulsar_non_batched format: It is similar to pulsar entry format, the difference is this entry format will encode the Kafka batch messages to non-batched messages for Pulsar client to consume messages with a key-shared subscription, for Ursa, the behavior will be same as pulsar format.
StreamNative Cloud also supports specifying the entry format on a per-topic basis. The entry format can be set through topic properties by using bin/pulsar-admin topics update-properties. The configuration key is kafkaEntryFormat, and the possible values are kafka or pulsar. The default value is pulsar if not specified.

Interoperability between Pulsar and Kafka clients

With the kafka entry format, Kafka producers can produce and consume messages directly and freely. However, Pulsar producers SHOULD NOT produce messages in these topics because they are unable to encode messages into a format consumable by Kafka clients. However, since version 2.9 of the Pulsar client, we introduced a message payload processor for Pulsar consumers. This means that messages produced from Kafka producers can now be consumed and decoded by Pulsar consumers. For the pulsar format, it allows messages to be freely produced and consumed between Kafka and Pulsar clients. The message format conversion is automatically handled by the broker, enabling more flexible use of either Kafka clients or Pulsar clients.

Details for the message format conversion with pulsar format

The conversion is mostly intuitive except for some edge cases. Take the following simple case for example,
The value received by a Pulsar consumer is guaranteed to be the same with the original value sent by a Kafka producer. However, a Kafka message has some extra metadata like:
  • key: the key used for routing the message to a specific partition
  • headers: a list of headers, each header is a key-value pair
A Pulsar message has similar fields:
  • key: the same as Kafka’s key
  • ordering key: the key used for Key_Shared subscriptions
  • properties: a list of properties, each property is a key-value pair
It should be noted that the types of key and header value are both byte[] in Kafka, while in Pulsar, the types of key and property value are both String. For keys, each key will be converted to a base64-encoded string as Pulsar’s key. See the following example:
You should use getKeyBytes() or getOrderingKey() to retrieve the original keys of Kafka messages. The anti-intuitive behavior is that the getKey() method will return the base64-encoded string. This behavior is made because the byte array could vary after the bytes -> UTF-8 string -> bytes conversion, for example:
Things get much more complicated with the conversion on headers.
  1. For a header key, there could be multiple values in a Kafka message but there is only a single property value for a given property key in a Pulsar message.
  2. There is no way to get the bytes of a Pulsar property value.
For the 1st issue, the latest value will be retained. For the 2nd issue, the conversion will be performed with the following approach:
  1. Convert the bytes directly as a UTF-8 string
  2. If the bytes is not a valid UTF-8 string’s bytes, convert it to a base64 encoded string.
For example,
There is another corner case that an extra property whose key is __ksn_internal_header_format will be received by the Pulsar consumer if there is a header value that is a base64-encoded string’s bytes.

Step to Produce msg with Kafka and Consume msg with Pulsar client

Requirements Pulsar Client Version ≥ 2.9 Pulsar Admin Version ≥ 2.10 Step
  1. Create topic with kafka format via Pulsar admin CLI
The kafka format can be following the same step, and using kafkaEntryFormat=kafka property.
  1. Install client libraries
  2. Kafka Producer and Pulsar Consumer with Kafka format

Step to Produce msg with Pulsar and Consume msg with Kafka client

  1. Create topic with pulsar format via Pulsar admin CLI
  2. Install client libraries
  3. Pulsar Producer and Kafka Consumer with Pulsar format

Step to Produce msg with Kafka client and Consume msg with Pulsar key-shared subscription

  1. Create topic with pulsar format via Pulsar admin CLI
  2. Install client libraries
  3. Kafka Producer and Pulsar Consumer with pulsar_non_batched format

Interoperability between Kafka and Pulsar Transactions

Currently, it is not possible to interoperate Kafka and Pulsar transactions together. You must choose one or the other because they use different mechanisms to store transactional states.

Interoperability between Kafka and Pulsar Schema

StreamNative Cloud supports both the Kafka and Pulsar schema registries as central repositories to store registered schema information, which enables producers and consumers to coordinate the schema of a topic’s messages through brokers. However, Kafka schemas and Pulsar schemas cannot be used simultaneously due to their differing API definitions and schema storage locations. We also plan to achieve a unified schema registry, which will support both Kafka and Pulsar schemas. This will allow for the exchangeable production and consumption of messages with schema using both Pulsar and Kafka clients:
  • Pulsar consumers will be able to consume messages with schema produced by Kafka producers.
  • Kafka consumers will be able to consume messages with schema produced by Pulsar producers.

Use Pulsar admin to get KSN producer and consumer stats

After the pulsar version 3.3.5.1 or 4.0.1.1, we can use the pulsar-admin CLI to get the KSN’s topic producer and consumer stats.
  1. Ursa Engine currently only supports namespace level stats.
  2. If you’re creating a Pulsar subscription on this topic, do not use __ksn_internal_subscription as the subscription name.
The KSN broker will register an internal producer and consumer for each topic. The producer’s name is {clusterName}-{generatorInstanceId}-{counter}, and the consumer’s name is __KSN__internal_consumer_{remoteAddress}. The subscription name is __ksn_internal_subscription. The internal producer and consumer will not send or consume messages, nor will they acknowledge messages or affect message retention. You can use the following command to get the stats:
You can also see the producer and consumer stats in the StreamNative Cloud console. Producer and Consumer Stats