1. Append-Only Log คืออะไร?
Append-Only Log คือโครงสร้างการจัดเก็บข้อมูลที่เน้นการเพิ่มข้อมูลใหม่ต่อท้ายข้อมูลเดิม แทนการแก้ไขหรือเขียนทับข้อมูลที่มีอยู่โดยตรง
แนวคิดนี้ทำให้ระบบสามารถเก็บลำดับของเหตุการณ์หรือการเปลี่ยนแปลงที่เกิดขึ้นตามเวลาได้
ตัวอย่างเช่น ระบบธนาคารที่บันทึกรายการฝากเงิน ถอนเงิน และโอนเงิน โดยเพิ่มรายการใหม่เข้าไปในประวัติธุรกรรม
Log
|
+-- Entry 1: AccountCreated
|
+-- Entry 2: MoneyDeposited
|
+-- Entry 3: MoneyWithdrawn
|
+-- Entry 4: MoneyTransferred
|
+-- Entry 5: AccountBalanceChecked
แต่ละรายการมีตำแหน่งของตัวเองใน Log ทำให้ระบบสามารถตรวจสอบลำดับเหตุการณ์และนำข้อมูลไปประมวลผลต่อได้
อย่างไรก็ตาม การใช้ Append-Only Log ไม่ได้หมายความว่าข้อมูลจะไม่มีวันถูกลบ เพราะระบบอาจมีกลไก Retention, Log Compaction หรือการลบข้อมูลตามนโยบายที่กำหนดไว้
2. หลักการทำงานของ Append-Only Log
สมมติว่าเราต้องการสร้างระบบบันทึกธุรกรรมอย่างง่าย
เริ่มต้นจาก Log ที่ยังไม่มีข้อมูล
Log = []
เมื่อมีธุรกรรมแรกเข้ามา
Append(Transaction_001)
Log = [
Transaction_001
]
เมื่อมีธุรกรรมที่สอง
Append(Transaction_002)
Log = [
Transaction_001,
Transaction_002
]
เมื่อมีธุรกรรมที่สาม
Append(Transaction_003)
Log = [
Transaction_001,
Transaction_002,
Transaction_003
]
ข้อมูลเดิมยังคงอยู่ และรายการใหม่จะถูกเพิ่มเข้าไปตามลำดับ
โครงสร้างนี้สามารถนำไปใช้กับ Event Log, Audit Trail, Transaction Log และระบบจัดเก็บข้อมูลที่ออกแบบให้เขียนข้อมูลต่อเนื่องได้
สิ่งสำคัญคือ ต้องแยกความหมายระหว่างลำดับที่ข้อมูลถูกเขียนลง Log กับเวลาที่เหตุการณ์เกิดขึ้นจริง เพราะทั้งสองอย่างอาจไม่ตรงกันในระบบกระจายศูนย์
3. ทำไมการเขียนข้อมูลต่อท้ายจึงมีประสิทธิภาพ?
การเขียนข้อมูลลง Storage มีต้นทุนหลายส่วน เช่น การเข้าถึงตำแหน่งจัดเก็บ การจัดการ Index และการทำงานของระบบไฟล์
การเขียนข้อมูลแบบ Sequential Write สามารถลดการเข้าถึงตำแหน่งจัดเก็บแบบสุ่มในหลายสถานการณ์ โดยเฉพาะเมื่อระบบเขียนข้อมูลต่อเนื่องเป็นชุด
เปรียบเทียบแนวทางการเขียนข้อมูล
|
ประเด็น |
Sequential Write |
Random Write |
|
รูปแบบ |
เขียนข้อมูลต่อเนื่อง |
เขียนหลายตำแหน่ง |
|
ลักษณะการเข้าถึง |
มีความต่อเนื่องมากกว่า |
อาจต้องเข้าถึงตำแหน่งที่กระจัดกระจาย |
|
ประสิทธิภาพ |
เหมาะกับงานเขียนต่อเนื่อง |
ขึ้นอยู่กับ Storage และรูปแบบงาน |
|
การใช้งาน |
Log, Event Stream, WAL |
การแก้ไขข้อมูลและ Index บางประเภท |
|
ข้อจำกัด |
ต้องจัดการการอ่านและค้นหาข้อมูลเพิ่มเติม |
อาจมีต้นทุนจากการเข้าถึงแบบสุ่ม |
ข้อควรเข้าใจคือ Append-Only ไม่ได้เร็วกว่าเสมอไป ประสิทธิภาพจริงขึ้นอยู่กับอุปกรณ์จัดเก็บข้อมูล การทำ Buffering, Batching, Indexing, Synchronization และรูปแบบการเข้าถึงข้อมูล
นอกจากนี้ SSD ยังรองรับการเข้าถึงแบบสุ่มได้ดี จึงไม่ควรนำข้อได้เปรียบของ Sequential Write ไปใช้เป็นกฎตายตัวกับ Storage ทุกประเภท
4. โครงสร้างภายในของ Log
ในระบบที่ใช้งานจริง Log มักประกอบด้วยข้อมูลหลายส่วน ไม่ใช่เพียงข้อความเรียงต่อกัน
ตัวอย่างโครงสร้างของ Log Entry
{
"offset": 1001,
"event_id": "evt_1001",
"event_type": "OrderCreated",
"timestamp": "2026-10-14T12:00:00Z",
"payload": {
"order_id": "ORD-1001",
"amount": 1500
}
}
องค์ประกอบสำคัญ ได้แก่
- Offset: ตำแหน่งของรายการภายใน Log หรือ Partition
- Event ID: ตัวระบุเหตุการณ์สำหรับการติดตามหรือช่วยตรวจสอบข้อมูลซ้ำ
- Event Type: ประเภทของเหตุการณ์
- Timestamp: เวลาที่เกี่ยวข้องกับเหตุการณ์
- Payload: ข้อมูลที่เหตุการณ์ต้องการส่งต่อ
ระบบจริงอาจมี Metadata เพิ่มเติม เช่น Schema Version, Partition Key, Checksum และข้อมูลสำหรับการตรวจสอบสิทธิ์หรือการติดตามการทำงาน
Offset ไม่จำเป็นต้องเป็นหมายเลขเดียวกันทั้งระบบ ใน Apache Kafka แต่ละ Partition มีลำดับ Offset ของตัวเอง
5. Append-Only Log กับ Database Transaction
ฐานข้อมูลสมัยใหม่จำนวนมากใช้ Log เพื่อช่วยรับประกันความทนทานของธุรกรรมและรองรับการกู้คืนระบบ
ตัวอย่างหนึ่งคือ Write-Ahead Logging (WAL)
หลักการทั่วไปของ WAL คือ ระบบบันทึกข้อมูลการเปลี่ยนแปลงลงใน Log ก่อนที่การเปลี่ยนแปลงที่เกี่ยวข้องจะถูกเขียนลง Data Page ตามเงื่อนไขที่กำหนด
ตัวอย่าง:
Application
|
v
Database Transaction
|
v
Write-Ahead Log
|
v
Commit
|
v
Data Pages
แผนภาพนี้เป็นภาพรวมเชิงแนวคิด รายละเอียดลำดับการเขียนจริงขึ้นอยู่กับฐานข้อมูลและการตั้งค่า
หากระบบหยุดทำงานหลัง Commit แต่ก่อนที่ Data Page บางส่วนจะถูกเขียนลงดิสก์ ฐานข้อมูลสามารถใช้ WAL และกลไก Recovery เพื่อกู้คืนการเปลี่ยนแปลงที่ยืนยันแล้วได้ตามข้อกำหนดด้าน Durability
ตัวอย่างเทคโนโลยีที่เกี่ยวข้อง ได้แก่ PostgreSQL WAL และกลไก Transaction Log ของระบบฐานข้อมูลอื่น ๆ
ทั้งนี้ WAL ไม่ใช่ Event Log สำหรับธุรกิจโดยตรงเสมอไป เพราะ WAL มักบันทึกการเปลี่ยนแปลงในระดับฐานข้อมูล ขณะที่ Business Event Log บันทึกเหตุการณ์ในระดับโดเมน เช่น OrderCreated หรือ PaymentCompleted
6. Append-Only Log กับ Event Sourcing
ทั้งสองแนวคิดเกี่ยวข้องกัน แต่มีบทบาทต่างกัน
Append-Only Log เป็นรูปแบบการจัดเก็บข้อมูลที่เน้นการเพิ่มรายการใหม่ต่อท้าย
Event Sourcing เป็นแนวทางการออกแบบระบบที่ใช้เหตุการณ์เป็นแหล่งข้อมูลหลักสำหรับสร้างสถานะของระบบ
ตัวอย่างระบบบัญชีที่ใช้ Event Sourcing
Initial Balance = 0
Event 1: Deposit 1000
Event 2: Withdraw 200
Event 3: Deposit 500
Current Balance = 1300
ระบบสามารถคำนวณยอดเงินปัจจุบันจากการนำเหตุการณ์มาประมวลผลตามลำดับ
เมื่อจำนวนเหตุการณ์เพิ่มขึ้น ระบบอาจใช้ Snapshot เพื่อเก็บสถานะ ณ จุดหนึ่ง แล้วนำเฉพาะเหตุการณ์หลัง Snapshot มาประมวลผลต่อ
อย่างไรก็ตาม Event Sourcing ต้องออกแบบเรื่องความถูกต้องของธุรกรรม การจัดลำดับเหตุการณ์ การเปลี่ยนแปลง Schema และการจัดการเหตุการณ์ที่ผิดพลาดอย่างรอบคอบ
การใช้ Append-Only Log เพียงอย่างเดียวไม่ได้ทำให้ระบบกลายเป็น Event Sourcing โดยอัตโนมัติ
7. Append-Only Log ใน Apache Kafka
Apache Kafka ใช้แนวคิด Distributed Log ในการจัดเก็บและกระจาย Event Streams
โดยทั่วไป Topic จะถูกแบ่งออกเป็น Partition และแต่ละ Partition จะมีลำดับของ Record ของตัวเอง
ตัวอย่าง:
Topic: orders
Partition 0:
Offset 0 -> OrderCreated
Offset 1 -> PaymentRequested
Offset 2 -> PaymentCompleted
Partition 1:
Offset 0 -> OrderCreated
Offset 1 -> OrderCancelled
Offset 2 -> RefundRequested
แต่ละ Partition มีลำดับข้อมูลของตัวเอง จึงไม่ควรสรุปว่าระบบมีลำดับเหตุการณ์แบบ Global Order ครอบคลุมทุก Partition โดยอัตโนมัติ
Kafka สามารถเก็บข้อมูลไว้ตาม Retention Policy และรองรับการอ่านข้อมูลย้อนหลังภายในช่วงที่ข้อมูลยังคงอยู่
นอกจากนี้ Kafka ยังมี Log Compaction ซึ่งช่วยเก็บค่าล่าสุดของแต่ละ Key ตามกฎที่กำหนด จึงทำให้ข้อมูลใน Log ไม่จำเป็นต้องคงอยู่ครบทุก Record ตลอดไป
8. ความท้าทายในการออกแบบ Append-Only Log
8.1 Storage Growth
เมื่อมีการเพิ่มข้อมูลต่อเนื่อง ปริมาณข้อมูลย่อมเพิ่มขึ้น
แนวทางแก้ไข:
- กำหนด Retention Policy
- แบ่ง Log เป็น Segment
- ใช้ Log Compaction เมื่อเหมาะสม
- จัดเก็บข้อมูลระยะยาวในระบบ Archive
8.2 Duplicate Processing
Consumer อาจอ่านเหตุการณ์เดิมซ้ำเมื่อเกิดความล้มเหลวหรือมีการ Retry
แนวทางแก้ไข:
- ใช้ Idempotency Key
- ออกแบบ Consumer ให้รองรับการประมวลผลซ้ำ
- บันทึกสถานะการประมวลผลอย่างถูกต้อง
- ใช้กลไก Transaction เมื่อระบบและกรณีใช้งานรองรับ
8.3 Event Ordering
ระบบที่มีหลาย Producer หรือหลาย Partition อาจไม่สามารถรับประกันลำดับเหตุการณ์ทั้งหมดร่วมกันได้
แนวทางแก้ไข:
- กำหนด Partition Key ให้เหมาะสม
- รักษาลำดับภายในขอบเขตที่ต้องการ
- ใช้ Sequence Number เมื่อจำเป็น
- แยกเวลาที่เหตุการณ์เกิดขึ้นออกจากลำดับการบันทึก
8.4 Crash Recovery
ระบบต้องสามารถกู้คืนข้อมูลหลังเกิดความผิดพลาดได้
แนวทางแก้ไข:
- ใช้กลไก Durability ที่เหมาะสม
- ตรวจสอบความสมบูรณ์ของ Log
- ออกแบบ Recovery Procedure
- ทดสอบกรณีเครื่องหยุดทำงานระหว่างเขียนหรือ Commit
9. ตัวอย่างการสร้าง Append-Only Log ด้วย Python
ตัวอย่างต่อไปนี้แสดงการเพิ่ม Event ลงไฟล์ JSON Lines โดยแต่ละบรรทัดเก็บข้อมูลหนึ่งเหตุการณ์
import json
from datetime import datetime, timezone
from pathlib import Path
LOG_FILE = Path("events.jsonl")
def append_event(event_type, payload):
event = {
"event_id": f"evt-{datetime.now(timezone.utc).timestamp()}",
"event_type": event_type,
"timestamp": datetime.now(timezone.utc).isoformat(),
"payload": payload,
}
with LOG_FILE.open("a", encoding="utf-8") as file:
file.write(json.dumps(event, ensure_ascii=False) + "\n")
return event
append_event(
"OrderCreated",
{
"order_id": "ORD-1001",
"amount": 1500,
},
)
append_event(
"PaymentCompleted",
{
"order_id": "ORD-1001",
"amount": 1500,
},
)
print("Events appended successfully.")
ตัวอย่างนี้ใช้เพื่ออธิบายแนวคิดเท่านั้น ไม่ใช่ Implementation สำหรับ Production เนื่องจากยังไม่มีการจัดการ Concurrent Writers, การรับประกัน Durability อย่างครบถ้วน, การตรวจสอบความสมบูรณ์ของ Log และกลไก Idempotency ที่เหมาะสม
หากต้องการใช้ในระบบจริง ควรใช้ Event ID ที่สร้างอย่างเหมาะสม และพิจารณา Transactional Outbox หรือ Message Broker สำหรับการเผยแพร่เหตุการณ์ระหว่างระบบ
10. สรุป
Append-Only Log เป็นแนวคิดพื้นฐานที่พบได้ในระบบจัดเก็บข้อมูล ระบบฐานข้อมูล และระบบกระจายศูนย์
ประโยชน์สำคัญไม่ได้มีเพียงการเขียนข้อมูลต่อท้าย แต่ยังรวมถึงความสามารถในการติดตามลำดับการเปลี่ยนแปลง การตรวจสอบย้อนหลัง และการนำข้อมูลไปประมวลผลในระบบอื่น
การเข้าใจ Append-Only Log จะช่วยให้สามารถต่อยอดไปสู่หัวข้อที่ซับซ้อนกว่าได้ เช่น Distributed Log, Write-Ahead Logging, Event Sourcing, Log Replication และ Stream Processing
ความคิดเห็น
แสดงความคิดเห็น