P
PipeCraft

Roadmap Progress

ข้อมูลเบื้องต้นเกี่ยวกับวิศวกรรมข้อมูล (Introduction to Data Engineering) Python สำหรับ Data Engineering พื้นฐาน Linux & CLI สำหรับวิศวกรข้อมูล Git สำหรับระบบงานข้อมูลและทีมพัฒนา ระบบเครือข่ายและระบบประมวลผลแบบกระจายศูนย์ (Networking & Distributed Systems) SQL ขั้นสูง (Window Functions & Optimization) ฐานข้อมูลไม่ใช่เชิงสัมพันธ์ (NoSQL Databases & Modern Stores) การออกแบบโครงสร้างข้อมูล (Star/Snowflake & SCD) โครงสร้างพื้นฐานเครือข่ายระบบคลาวด์ (Cloud-based Networking) สถาปัตยกรรม Data Lakehouse (Apache Iceberg & MinIO) Local-first Data Engineering ด้วย DuckDB โครงสร้างพื้นฐานในรูปแบบโค้ด (IaC ด้วย Terraform) การแปลงข้อมูลระดับโปรด้วย dbt-core ข้อตกลงร่วมด้านข้อมูล (Data Contracts) การบริการและการส่งต่อข้อมูลวิเคราะห์ (Data Serving & Reverse ETL) การประมวลผลข้อมูลขนาดใหญ่แบบกระจายด้วย Apache Spark ระบบจัดการเวิร์กโฟลว์ข้อมูล (Airflow, Dagster & Prefect) การประมวลผลข้อมูลแบบเรียลไทม์ด้วย Kafka & Redpanda การจัดการคอนเทนเนอร์และคลัสเตอร์ (Containers & Kubernetes) ระบบ CI/CD และการเฝ้าระวังคุณภาพข้อมูล (CI/CD, Monitoring & Testing) ระบบความปลอดภัยและการควบคุมข้อมูล (Security, Governance & Privacy) ระบบปฏิบัติการและประมวลผลโมเดล (Machine Learning & MLOps)
บทที่ 5: ระบบประมวลผลขนาดใหญ่และการจัดลำดับงาน (Orchestration, Scale & Streaming)

การประมวลผลข้อมูลแบบเรียลไทม์ด้วย Kafka & Redpanda

5.3 การส่งสัญญาณประมวลผลข้อมูลเรียลไทม์ (Kafka & Redpanda)

สถาปัตยกรรมสตรีมมิ่งข้อมูล (Data Streaming) ประมวลผลข้อมูลทันทีเมื่อเกิดเหตุการณ์ขึ้น โดยเก็บข้อมูลใน Message Broker เพื่อส่งต่อไปยังผู้บริโภคข้อมูลเรียลไทม์

1. โครงสร้างภายในตารางกระทู้แยกส่วนและการจดจำ Offset (Topic Partitioning Internals)

ทฤษฎีและกลไกการทำงาน (How it works): Apache Kafka จัดเก็บข้อมูลแต่ละหัวข้อ (Topic) แบบกระจายศูนย์โดยแบ่งออกเป็น **Partitions** ซึ่งมีโครงสร้างจัดเก็บแบบเขียนต่อท้ายไฟล์อย่างเดียว (Append-only Commit Log) เรียงตามลำดับอย่างเหนียวแน่น ข้อมูลแต่ละตัวที่แทรกจะได้รับรหัสตำแหน่ง **Offset** ประจำตัว กลไกนี้ช่วยให้ระบบสตรีมมิ่งสามารถอ่านข้อมูลขนานกันได้โดยไม่มีสะดุด และยินยอมให้ผู้รับ (Consumer) ย้อนไปดึงข้อมูลใหม่ ณ ตำแหน่งใดก็ได้ย้อนหลังตาม Offset ที่บันทึกไว้

