PHP Academy · บทเรียน

Apache Kafka กับ PHP

สตรีมเหตุการณ์ปริมาณสูงด้วย Kafka

บทเรียน 3 จาก 413 ขั้นตอน

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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. เหตุผลที่ควรใช้การส่งข้อความแบบอะซิงโครนัส
  2. การทำงานกับ RabbitMQ ใน PHP
  3. Apache Kafka กับ PHP
  4. การสร้างเวิร์กโฟลว์ที่ขับเคลื่อนด้วยเหตุการณ์
← กลับไปที่ PHP Academy