A Ruby client library for Apache Kafka
This library is no longer actively developed and has been superseded by librdkafka via rdkafka-ruby bindings. While this library may still receive security patches and bug fixes, it is no longer recommended for production usage.
There needs to be a concerted effort to keep up with Kafka features. There is no point in trying to keep up with Kafka development when other languages use a well-established C binding and get more official support.
A Ruby client library for Apache Kafka, a distributed log and message bus. The focus of this library will be operational simplicity, with good logging and metrics that can make debugging issues easier.
Add this line to your application's Gemfile:
gem 'ruby-kafka'
And then execute:
$ bundle
Or install it yourself as:
$ gem install ruby-kafka
Producer API
Consumer API
Kafka 0.8
Full support in v0.4.x
Unsupported
Kafka 0.9
Full support in v0.4.x
Full support in v0.4.x
Kafka 0.10
Full support in v0.5.x
Full support in v0.5.x
Kafka 0.11
Full support in v0.7.x
Limited support
Kafka 1.0
Limited support
Limited support
Kafka 2.0
Limited support
Limited support
Kafka 2.1
Limited support
Limited support
Kafka 2.2
Limited support
Limited support
Kafka 2.3
Limited support
Limited support
Kafka 2.4
Limited support
Limited support
Kafka 2.5
Limited support
Limited support
Kafka 2.6
Limited support
Limited support
Kafka 2.7
Limited support
Limited support
This library is targeting Kafka 0.9 with the v0.4.x series and Kafka 0.10 with the v0.5.x series. There's limited support for Kafka 0.8, and things should work with Kafka 0.11, although there may be performance issues due to changes in the protocol.
This library requires Ruby 2.1 or higher.
Please see the documentation site for detailed documentation on the latest release. Note that the documentation on GitHub may not match the version of the library you're using – there are still being made many changes to the API.
A client must be initialized with at least one Kafka broker, from which the entire Kafka cluster will be discovered. Each client keeps a separate pool of broker connections. Don't use the same client from more than one thread.
require "kafka"
# The first argument is a list of "seed brokers" that will be queried for the full
# cluster topology. At least one of these *must* be available. `client_id` is
# used to identify this client in logs and metrics. It's optional but recommended.
kafka = Kafka.new(["kafka1:9092", "kafka2:9092"], client_id: "my-application")
You can also use a hostname with seed brokers' IP addresses:
kafka = Kafka.new("seed-brokers:9092", client_id: "my-application", resolve_seed_brokers: true)
The simplest way to write a message to a Kafka topic is to call #deliver_message:
kafka = Kafka.new(...)
kafka.deliver_message("Hello, World!", topic: "greetings")
This will write the message to a random partition in the greetings topic. If you want to write to a specific partition, pass the partition parameter:
# Will write to partition 42.
kafka.deliver_message("Hello, World!", topic: "greetings", partition: 42)
If you don't know exactly how many partitions are in the topic, or if you'd rather have some level of indirection, you can pass in partition_key instead. Two messages with the same partition key will always be assigned to the same partition. This is useful if you want to make sure all messages with a given attribute are always written to the same partition, e.g. all purchase events for a given customer id.
# Partition keys assign a partition deterministically.
kafka.deliver_message("Hello, World!", topic: "greetings", partition_key: "hello")
Kafka also supports message keys. When passed, a message key can be used instead of a partition key. The message key is written alongside the message value and can be read by consumers. Message keys in Kafka can be used for interesting things such as Log Compaction. See Partitioning for more information.
# Set a message key; the key will be used for partitioning since no explicit
# `partition_key` is set.
kafka.deliver_message("Hello, World!", key: "hello", topic: "greetings")
While #deliver_message works fine for infrequent writes, there are a number of downsides:
The Producer API solves all these problems and more:
# Instantiate a new producer.
producer = kafka.producer
# Add a message to the producer buffer.
producer.produce("hello1", topic: "test-messages")
# Deliver the messages to Kafka.
producer.deliver_messages
#produce will buffer the message in the producer but will not actually send it to the Kafka cluster. Buffered messages are only delivered to the Kafka cluster once #deliver_messages is called. Since messages may be destined for different partitions, this could involve writing to more than one Kafka broker. Note that a failure to send all buffered messages after the configured number of retries will result in Kafka::DeliveryFailed being raised. This can be rescued and ignored; the messages will be kept in the buffer until the next attempt.
Read the docs for Kafka::Producer for more details.
A normal producer will block while #deliver_messages is sending messages to Kafka, possibly for tens of seconds or even minutes at a time, depending on your timeout and retry settings. Furthermore, you have to call #deliver_messages manually, with a frequency that balances batch size with message delay.
In order to avoid blocking during message deliveries you can use the asynchronous producer API. It is mostly similar to the synchronous API, with calls to #produce and #deliver_messages. The main difference is that rather than blocking, these calls will return immediately. The actual work will be done in a background thread, with the messages and operations being sent from the caller over a thread safe queue.
# `#async_producer` will create a new asynchronous producer.
producer = kafka.async_producer
# The `#produce` API works as normal.
producer.produce("hello", topic: "greetings")
# `#deliver_messages` will return immediately.
producer.deliver_messages
# Make sure to call `#shutdown` on the producer in order to avoid leaking
# resources. `#shutdown` will wait for any pending messages to be delivered
# before returning.
producer.shutdown
By default, the delivery policy will be the same as for a synchronous producer: only wh
No open issues yet, or sync has not completed.