ทั้งคู่เป็น **Messaging Systems** แต่มี architecture และ use cases ต่างกันมาก
ตารางเปรียบเทียบ
| ลำดับ | หัวข้อ | Apache Kafka | JMS (Java Message Service) |
|---|---|---|---|
| 1 | พื้นฐาน | Distributed commit log / Event streaming platform | API สำหรับ Message Oriented Middleware (MOM) |
| 2 | Model | Publish-Subscribe + Consumer Groups (Hybrid) | Point-to-Point (Queue) + Pub/Sub (Topic) |
| 3 | Mechanism | **Pull** - Consumer poll ข้อมูลเอง | **Push** - Broker push ให้ Consumer |
| 4 | Message Retention | Policy-based (เวลา/ขนาด) - เก็บได้นาน/ถาวร | Acknowledgment-based - ลบหลัง consume แล้ว |
| 5 | Ordering | ** đảm bảo** ต่อ partition | ไม่รับประกัน ordering (ขึ้นกับ provider) |
| 6 | Rebalancing | Auto rebalance เมื่อ consumer join/leave group | ไม่มี built-in (ขึ้นกับ provider) |
| 7 | Scalability | Horizontal scaling ด้วย partitions | จำกัดโดย queue/topic architecture |
| 8 | Replayability | ✅ อ่านซ้ำได้ (offset management) | ❌ ทั่วไปไม่รองรับ (ข้อความหายหลัง ack) |
| 9 | Throughput | สูงมาก (millions msg/sec) | ปานกลาง (ขึ้นกับ implementation) |
| 10 | Protocol | Custom binary protocol over TCP | JMS API (provider-specific wire protocol) |
Kafka: Pull-based Consumer Groups
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Producer │────▶│ Topic │◀───▶│ Consumer │
│ (Writer) │ │ (Partitions)│ │ Group │
└─────────────┘ └──────────────┘ └─────────────┘
│
┌──────┴──────┐
▼ ▼
Partition 0 Partition 1
(offset 0..n) (offset 0..n)
- Producers เขียนต่อ partition (round-robin หรือ key-based)
- Consumers ใน group เดียว แบ่งกันอ่าน partitions (1 partition = 1 consumer)
- Offset เก็บว่าแต่ละ consumer อ่านถึงไหน → **Replay ได้**
JMS: Push-based Queues/Topics
Point-to-Point (Queue): Publish/Subscribe (Topic):
┌─────────┐ ┌───────┐ ┌─────────┐ ┌───────┐
│Producer │───▶│ Queue │ │Producer │───▶│ Topic │
└─────────┘ └───┬───┘ └─────────┘ └───┬───┘
│ │
┌──────┴──────┐ ┌──────┴──────┐
▼ ▼ ▼ ▼
Consumer 1 Consumer 2 Subscriber 1 Subscriber 2
(competing) (only 1 gets msg) (both get msg) (both get msg)
- Queue: 1 message → 1 consumer (competing consumers)
- Topic: 1 message → all subscribers (broadcast)
- Message ถูกลบหลัง ack → **Replay ไม่ได้**
เมื่อไหร่ควรใช้ Kafka?
- 🔄 **Event Sourcing / CQRS** - ต้องการ replay events
- 📊 **Log Aggregation / Metrics** - High throughput, retention
- 🔗 **Microservices Communication** - Async, decoupled, replayable
- 📈 **Stream Processing** - Kafka Streams, ksqlDB, Flink
- 🌐 **Multi-consumer patterns** - Group + broadcast พร้อมกัน
เมื่อไหร่ควรใช้ JMS?
- 📋 **Traditional Enterprise Apps** - มี JMS provider อยู่แล้ว (ActiveMQ, IBM MQ, WebLogic)
- ✅ **Guaranteed Delivery once** - ไม่ต้อง replay, แค่ส่งถึงปลายทาง
- 🔧 **Simple Queue/Topic needs** - ไม่ต้องการ complexity ของ Kafka
- 🏢 **Legacy Integration** - ระบบเก่าที่ใช้ JMS API อยู่แล้ว
- 💰 **Transactional Messaging** - JTA/XA transactions (Kafka มี transactions แต่ซับซ้อนกว่า)
Code Comparison
Kafka Producer/Consumer (Java)
// Producer
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
KafkaProducer producer = new KafkaProducer<>(props);
producer.send(new ProducerRecord<>("my-topic", "key", "value"));
// Consumer
props.put("group.id", "my-group");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
KafkaConsumer consumer = new KafkaConsumer<>(props);
consumer.subscribe(Collections.singletonList("my-topic"));
while (true) {
ConsumerRecords records = consumer.poll(Duration.ofMillis(100));
for (ConsumerRecord record : records) {
System.out.println(record.value());
}
}
JMS (ActiveMQ Example)
ConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
Connection connection = factory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Queue (Point-to-Point)
Queue queue = session.createQueue("MY_QUEUE");
MessageProducer producer = session.createProducer(queue);
producer.send(session.createTextMessage("Hello Queue"));
// Topic (Pub/Sub)
Topic topic = session.createTopic("MY_TOPIC");
MessageProducer topicProducer = session.createProducer(topic);
topicProducer.send(session.createTextMessage("Hello Topic"));
connection.start();
// Consumer code similar...
สรุป
Kafka = Event Streaming Platform (High throughput, Replay, Distributed log)
JMS = Traditional Messaging API (Queue/Topic, Push, Acknowledgment-based)
เลือก Kafka สำหรับ Modern event-driven architectures | เลือก JMS สำหรับ Enterprise legacy integration