# Concept of Kafka Topic partitioning and offsets layout
Topic: sales-clicks
   ├── Partition 0: [Msg 0 (Offset 0)] -> [Msg 1 (Offset 1)] -> [Msg 2 (Offset 2)]
   └── Partition 1: [Msg 0 (Offset 0)] -> [Msg 1 (Offset 1)]
                    

Use Case ในชีวิตจริง (Real-world Scenario): ยอดดาวน์โหลดกดไลก์เพจจากลูกค้าทั่วประเทศวิ่งเข้ามาพร้อมกัน 50,000 ครั้งต่อวินาที ทราฟฟิกจะโดนหั่นแยกเป็น 8 พาร์ทิชันกระจายแบ่งเบาภาระงานให้ Worker 8 ตัวคำนวณสรุปผลยอดได้เรียลไทม์

ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations): การเลือกใช้คีย์พาร์ทิชันที่ไม่มีการกระจาย (Bad partitioning key เช่น คีย์ตามรหัสปี) ทำให้ข้อมูลเกือบทั้งหมดตกไปที่พาร์ทิชันเดียว แก้ไขโดยเลือกใช้คีย์ที่กระจายตัวสูง เช่น ค่าแฮชเลขบัตรหรือ ID ลูกค้า (Customer UUID)

2. กลไกระบบแบ่งกลุ่มผู้รับและการจัดแจกพาร์ทิชันใหม่ (Consumer Groups & Rebalancing)

ทฤษฎีและกลไกการทำงาน (How it works): สมาชิกกลุ่มผู้บริโภคข้อมูล (**Consumer Group**) จะร่วมกันแบ่งส่วนแบ่งการสแกนพาร์ทิชันทั้งหมดของกระทู้ เมื่อมีการเพิ่มหรือลดเครื่องประมวลผลภายในกลุ่ม คลัสเตอร์โหนดประสานงานจะจัดระเบียบส่งคำสั่ง **Rebalance** เพื่อนำสิทธิ์จองคิวพาร์ทิชันมาแจกจ่ายให้สมาชิกใหม่รับช่วงงานต่อทันทีเพื่อให้แน่ใจว่าไม่มีพาร์ทิชันใดถูกทอดทิ้งไม่มีใครประมวลผล

# Python script simulating a Kafka Consumer listening in a Consumer Group
from kafka import KafkaConsumer
import json

consumer = KafkaConsumer(
    "production-clickstream",
    bootstrap_servers=["kafka-1:9092", "kafka-2:9092"],
    group_id="click-metrics-aggregator", # Group ID ties multiple processes
    auto_offset_reset="earliest",
    enable_auto_commit=False # Manual commits are safer for transaction consistency
)
                    

Use Case ในชีวิตจริง (Real-world Scenario): ระหว่างช่วงแคมเปญโปรโมชั่น 11.11 ระบบตรวจสอบหน้าสั่งซื้อยอดโหลดพุ่งชนขีดจำกัด ทีมระบบข้อมูลสามารถเปิดเซิร์ฟเวอร์ Consumer ตัวใหม่เข้ากลุ่มเดิมได้ทันทีโดยไม่ต้องหยุดการทำงานของระบบเพื่อมาขยายพอร์ต

ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations): ข้อผิดพลาด **Rebalance Storm** เมื่อระบบทำงานช้าเกินกว่าพารามิเตอร์ `max.poll.interval.ms` และถูกเตะออกจากกลุ่มบ่อยครั้ง แก้ไขโดยการย้ายกระบวนการคำนวณที่หนักไปประมวลผลแบบกระจาย หรือเพิ่มเวลารอบ polling ให้สอดคล้องกับประสิทธิภาพรันของสคริปต์

3. ความเสถียรข้อมูลและการกำหนดการสำเนากลุ่ม (ISR & Replication Configs)

