Apache Flink Streaming Message Queue Design
โดย อ. บอมกิตติทัศน์เจริญพนาสิทธิ์ | อัปเดต 24 ก. พ. 2026 | อ่าน 16 นาที
- Stream Processing คืออะไร — Batch vs Stream
- Apache Flink คืออะไร — สถาปัตยกรรมและจุดเด่น
- เปรียบเทียบ Flink vs Spark Streaming vs Kafka Streams
- Message Queue Design Pattern
- Kafka + Flink — คู่หู Stream Processing
- Flink Architecture — JobManager, TaskManager, State
- Windowing — Tumbling, Sliding, Session
- Checkpointing และ Exactly-once Semantics
- Flink SQL — Stream Processing ด้วย SQL
- ตัวอย่าง Real-time Fraud Detection Pipeline
- Deploy Flink บน Kubernetes
- Monitoring และ Troubleshooting
- Best Practices และสรุป
Stream Processing คืออะไร — Batch vs Stream
Batch Processing ประมวลผลข้อมูลเป็นก้อนใหญ่เช่นรัน ETL Job ทุกคืนเพื่อสรุปยอดขายวันนี้ข้อดีคือง่ายแต่ข้อเสียคือ Latency สูงข้อมูลอาจล่าช้าหลายชั่วโมงส่วน Stream Processing ประมวลผลข้อมูลทันทีที่เข้ามา Event-by-Event ให้ Latency ต่ำระดับมิลลิวินาทีเช่นตรวจจับ Fraud ทันทีเมื่อมี Transaction ผิดปกติแจ้งเตือน Server Down ทันทีเมื่อ Metric ผิดปกติ
ในปี 2026 Stream Processing กลายเป็น Default สำหรับ Data Pipeline ใหม่เพราะธุรกิจต้องการ Real-time Insight ไม่ใช่รายงานเมื่อวาน Use Case ที่นิยมได้แก่ Real-time Analytics Dashboard, Fraud Detection, IoT Sensor Monitoring, Recommendation Engine, Log Analysis และ Real-time ETL
Apache Flink คืออะไร — สถาปัตยกรรมและจุดเด่น
Apache Flink เป็น Open Source Distributed Stream Processing Framework ที่พัฒนาจาก Research Project ของมหาวิทยาลัยในเยอรมนีกลายเป็น Top-level Apache Project ในปี 2014 ถูกใช้งานโดย Alibaba (ประมวลผล 4.6 พันล้าน Event/วินาทีช่วง Singles' Day), Uber (Real-time Pricing), Netflix (Real-time Data Pipeline) และ Spotify (Recommendation)
จุดเด่นของ Flink ได้แก่ True Streaming ไม่ใช่ Micro-batching ให้ Latency ต่ำจริงๆ, Stateful Processing เก็บ State ใน Memory พร้อม Fault Tolerance, Exactly-once Semantics การันตีว่า Event จะถูก Process แค่ครั้งเดียว, Event Time Processing จัดการ Out-of-order Event ได้ดี, Unified Batch & Stream ใช้ API เดียวกันสำหรับทั้ง Batch และ Stream และ Flink SQL เขียน Stream Processing ด้วย SQL ได้เลย
เปรียบเทียบ Flink vs Spark Streaming vs Kafka Streams
| คุณสมบัติ | Apache Flink | Spark Streaming | Kafka Streams |
|---|---|---|---|
| Processing Model | True Streaming | Micro-batching | True Streaming |
| Latency | มิลลิวินาที | วินาที | มิลลิวินาที |
| State Management | Built-in (RocksDB) | Limited | Built-in (RocksDB) |
| Exactly-once | End-to-end | At-least-once (default) | End-to-end (Kafka only) |
| SQL Support | Flink SQL (ดีมาก) | Spark SQL | ksqlDB (แยก) |
| Deployment | Standalone/YARN/K8s | Standalone/YARN/K8s | Library (ไม่ต้อง Cluster) |
| Learning Curve | สูง | ปานกลาง | ต่ำ |
| เหมาะกับ | Complex Stream Processing | Batch + Stream | Kafka-centric App |
Message Queue Design Pattern
Message Queue เป็น Middleware ที่ Decouple ระบบ Producer กับ Consumer ให้ส่งข้อมูลผ่าน Queue/Topic แทนการเรียกกันตรงๆ Pattern หลักที่ต้องรู้
- Point-to-Point (Queue) — Message ถูกส่งไป Consumer เดียวเมื่อ Consumer อ่านแล้ว Message หายจาก Queue เหมาะกับ Task Distribution เช่นจ่ายงานให้ Worker หลายตัว
- Publish/Subscribe (Topic) — Message ถูกส่งไปทุก Subscriber ที่ Subscribe Topic นั้นเหมาะกับ Event Broadcasting เช่น Order Event ส่งไปทั้ง Inventory Service, Notification Service, Analytics
- Fan-out — Event เดียวถูกกระจายไปหลาย Queue/Topic ให้ Consumer แต่ละตัว Process แยกกัน
- Dead Letter Queue (DLQ) — Message ที่ Process ล้มเหลวหลายครั้งจะถูกย้ายเข้า DLQ สำหรับตรวจสอบด้วยมือไม่ Block Pipeline หลัก
- Priority Queue — Message ถูกจัดลำดับตามความสำคัญ High Priority ถูก Process ก่อน
- Event Sourcing — เก็บทุก Event เป็น Immutable Log สร้าง State ใหม่จาก Event ทั้งหมดได้ทุกเมื่อ
Kafka + Flink — คู่หู Stream Processing
Apache Kafka ทำหน้าที่เป็น Distributed Event Streaming Platform เก็บ Event เป็น Immutable Log ใน Topic แบ่งเป็น Partition สำหรับ Parallelism ส่วน Flink อ่าน Event จาก Kafka Topic ทำ Computation (Filter, Aggregate, Join, Window) แล้วเขียนผลลัพธ์กลับไป Kafka Topic อื่นหรือ Database
// Flink + Kafka Source (Java)
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
KafkaSource<String> source = KafkaSource.<String>builder()
.setBootstrapServers("kafka:9092")
.setTopics("orders")
.setGroupId("flink-order-processor")
.setStartingOffsets(OffsetsInitializer.latest())
.setValueOnlyDeserializer(new SimpleStringSchema())
.build();
DataStream<String> orders = env.fromSource(
source, WatermarkStrategy.noWatermarks(), "Kafka Orders"
);
// Transform
DataStream<OrderSummary> summary = orders
.map(json -> parseOrder(json))
.filter(order -> order.getAmount() > 0)
.keyBy(Order::getCustomerId)
.window(TumblingEventTimeWindows.of(Time.minutes(5)))
.aggregate(new OrderAggregator());
// Sink กลับ Kafka
KafkaSink<String> sink = KafkaSink.<String>builder()
.setBootstrapServers("kafka:9092")
.setRecordSerializer(
KafkaRecordSerializationSchema.builder()
.setTopic("order-summaries")
.setValueSerializationSchema(new SimpleStringSchema())
.build()
)
.setDeliveryGuarantee(DeliveryGuarantee.EXACTLY_ONCE)
.build();
summary.map(s -> toJson(s)).sinkTo(sink);
env.execute("Order Processor");
Flink Architecture — JobManager, TaskManager, State
Flink Cluster ประกอบด้วย 3 Component หลัก
- JobManager (Master) — รับ Job จาก Client สร้าง Execution Graph กระจายงานไป TaskManager จัดการ Checkpoint และ Recovery เมื่อ TaskManager ล่มมี 1 Active + 1 Standby สำหรับ HA
- TaskManager (Worker) — รัน Task จริงแต่ละ TaskManager มีหลาย Task Slot สำหรับ Parallelism เก็บ State ใน Memory/RocksDB
- State Backend — ที่เก็บ State ของ Operator มี 3 แบบ: HashMapStateBackend (เก็บใน Memory เร็วมากแต่จำกัดด้วย RAM), EmbeddedRocksDBStateBackend (เก็บใน RocksDB บน Disk รองรับ State ขนาดใหญ่) และ Checkpoint Storage (S3, HDFS สำหรับ Durable Snapshot)
Windowing — Tumbling, Sliding, Session
Window เป็น Concept สำคัญของ Stream Processing ที่จัดกลุ่ม Event ตามเวลาเพื่อทำ Aggregation
| Window Type | ลักษณะ | ตัวอย่าง |
|---|---|---|
| Tumbling | ช่วงเวลาคงที่ไม่ซ้อนกัน | สรุปยอดขายทุก 5 นาที |
| Sliding | ช่วงเวลาคงที่เลื่อนทับกัน | เฉลี่ย 10 นาทีล่าสุดอัปเดตทุก 1 นาที |
| Session | ช่วงเวลาตาม Activity Gap | Session ผู้ใช้ (จบเมื่อไม่มี Event 30 นาที) |
| Global | ไม่แบ่งเวลารวมทุก Event | นับ Total ตลอดชีพ |
// Tumbling Window — สรุปทุก 5 นาที
orders.keyBy(Order::getProductId)
.window(TumblingEventTimeWindows.of(Time.minutes(5)))
.sum("amount");
// Sliding Window — เฉลี่ย 10 นาที อัปเดตทุกนาที
orders.keyBy(Order::getProductId)
.window(SlidingEventTimeWindows.of(Time.minutes(10), Time.minutes(1)))
.aggregate(new AverageAggregator());
// Session Window — Session Gap 30 นาที
clicks.keyBy(Click::getUserId)
.window(EventTimeSessionWindows.withGap(Time.minutes(30)))
.process(new SessionAnalyzer());
Checkpointing และ Exactly-once Semantics
Checkpointing เป็นกลไกที่ทำให้ Flink Fault-tolerant ระบบจะสร้าง Consistent Snapshot ของ State ทั้ง Pipeline เป็นระยะ (เช่นทุก 1 นาที) เก็บไว้ใน Durable Storage เช่น S3 หรือ HDFS เมื่อเกิด Failure Flink จะ Restore จาก Checkpoint ล่าสุดแล้ว Replay Event จาก Kafka ตั้งแต่ Offset ที่ Checkpoint ไว้
// เปิด Checkpointing
env.enableCheckpointing(60000); // ทุก 60 วินาที
env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);
env.getCheckpointConfig().setMinPauseBetweenCheckpoints(30000);
env.getCheckpointConfig().setCheckpointTimeout(120000);
env.getCheckpointConfig().setMaxConcurrentCheckpoints(1);
// ใช้ RocksDB State Backend + S3 Checkpoint
env.setStateBackend(new EmbeddedRocksDBStateBackend());
env.getCheckpointConfig().setCheckpointStorage("s3://my-bucket/flink-checkpoints/");
End-to-end Exactly-once ต้องใช้ร่วมกับ Kafka Transaction Flink จะ Commit Kafka Offset และ Sink Output ภายใน Transaction เดียวกับ Checkpoint ทำให้แม้ Failure จะไม่มี Duplicate Output
Flink SQL — Stream Processing ด้วย SQL
Flink SQL ให้เขียน Stream Processing ด้วย SQL ได้เลยลด Learning Curve มากสำหรับคนที่คุ้นเคย SQL
-- สร้าง Kafka Source Table
CREATE TABLE orders (
order_id STRING,
customer_id STRING,
product_id STRING,
amount DOUBLE,
order_time TIMESTAMP(3),
WATERMARK FOR order_time AS order_time - INTERVAL '5' SECOND
) WITH (
'connector' = 'kafka',
'topic' = 'orders',
'properties.bootstrap.servers' = 'kafka:9092',
'properties.group.id' = 'flink-sql',
'format' = 'json',
'scan.startup.mode' = 'latest-offset'
);
-- Real-time Aggregation ทุก 5 นาที
SELECT
product_id,
TUMBLE_START(order_time, INTERVAL '5' MINUTE) AS window_start,
COUNT(*) AS order_count,
SUM(amount) AS total_revenue
FROM orders
GROUP BY
product_id,
TUMBLE(order_time, INTERVAL '5' MINUTE);
-- Fraud Detection: มากกว่า 10 Transaction ใน 1 นาที
SELECT customer_id, COUNT(*) AS tx_count
FROM orders
GROUP BY customer_id, TUMBLE(order_time, INTERVAL '1' MINUTE)
HAVING COUNT(*) > 10;
ตัวอย่าง Real-time Fraud Detection Pipeline
// Fraud Detection Pipeline
DataStream<Transaction> transactions = env.fromSource(kafkaSource, ...);
// Pattern: มากกว่า 5 Transaction จาก Card เดียวกันใน 1 นาที
DataStream<Alert> alerts = transactions
.keyBy(Transaction::getCardNumber)
.window(SlidingEventTimeWindows.of(Time.minutes(1), Time.seconds(10)))
.process(new ProcessWindowFunction<Transaction, Alert, String, TimeWindow>() {
@Override
public void process(String cardNumber, Context ctx,
Iterable<Transaction> txns, Collector<Alert> out) {
List<Transaction> list = new ArrayList<>();
txns.forEach(list::add);
if (list.size() > 5) {
double total = list.stream().mapToDouble(Transaction::getAmount).sum();
out.collect(new Alert(
cardNumber, "HIGH_FREQUENCY",
list.size() + " transactions in 1 min, total: " + total,
ctx.window().getEnd()
));
}
}
});
// ส่ง Alert ไป Kafka Topic + Database
alerts.sinkTo(kafkaAlertSink);
alerts.addSink(new JdbcSink<>(...));
Deploy Flink บน Kubernetes
# Flink Kubernetes Operator
helm repo add flink-operator https://downloads.apache.org/flink/flink-kubernetes-operator-1.8.0/
helm install flink-operator flink-operator/flink-kubernetes-operator
# FlinkDeployment CRD
apiVersion: flink.apache.org/v1beta1
kind: FlinkDeployment
metadata:
name: fraud-detection
spec:
image: flink:1.18
flinkVersion: v1_18
flinkConfiguration:
taskmanager.numberOfTaskSlots: "4"
state.backend: rocksdb
state.checkpoints.dir: s3://my-bucket/checkpoints/
execution.checkpointing.interval: "60000"
serviceAccount: flink
jobManager:
resource:
memory: "2048m"
cpu: 1
taskManager:
replicas: 3
resource:
memory: "4096m"
cpu: 2
job:
jarURI: s3://my-bucket/jars/fraud-detection.jar
entryClass: com.example.FraudDetection
parallelism: 8
upgradeMode: savepoint
Monitoring และ Troubleshooting
- Flink Web UI — ดู Job Graph, Task Status, Checkpoint History, Backpressure
- Prometheus + Grafana — Flink มี Prometheus Reporter ในตัวส่ง Metrics เข้า Grafana Dashboard
- Backpressure — ถ้า Operator ช้าจะเกิด Backpressure ดูได้จาก Web UI แก้ด้วยเพิ่ม Parallelism หรือ Optimize Logic
- Checkpoint Duration — ถ้า Checkpoint ใช้เวลานานเกินไปอาจ Timeout แก้ด้วยลด State Size หรือใช้ Incremental Checkpoint
- Out-of-Memory — TaskManager OOM แก้ด้วยเพิ่ม Memory, ใช้ RocksDB State Backend หรือลด State TTL
Best Practices และสรุป
- ใช้ Event Time ไม่ใช่ Processing Time — Event Time ให้ผลลัพธ์ที่ถูกต้องแม้ Event มาช้าหรือสลับลำดับ
- ตั้ง Watermark ให้เหมาะสม — Watermark บอกว่า Event ที่ช้ากว่านี้ไม่น่าจะมาแล้วกำหนดตาม SLA ของ Data Source
- ใช้ RocksDB State Backend — สำหรับ State ขนาดใหญ่ที่เกิน Memory
- เปิด Incremental Checkpoint — ลด Checkpoint Duration สำหรับ State ขนาดใหญ่
- ตั้ง State TTL — กำหนดอายุ State ที่ไม่ได้ใช้นานป้องกัน State โตไม่หยุด
- Monitor Backpressure — Backpressure คือสัญญาณว่า Pipeline มีคอขวดต้องแก้ทันที
- ใช้ Savepoint ก่อน Upgrade — สร้าง Savepoint ก่อน Deploy Version ใหม่เพื่อ Migrate State
- Design Idempotent Sink — Sink ต้องรองรับ Duplicate Write กรณี Recovery
Apache Flink + Message Queue เป็น Foundation ของ Real-time Data Architecture สมัยใหม่เหมาะกับ Fraud Detection, Real-time Analytics, IoT Processing และทุก Use Case ที่ต้องการ Low Latency + High Reliability ติดตามบทความใหม่ๆได้ที่ SiamCafe.net
Q: Apache Flink คืออะไร
Distributed Stream Processing Framework สำหรับ Stateful Computation แบบ Real-time รองรับ Exactly-once Semantics และ Event Time Processing