Apache Kafka con PHP
Transmita eventos de alto rendimiento con Kafka
Apache Kafka con PHP es una lección gratuita de PHP Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de PHP Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de PHP Academy incluye 4 lecciones en total.
Kafka con PHP
Kafka no es una cola de tareas: es un registro de commits distribuido y de solo adición. Los productores agregan registros a los topics; los consumidores leen desde su propio offset y pueden reproducir el historial. Esto hace que Kafka sea ideal para flujos de eventos de alto rendimiento, event sourcing y para alimentar varios grupos de consumidores independientes desde un mismo flujo.
En PHP, se comunica con Kafka mediante ext-rdkafka, un binding sobre la biblioteca de C probada en producción librdkafka.
Registro, no cola
Este es el cambio de modelo mental al pasar de RabbitMQ a Kafka:
- Los mensajes no se eliminan al consumirse; caducan según la política de retención (por tiempo o tamaño).
- Cada consumidor realiza el seguimiento de su propio offset, es decir, su posición en el registro.
- Un topic se divide en particiones; el orden solo está garantizado dentro de una partición.
- Varios grupos de consumidores leen el mismo topic de forma independiente.
Si necesita reproducir mensajes, distribuirlos a muchos lectores o alcanzar un rendimiento enorme, Kafka es adecuado. Si necesita enrutamiento por mensaje y TTL, RabbitMQ es más apropiado.
Instalar ext-rdkafka
Instale primero la biblioteca nativa, después la extensión PECL y, opcionalmente, un wrapper de más alto nivel.
# Debian/Ubuntu
apt-get install -y librdkafka-dev
pecl install rdkafka
echo "extension=rdkafka.so" >> php.ini
# Optional ergonomic wrapper
composer require longlang/phpkafka # or arnaud-lb/php-rdkafka-stubs for IDEProducir registros
Cree un RdKafka\Producer, obtenga una referencia al topic y llame a produce(). La clave determina en qué partición termina un registro: con la misma clave se usa la misma partición y se conserva el orden. Llame siempre a flush() antes de salir; de lo contrario, perderá los registros almacenados en el búfer.
<?php
$conf = new RdKafka\Conf();
$conf->set('bootstrap.servers', 'localhost:9092');
$producer = new RdKafka\Producer($conf);
$topic = $producer->newTopic('orders');
// RD_KAFKA_PARTITION_UA = let the partitioner choose by key
$key = 'order-42';
$topic->produce(RD_KAFKA_PARTITION_UA, 0, json_encode(['id' => 42]), $key);
$producer->poll(0);
$result = $producer->flush(10000); // wait up to 10s
if ($result !== RD_KAFKA_RESP_ERR_NO_ERROR) {
throw new RuntimeException('Failed to flush');
}Particionar por clave
La partición es el núcleo de la escalabilidad y el orden en Kafka. El particionador predeterminado aplica un hash a la clave del registro: partition = hash(key) % numPartitions. Elegir una buena clave es importante:
- Usar
customerIdcomo clave → todos los eventos de un cliente permanecen ordenados y en una sola partición. - Clave nula → distribución round-robin entre las particiones (máximo rendimiento, sin orden).
Nunca puede reducir el número de particiones de un topic, y añadir particiones reorganiza la asignación del hash; por eso, dimensione las particiones para el paralelismo máximo desde el principio.
Grupos de consumidores y offsets
Use el KafkaConsumer de alto nivel con group.id. Kafka asigna las particiones entre los miembros del grupo y realiza un rebalanceo cuando los miembros se incorporan o se retiran. Cada miembro lee únicamente sus particiones asignadas, lo que proporciona escalado horizontal sin esfuerzo adicional.
<?php
$conf = new RdKafka\Conf();
$conf->set('bootstrap.servers', 'localhost:9092');
$conf->set('group.id', 'order-emailers');
$conf->set('auto.offset.reset', 'earliest'); // start of log if no offset
$conf->set('enable.auto.commit', 'false'); // we commit manually
$consumer = new RdKafka\KafkaConsumer($conf);
$consumer->subscribe(['orders']);
while (true) {
$msg = $consumer->consume(5000);
if ($msg->err === RD_KAFKA_RESP_ERR_NO_ERROR) {
handle($msg->payload);
$consumer->commit($msg); // commit offset AFTER work
}
}
function handle(string $p): void {}Cuándo confirmar
La confirmación del offset define la semántica de entrega:
- Confirme después de procesar → entrega al menos una vez (un fallo antes de la confirmación vuelve a reproducir el registro).
- Confirme antes de procesar → entrega como máximo una vez (un fallo hace que se pierda).
El auto-commit (enable.auto.commit=true) confirma según un temporizador, independientemente de si el trabajo terminó; es práctico, pero puede descartar registros silenciosamente si se produce un fallo. Desactívelo y confirme manualmente cuando la corrección sea importante.
Gestionar errores de consumo
No todos los valores que retorna consume() son mensajes. Debe evaluar el código de error: __PARTITION_EOF y __TIMED_OUT son señales de control normales, no fallos.
<?php
$msg = $consumer->consume(2000);
switch ($msg->err) {
case RD_KAFKA_RESP_ERR_NO_ERROR:
echo "Got: {$msg->payload} @ offset {$msg->offset}\n";
break;
case RD_KAFKA_RESP_ERR__PARTITION_EOF:
echo "Reached end of partition\n"; // caught up, keep polling
break;
case RD_KAFKA_RESP_ERR__TIMED_OUT:
echo "No message this poll\n";
break;
default:
throw new \Exception($msg->errstr(), $msg->err);
}Ajustar el rendimiento
El rendimiento de Kafka proviene del procesamiento por lotes. Configuraciones clave del productor:
linger.ms: espera brevemente para agrupar más registros por solicitud (por ejemplo, 5–20 ms).batch.size/queue.buffering.max.messages: búferes más grandes y menos viajes de ida y vuelta.compression.type:lz4ozstdreducen considerablemente el coste de red.acks:allpara obtener durabilidad,1para reducir la latencia.
<?php
$conf = new RdKafka\Conf();
$conf->set('bootstrap.servers', 'localhost:9092');
$conf->set('compression.type', 'lz4');
$conf->set('linger.ms', '10');
$conf->set('batch.size', '65536');
$conf->set('acks', 'all');
$producer = new RdKafka\Producer($conf);Callbacks de informe de entrega
Como produce() es asíncrono, un envío fallido no lanzará una excepción en el momento. Registre un callback de informe de entrega en la configuración del productor para conocer el resultado de cada registro; esta es la única forma fiable de detectar fallos silenciosos del productor en PHP.
<?php
$conf = new RdKafka\Conf();
$conf->set('bootstrap.servers', 'localhost:9092');
$conf->setDrMsgCb(function ($producer, $msg) {
if ($msg->err) {
fwrite(STDERR, 'Delivery FAILED: ' . rd_kafka_err2str($msg->err) . "\n");
} else {
echo "Delivered to partition {$msg->partition} @ offset {$msg->offset}\n";
}
});
$producer = new RdKafka\Producer($conf);
// poll() services the callback queue; call it after producing
$producer->poll(0);Particularidades de PHP
Kafka presupone clientes de larga duración, pero el ciclo de vida de las solicitudes de PHP entra en conflicto con esto:
- Los productores almacenan datos en búfer de forma asíncrona: llame siempre a
flush()antes de que termine el script o perderá los registros. - Ejecute los consumidores como workers persistentes de CLI bajo un supervisor, nunca dentro de una solicitud web.
- Los rebalanceos pausan el consumo; mantenga corto el trabajo por mensaje o establezca
max.poll.interval.mscon un margen amplio para que no se le expulse del grupo. - Establezca
log_levely registre el callback de informe de entrega del productor para detectar fallos silenciosos.
Comprobación rápida
Garantías de orden en Kafka.
Resumen
Kafka al estilo de PHP:
- Kafka es un registro reproducible, no una cola; los consumidores realizan el seguimiento de los offsets.
- La partición por clave proporciona orden por clave y escalado.
- Los grupos de consumidores dividen las particiones y realizan rebalanceos automáticamente.
- Confirme los offsets después del trabajo para obtener una entrega al menos una vez; desactive el auto-commit para tener control.
- Ajuste
linger.ms,batch.sizeycompression.type; llame siempre aflush().
Siguiente tema: conectar estas primitivas para crear flujos de trabajo fiables y orientados a eventos.
Preguntas frecuentes
¿La lección «Apache Kafka con PHP» es gratis?
Sí — el texto completo de «Apache Kafka con PHP» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de PHP Academy, actualiza a CoddyKit PRO. El curso de PHP Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Apache Kafka con PHP»?
Transmita eventos de alto rendimiento con Kafka Practicas PHP Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar PHP Academy?
No se requiere experiencia previa. PHP Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.
¿Cuánto tiempo toma la lección «Apache Kafka con PHP»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de PHP Academy?
Sí. Cada lección de PHP Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Por qué usar mensajería asíncrona
- Trabajo con RabbitMQ en PHP
- Apache Kafka con PHP
- Creación de flujos de trabajo basados en eventos