ทฤษฎีและกลไกการทำงาน (How it works): เพื่อค้ำประกันว่าข้อความการชำระเงินไม่หายไปแม้เซิร์ฟเวอร์ Kafka Broker จะระเบิดพังพินาศ Kafka นำระบบการคัดลอกสำเนามาใช้งานโดยใช้ **In-Sync Replicas (ISR)**: - **Leader Partition**: โหนดหลักคอยรับเขียนอ่านข้อมูล - **Follower Partitions**: สำเนารองที่คอยตามซิงก์ดึงข้อมูลตามลีดเดอร์ หากเราตั้งค่าพารามิเตอร์ส่งข้อมูล `acks=all` (หรือ `acks=-1`) ตัว Producer จะสแตนด์บายรอจนกว่าเครื่อง ISR ทั้งหมดจะเซฟลงดิสก์สำเร็จ จึงจะยืนยันคำสั่งเขียน เพื่อการันตีระดับ Zero Data Loss

# Producer configuration demonstrating zero data loss settings
from kafka import KafkaProducer

producer = KafkaProducer(
    bootstrap_servers=["kafka-1:9092", "kafka-2:9092"],
    acks="all",            # Wait for replica handshakes before confirming write
    retries=5,             # Retry sending on transient failures
    max_in_flight_requests_per_connection=1 # Preserve exact sequence order
)
                    

Use Case ในชีวิตจริง (Real-world Scenario): ระบบตัดแต้มเงินบัญชีลูกค้าธนาคาร การสูญหายของข้อความแม้แต่รายการเดียวหมายถึงยอดเงินบัญชีของลูกค้าคลาดเคลื่อนทันที การเปิดใช้ `acks=all` และ `min.insync.replicas=2` ช่วยค้ำประกันให้ธุรกรรมคงอยู่เสถียร

ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations): การกำหนด `acks=all` ส่งผลกระทบทำให้ความเร็วการเขียนลดลง (Throughput drop) เนื่องจากคอขวดเวลาการคัดลอกเครือข่าย แก้ไขโดยเปิดใช้งานการบีบอัดข้อมูลแบบก้อน (Compression type snappy หรือ lz4)

4. ทฤษฎีความรับประกันจำนวนการประมวลผลข้อความ (At-Least-Once, At-Most-Once, และ Exactly-Once)

ทฤษฎีและกลไกการทำงาน (How it works): วงรอบระบบประมวลผลท่อสตรีมมีการเลือกรับรอง 3 เงื่อนไข: 1. **At-Most-Once (อย่างมากที่สุดหนึ่งครั้ง)**: คอมมิตเซฟ Offset ทันทีก่อนรันผลลัพธ์ หากโปรเซสพังข้อมูลจะสูญหายแต่ไม่เคยซ้ำซ้อน 2. **At-Least-Once (อย่างน้อยที่สุดหนึ่งครั้ง)**: รันผลลัพธ์จนจบก่อน แล้วค่อยสั่งคอมมิต Offset หากโปรเซสพังระเบียนข้อมูลอาจส่งไปซ้ำซ้อน 3. **Exactly-Once Processing (EoS - ครั้งเดียวอย่างแม่นยำ)**: ประสานร่วมกับระบบทรานแซกชันเพื่อยืนยันบันทึกทั้ง Offset และข้อมูลผลลัพธ์ปลายทางในบล็อกอะตอมิกเดียวกันผ่าน Kafka Transactions

# Conceptual settings to achieve exactly-once processing (EoS) in Kafka
# 1. Enable idempotence in Producer
producer_config = {'enable.idempotence': True, 'transactional.id': 'prod-tx-01'}
# 2. Configure Consumer to read only committed transactions
consumer_config = {'isolation.level': 'read_committed'}
                    

