PHP-rdkafka is a thin librdkafka binding providing a working PHP 5 / PHP 7 Kafka 0.8 / 0.9 client.
It supports the high level and low level consumers, producer, and metadata APIs.
The API ressembles as much as possible to librdkafka's, and is fully documented here.
https://arnaud-lb.github.io/php-rdkafka/phpdoc/rdkafka.setup.html
https://arnaud-lb.github.io/php-rdkafka/phpdoc/rdkafka.examples.html
For producing, we first need to create a producer, and to add brokers (Kafka servers) to it:
<?php
$rk = new RdKafka\Producer();
$rk->setLogLevel(LOG_DEBUG);
$rk->addBrokers("10.0.0.1,10.0.0.2");
Next, we create a topic instance from the producer:
<?php
$topic = $rk->newTopic("test");
From there, we can produce as much messages as we want, using the produce method:
<?php
$topic->produce(RD_KAFKA_PARTITION_UA, 0, "Message payload");
The first argument is the partition. RD_KAFKA_PARTITION_UA stands for unassigned, and lets librdkafka choose the partition.
The second argument are message flags and should always be 0, currently.
The message payload can be anything.
The RdKafka\KafkaConsumer class supports automatic partition assignment/revocation. See the example here.
We first need to create a low level consumer, and to add brokers (Kafka servers) to it:
<?php
$rk = new RdKafka\Consumer();
$rk->setLogLevel(LOG_DEBUG);
$rk->addBrokers("10.0.0.1,10.0.0.2");
Next, create a topic instance by calling the newTopic()
method, and start
consuming on partition 0:
<?php
$topic = $rk->newTopic("test");
// The first argument is the partition to consume from.
// The second argument is the offset at which to start consumption. Valid values
// are: RD_KAFKA_OFFSET_BEGINNING, RD_KAFKA_OFFSET_END, RD_KAFKA_OFFSET_STORED.
$topic->consumeStart(0, RD_KAFKA_OFFSET_BEGINNING);
Next, retrieve the consumed messages:
<?php
while (true) {
// The first argument is the partition (again).
// The second argument is the timeout.
$msg = $topic->consume(0, 1000);
if ($msg->err) {
echo $msg->errstr(), "\n";
break;
} else {
echo $msg->payload, "\n";
}
}
Consuming from multiple topics and/or partitions can be done by telling librdkafka to forward all messages from these topics/partitions to an internal queue, and then consuming from this queue:
Creating the queue:
<?php
$queue = $rk->newQueue();
Adding topars to the queue:
<?php
$topic1 = $rk->newTopic("topic1");
$topic1->consumeQueueStart(0, RD_KAFKA_OFFSET_BEGINNING, $queue);
$topic1->consumeQueueStart(1, RD_KAFKA_OFFSET_BEGINNING, $queue);
$topic2 = $rk->newTopic("topic2");
$topic2->consumeQueueStart(0, RD_KAFKA_OFFSET_BEGINNING, $queue);
Next, retrieve the consumed messages from the queue:
<?php
while (true) {
// The only argument is the timeout.
$msg = $queue->consume(1000);
if ($msg->err) {
echo $msg->errstr(), "\n";
break;
} else {
echo $msg->payload, "\n";
}
}
librdkafka can store offsets in a local file, or on the broker. The default is local file, and as soon as you start using RD_KAFKA_OFFSET_STORED
as consuming offset, rdkafka starts to store the offset.
By default, the file is created in the current directory, with a name based on the topic and the partition. The directory can be changed by setting the offset.store.path
configuration property.
Other interesting properties are: offset.store.sync.interval.ms
, offset.store.method
, auto.commit.interval.ms
, auto.commit.enable
, offset.store.method
, group.id
.
<?php
$topicConf = new RdKafka\TopicConf();
$topicConf->set("auto.commit.interval.ms", 1e3);
$topicConf->set("offset.store.sync.interval.ms", 60e3);
$topic = $rk->newTopic("test", $topicConf);
$topic->consumeStart(0, RD_KAFKA_OFFSET_STORED);
librdkafka will buffer up to 1GB of messages for each consumed partition by default. You can lower memory usage by reducing the value of the queued.max.messages.kbytes
parameter on your consumers.
Each consumer and procuder instance will fetch topics metadata at an interval defined by the topic.metadata.refresh.interval.ms
parameter. Depending on your librdkafka version, the parameter defaults to 10 seconds, or 600 seconds.
librdkafka fetches the metadata for all topics of the cluster by default. Setting topic.metadata.refresh.sparse
to the string "true"
makes sure that librdkafka fetches only the topics he uses.
Setting topic.metadata.refresh.sparse
to "true"
, and topic.metadata.refresh.interval.ms
to 600 seconds (plus some jitter) can reduce the bandwidth a lot, depending on the number of consumers and topics.
This setting allows librdkafka threads to terminate as soon as librdkafka is done with them. This effectively allows your PHP processes / requests to terminate quickly.
When enabling this, you have to mask the signal like this:
<?php
// once
pcntl_sigprocmask(SIG_BLOCK, array(SIGIO));
// any time
$conf->set('internal.termination.signal', SIGIO);
https://arnaud-lb.github.io/php-rdkafka/phpdoc/book.rdkafka.html
Documentation copied from librdkafka.
Authors: see contributors.
php-rdkafka is released under the MIT license.