Apache Kafka กับ PHP
สตรีมเหตุการณ์ปริมาณสูงด้วย Kafka
Apache Kafka กับ PHP เป็นบทเรียน PHP Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน PHP Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส PHP Academy มีบทเรียนทั้งหมด 4 บทเรียน
Kafka ด้วย PHP
Kafka ไม่ใช่คิวงาน — แต่เป็นบันทึกคอมมิตแบบกระจายที่เติมต่อได้เท่านั้น ผู้ผลิตจะเติมระเบียนต่อท้ายหัวข้อ ส่วนผู้รับข้อความจะอ่านข้อมูลจากออฟเซ็ตของตนเองและเล่นประวัติซ้ำได้ จึงทำให้ Kafka เหมาะอย่างยิ่งสำหรับสตรีมเหตุการณ์ที่มีปริมาณงานสูง การสร้างแหล่งที่มาจากเหตุการณ์ และการป้อนข้อมูลจากสตรีมเดียวให้กลุ่มผู้รับข้อความอิสระหลายกลุ่ม
ใน PHP คุณสื่อสารกับ Kafka ผ่าน ext-rdkafka ซึ่งเป็นการเชื่อมต่อกับไลบรารี C ที่ผ่านการใช้งานจริงมาอย่างยาวนานอย่าง librdkafka
บันทึก ไม่ใช่คิว
การเปลี่ยนมุมมองทางความคิดจาก RabbitMQ มาเป็น Kafka:
- ข้อความจะไม่ถูกลบเมื่อมีการรับไปแล้ว แต่จะหมดอายุตามนโยบายการเก็บรักษา (ตามเวลาหรือขนาด)
- ผู้รับข้อความแต่ละรายติดตามออฟเซ็ตของตนเอง ซึ่งก็คือตำแหน่งในบันทึก
- หัวข้อถูกแบ่งเป็นพาร์ทิชัน การเรียงลำดับรับประกันเฉพาะภายในพาร์ทิชันเดียว
- กลุ่มผู้รับข้อความหลายกลุ่มอ่านหัวข้อเดียวกันอย่างเป็นอิสระจากกัน
หากคุณต้องการเล่นข้อมูลซ้ำ กระจายข้อมูลให้ผู้อ่านจำนวนมาก หรือมีปริมาณงานมหาศาล Kafka เหมาะสม แต่หากต้องการกำหนดเส้นทางแยกตามข้อความและกำหนด TTL RabbitMQ เหมาะสมกว่า
การติดตั้งส่วนขยาย ext-rdkafka
ติดตั้งไลบรารีเนทีฟก่อน จากนั้นติดตั้งส่วนขยาย PECL แล้วจึงติดตั้งตัวห่อระดับสูงเพิ่มเติมได้ตามต้องการ
# 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 IDEการสร้างระเบียน
สร้าง RdKafka\Producer รับตัวจัดการหัวข้อ แล้วเรียก produce() คีย์จะควบคุมว่าระเบียนจะไปอยู่ในพาร์ทิชันใด — คีย์เดียวกันจะอยู่ในพาร์ทิชันเดียวกันและรักษาลำดับไว้ เรียก flush() ทุกครั้งก่อนออกจากโปรแกรม มิฉะนั้นระเบียนที่อยู่ในบัฟเฟอร์จะสูญหาย
<?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');
}การแบ่งพาร์ทิชันด้วยคีย์
การแบ่งพาร์ทิชันคือหัวใจของความสามารถในการขยายระบบและการเรียงลำดับของ Kafka ตัวแบ่งพาร์ทิชันเริ่มต้นจะคำนวณแฮชจากคีย์ระเบียน: partition = hash(key) % numPartitions การเลือกคีย์ที่ดีมีความสำคัญ:
- ใช้
customerIdเป็นคีย์ → เหตุการณ์ทั้งหมดของลูกค้ารายหนึ่งจะเรียงลำดับอยู่ในพาร์ทิชันเดียวกัน - คีย์ว่าง → กระจายแบบวนรอบไปยังพาร์ทิชันต่าง ๆ (ปริมาณงานสูงสุด แต่ไม่มีการเรียงลำดับ)
คุณไม่สามารถลดจำนวนพาร์ทิชันของหัวข้อได้ และการเพิ่มพาร์ทิชันจะจัดเรียงการแมปแฮชใหม่ — ดังนั้นควรกำหนดขนาดพาร์ทิชันให้รองรับการทำงานพร้อมกันสูงสุดตั้งแต่ต้น
กลุ่มผู้รับข้อความและออฟเซ็ต
ใช้ KafkaConsumer ระดับสูงร่วมกับ group.id Kafka จะจัดสรรพาร์ทิชันให้สมาชิกในกลุ่ม และปรับสมดุลใหม่เมื่อสมาชิกเข้าร่วมหรือออกจากกลุ่ม สมาชิกแต่ละรายจะอ่านเฉพาะพาร์ทิชันที่ได้รับมอบหมาย ทำให้ขยายระบบตามแนวนอนได้โดยไม่ต้องทำอะไรเพิ่ม
<?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 {}ควรคอมมิตเมื่อใด
การคอมมิตออฟเซ็ตจะกำหนดความหมายของการส่งมอบ:
- คอมมิตหลังประมวลผล → อย่างน้อยหนึ่งครั้ง (หากโปรแกรมหยุดทำงานก่อนคอมมิต ระเบียนจะถูกอ่านซ้ำ)
- คอมมิตก่อนประมวลผล → ไม่เกินหนึ่งครั้ง (หากโปรแกรมหยุดทำงาน ระเบียนจะสูญหาย)
การคอมมิตอัตโนมัติ (enable.auto.commit=true) จะคอมมิตตามตัวจับเวลาโดยไม่สนใจว่างานของคุณเสร็จหรือไม่ — สะดวกแต่สามารถทำให้ระเบียนสูญหายโดยไม่รู้ตัวเมื่อโปรแกรมหยุดทำงาน ปิดใช้งานการทำงานนี้และคอมมิตด้วยตนเองเมื่อความถูกต้องสำคัญ
การจัดการข้อผิดพลาดขณะรับข้อความ
ค่าที่ส่งคืนจาก consume() ไม่ได้เป็นข้อความทั้งหมด คุณต้องแยกการทำงานตามรหัสข้อผิดพลาด — __PARTITION_EOF และ __TIMED_OUT เป็นสัญญาณควบคุมปกติ ไม่ใช่ความล้มเหลว
<?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);
}การปรับแต่งปริมาณงาน
ปริมาณงานของ Kafka มาจากการรวมระเบียนเป็นชุด การตั้งค่าที่สำคัญของผู้ผลิตมีดังนี้:
linger.ms— รอช่วงสั้น ๆ เพื่อรวมระเบียนต่อคำขอให้ได้มากขึ้น (เช่น 5–20 มิลลิวินาที)batch.size/queue.buffering.max.messages— บัฟเฟอร์ใหญ่ขึ้น ทำให้มีการเดินทางไปกลับน้อยลงcompression.type—lz4หรือzstdลดต้นทุนเครือข่ายได้อย่างมากacks—allเพื่อความคงทน และ1เพื่อเวลาแฝงที่ต่ำกว่า
<?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);ฟังก์ชันเรียกกลับรายงานการส่งมอบ
เนื่องจาก produce() ทำงานแบบไม่พร้อมกัน การส่งที่ล้มเหลวจะไม่ทำให้เกิดข้อผิดพลาดทันที ลงทะเบียนฟังก์ชันเรียกกลับรายงานการส่งมอบในการตั้งค่าผู้ผลิต เพื่อทราบผลลัพธ์ของระเบียนแต่ละรายการ — นี่เป็นวิธีเดียวที่เชื่อถือได้ในการตรวจจับความล้มเหลวของผู้ผลิตใน 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);ข้อควรระวังเฉพาะของ PHP
Kafka ออกแบบมาสำหรับไคลเอนต์ที่ทำงานต่อเนื่องเป็นเวลานาน แต่วงจรการร้องขอของ PHP ไม่เอื้ออำนวยต่อรูปแบบนี้:
- ผู้ผลิตจะเก็บข้อมูลในบัฟเฟอร์แบบไม่พร้อมกัน — เรียก
flush()ทุกครั้งก่อนสคริปต์สิ้นสุด มิฉะนั้นระเบียนจะสูญหาย - เรียกใช้ผู้รับข้อความเป็นผู้ปฏิบัติงาน CLI แบบถาวรภายใต้ตัวควบคุม และอย่าเรียกใช้ภายในคำขอเว็บ
- การปรับสมดุลใหม่จะหยุดการรับข้อความชั่วคราว ดังนั้นควรทำงานต่อข้อความให้สั้น หรือใช้
max.poll.interval.msด้วยค่าที่มากพอ เพื่อไม่ให้ถูกนำออกจากกลุ่ม - ตั้งค่า
log_levelและลงทะเบียนฟังก์ชันเรียกกลับรายงานการส่งมอบของผู้ผลิต เพื่อจับความล้มเหลวที่เกิดขึ้นโดยไม่แสดงอาการ
ตรวจสอบอย่างรวดเร็ว
การรับประกันการเรียงลำดับใน Kafka
สรุปทบทวน
Kafka ในรูปแบบ PHP:
- Kafka คือบันทึกที่เล่นซ้ำได้ ไม่ใช่คิว ผู้รับข้อความติดตามออฟเซ็ต
- การแบ่งพาร์ทิชันด้วยคีย์ให้การเรียงลำดับตามคีย์และช่วยขยายระบบ
- กลุ่มผู้รับข้อความจะแบ่งพาร์ทิชันและปรับสมดุลใหม่โดยอัตโนมัติ
- คอมมิตออฟเซ็ตหลังทำงานเพื่อให้ส่งมอบอย่างน้อยหนึ่งครั้ง และปิดการคอมมิตอัตโนมัติเพื่อควบคุมได้เอง
- ปรับแต่ง
linger.ms,batch.sizeและcompression.typeและเรียกflush()ทุกครั้ง
ถัดไป: นำพื้นฐานเหล่านี้มาเชื่อมต่อเป็นกระบวนการทำงานที่ขับเคลื่อนด้วยเหตุการณ์และเชื่อถือได้
เรียนรู้ PHP ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 49
- บทเรียน
- 195
คำถามที่พบบ่อย
บทเรียน “Apache Kafka กับ PHP” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “Apache Kafka กับ PHP” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส PHP Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส PHP Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “Apache Kafka กับ PHP”
สตรีมเหตุการณ์ปริมาณสูงด้วย Kafka คุณปฏิบัติ PHP Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน PHP Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน PHP Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “Apache Kafka กับ PHP” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน PHP Academy นี้ได้ไหม
ได้ บทเรียน PHP Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- เหตุผลที่ควรใช้การส่งข้อความแบบอะซิงโครนัส
- การทำงานกับ RabbitMQ ใน PHP
- Apache Kafka กับ PHP
- การสร้างเวิร์กโฟลว์ที่ขับเคลื่อนด้วยเหตุการณ์