Use Case ในชีวิตจริง (Real-world Scenario): ท่อส่งเงินเดือนพนักงานปลายทางที่ห้ามเกิดยอดประมวลผลซ้ำซ้อน (Double payments) การวางระบบแบบ Exactly-Once การันตีว่าไม่มีใครได้รับเงินโอนซ้ำสองรอบหากจ๊อบเน็ตหลุดกลางคัน

ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations): ระบบ Exactly-Once มีข้อจำกัดที่ต้องการใช้ทรัพยากรประมวลผลสูงและรันได้เฉพาะบน Kafka-to-Kafka ทรานแซกชันเท่านั้น แก้ไขโดยหากสตรีมไปหาปลายทางภายนอก (เช่น Database) ให้ใช้วิธีรันแบบ At-Least-Once คู่กับการเขียนทับข้อมูลด้วยกลไก Idempotency คีย์ทับปลายทาง

5. การบีบอัดบันทึกเหตุการณ์และการกำหนดนโยบายจัดเก็บไฟล์ (Log Compaction)

ทฤษฎีและกลไกการทำงาน (How it works): สำหรับตารางสถานะข้อมูล (เช่น ตารางยอดบัตรเครดิตสะสมปัจจุบัน) เราไม่ได้ต้องการประวัติการซื้อทุกแถวย้อนหลังเป็นปี แต่ต้องการค่าล่าสุดของคีย์ Kafka นำเสนอคุณสมบัติ **Log Compaction** ระบบจะรันกวาดไฟล์เบื้องหลังเพื่อคัดลอกทิ้งลบข้อความออฟเซ็ตเก่าที่คีย์ซ้ำกันออกไป และเหลือทิ้งไว้เพียงค่าปัจจุบันของคีย์นั้นๆ ช่วยประหยัดเนื้อที่การจัดเก็บไฟล์ในเครื่องโบรกเกอร์มหาศาล

# Configuration parameters inside Kafka topic settings to enable log compaction
cleanup.policy=compact
delete.retention.ms=86400000 # Time window before deleted records are fully removed
                    

Use Case ในชีวิตจริง (Real-world Scenario): ตารางสถานะยอดเครดิตคงเหลือของลูกค้าที่พนักงานสืบค้นบ่อย การบีบอัด Log Compaction ช่วยให้โหนดระบบฐานข้อมูลใหม่สามารถโหลดสภาพคีย์สถานะยอดล่าสุดจากหัวข้อ Kafka ขึ้นมาจำในแรมได้อย่างรวดเร็วโดยไม่ต้องวิ่งไล่อ่านประวัติออร์เดอร์ย้อนหลังล้านแถว

ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations): การลบข้อมูลหลักออกด้วยการส่งคีย์ว่างเปล่า (Tombstone Marker) หากกำหนดเวลาจัดเก็บสั้นเกินไป อาจทำให้ Consumer บางกลุ่มตรวจเช็คไม่ทันและได้ค่ารายงานข้อมูลที่ไม่สมบูรณ์ แก้ไขโดยขยายกรอบเวลากักเก็บคีย์ลบ `delete.retention.ms` เผื่อไว้

🛠️ Weekend Sandbox Challenge: Build a manual offset-committing Kafka Consumer

โจทย์ปฏิบัติการ: จงเขียนโปรแกรม Python ในการดึงข้อมูลจากระบบ Kafka Broker โดยปิดคุณสมบัติ Auto-commit และทำการยืนยันพิกัด (Manual Offset Commit) เฉพาะเมื่อสคริปต์ประมวลผลข้อมูลลงฐานข้อมูลสำเร็จแล้วเท่านั้น

# manual_commit_consumer.py
from kafka import KafkaConsumer

consumer = KafkaConsumer(
    'production-sales',
    bootstrap_servers=['localhost:9092'],
    enable_auto_commit=False, # Disable auto-commit
    group_id='sales-verifier'
)

for message in consumer:
    # 1. Process records (Simulate database insert)
    print(f"Processing database write: {message.value.decode('utf-8')}")
    
    # 2. Commit offsets manually only after writing is successful
    consumer.commit()
    print("Offset committed successfully.")
                    

💼 Senior Technical Interview Q&A

Q1: จงอธิบายกลไกการประสานงานภายในกลุ่มผู้บริโภคข้อมูล (Consumer Group Coordination) และปัญหาเมื่อมีโหนดเข้าออกพาร์ทิชันใหม่ (Partition Rebalancing)?

A1: Consumer Group จะตกลงให้ผู้บริโภคย่อยแบ่งกันตรวจพาร์ทิชันของ Topic เมื่อมีโหนดเข้าออกเพิ่มหรือเครื่องหลุดการส่งชีพจร (Heartbeat) ตัวประคับประคอง (Group Coordinator) จะสั่งรันกลไก Rebalance เพื่อขยับสิทธิ์จองพาร์ทิชันใหม่ ระหว่างเกิด Rebalancing โปรเซสการอ่านเขียนข้อมูลสตรีมทั้งหมดจะถูกระงับชั่วคราวช้าลง

Q2: การออกแบบระบบสตรีมมิ่งให้มีคุณสมบัติประมวลผลครั้งเดียวอย่างแม่นยำ (Exactly-Once Semantics - EoS) ในระบบ Kafka และ Flink ทำงานร่วมกันอย่างไร?

A2: Flink และ Kafka ประสานงานกันผ่านการบันทึกสถานะธุรกรรมสองขั้นตอน (Two-Phase Commit Protocol) โดย Flink จะส่งจุดเช็คตรวจสอบสถานะ (Barrier Snapshots) เข้าท่อ และตัว Kafka Producer จะเปิดธุรกรรมรันเขียนข้อความชั่วคราว เมื่อ Flink ยืนยันบันทึกเสร็จ จึงสั่ง Commit ปิดกล่อง Offset และข้อมูลจริงพร้อมกัน

📡 Real-time Event Streaming & Lag Monitor

Interactive Streaming

เป้าหมาย: แก้ไขวิกฤตคอขวดข้อมูล (High Consumer Lag) เนื่องจากความเร็วในการดึงข้อมูลของระบบตามหลังการส่งสัญญาณคีย์คลิก (Producer) โดยคลิก **Scale Consumer** เพื่อจัดสรร Consumer Group ให้ครบ 3 โหนด ทำงานแบบขนานกับ 3 พาร์ทิชัน

Event Producer
P
user_clicks_stream ● 60 events/sec
Topic: user-clicks
Partition 0 Lag: 0
Partition 1 Lag: 2450
Partition 2 Lag: 3120
Consumer Group
Consumer-1
Offline
Offline
⚙️ Consumer Group scaling controls
ขยาย Consumer เพื่อดึงข้อมูลขนาน ป้องกันเหตุการณ์ข้อมูลล่าช้าและสูญหาย

ข้อดี / จุดเด่น & ข้อเสีย / ข้อควรระวัง

ข้อดี / จุดเด่น

  • ประมวลผลข้อมูลสดใหม่ได้ความเร็วระดับมิลลิวินาที ตอบรับเหตุการณ์ธุรกิจรวดเร็ว
  • เป็นแหล่งจัดเก็บข้อมูลชั่วคราวที่มีเสถียรภาพและขยายระบบได้แนวนอนยอดเยี่ยม

ข้อเสีย / ข้อควรระวัง

  • การเชื่อมโยงระบบและการทดสอบสถาปัตยกรรมมีความยุ่งยากและตั้งค่ายากกว่าระบบ Batch
  • ใช้พลังทรัพยากรจัดเตรียมดิสก์และแรมค่อนข้างสูงมากตลอดเวลา

ปฏิบัติการจริง (Lab Practice)

Bilingual Guide

แล็บ: สร้างและสตรีมข้อมูลผ่าน Redpanda Playground

💡 คำแนะนำ & ทริกเด็ด

ควรตรวจสอบค่า Lag ของ Consumer อยู่เสมอ หากค่าเริ่มสูงขึ้น แสดงว่าโค้ดดึงประมวลผลช้าเกินไป ให้ทำการเพิ่มจำนวน Partition และขยาย Consumers ขึ้นมาทำงานขนานช่วย