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)
บทที่ 2: การจัดเก็บและสร้างแบบจำลองข้อมูล (Data Storage & Modeling)

ฐานข้อมูลไม่ใช่เชิงสัมพันธ์ (NoSQL Databases & Modern Stores)

2.2 ฐานข้อมูล NoSQL และกลไกเครื่องยนต์จัดเก็บ (NoSQL Databases & Storage Engines)

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

1. ฐานข้อมูลแบบ Key-Value และ Document (Redis vs. MongoDB)

ทฤษฎีและกลไกการทำงาน (How it works): NoSQL แบ่งโครงสร้างตามการจัดเก็บหลัก: - **Key-Value Store (เช่น Redis)**: ทำการเก็บข้อมูลทั้งหมดในหน่วยความจำชั่วคราว (In-memory) ดึงหาค่าตรงตัวผ่านรหัสกุญแจ (Key) ด้วยความเร็วระดับไมโครวินาที - **Document Store (เช่น MongoDB)**: เก็บข้อมูลในรูปแบบไฟล์กึ่งมีโครงสร้าง (BSON/JSON Documents) รองรับการสร้างดัชนีซ้อนและคิวรี่ที่มีความยืดหยุ่นสูงโดยไม่ต้องประกาศโครงสร้างตารางล่วงหน้า (Schemaless)

# Python script interacting with Redis (Key-Value) and MongoDB (Document)
import redis
from pymongo import MongoClient

# 1. Redis Session Cache Write
r = redis.Redis(host='localhost', port=6379, db=0)
r.setex("user:42:session", 3600, "active_session_payload")

# 2. MongoDB Event Log Write
client = MongoClient("mongodb://localhost:27017/")
db = client.pipecraft_logs
db.events.insert_one({
    "user_id": 42,
    "action": "checkout",
    "metadata": {"items_count": 3, "ip": "192.168.1.1"}
})
                    

Use Case ในชีวิตจริง (Real-world Scenario): ระบบจำหน่ายสินค้าออนไลน์ใช้ Redis ในการจำลองที่เก็บตะกร้าสินค้าชั่วคราว (Session Cache) เพื่อการันตีความเร็ว และเลือกใช้ MongoDB ในการบันทึกประวัติการกระทำหรือล็อกพฤทีพฤติกรรมผู้ใช้เพื่อประโยชน์ในการวิเคราะห์

ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations): ความไม่ยืดหยุ่นของสกีมาใน MongoDB อาจส่งผลให้ระบบงานพังหากแอปพลิเคชันป้อนฟิลด์ผิดเพี้ยนเข้ามาโดยไม่มีตัวคัดกรอง แก้ไขโดยกำหนดกฎการตรวจสอบโครงสร้างเอกสาร (Schema Validation Rules) ที่ฝั่ง MongoDB หรือใช้ไลบรารี Pydantic คัดกรองประเภทในระดับโค้ดก่อนเซฟ

2. เครื่องยนต์จัดเก็บข้อมูล: ข้อเปรียบเทียบ B-Tree vs. LSM-Tree

ทฤษฎีและกลไกการทำงาน (How it works): การเขียนและอ่านลงแผ่นดิสก์ขับเคลื่อนด้วย 2 อัลกอริทึมหลัก: - **B-Tree Engine (เช่น InnoDB ของ MySQL)**: บันทึกข้อมูลแบ่งเป็นบล็อกขนาดคงที่ (Pages) เมื่ออัปเดตจะเข้าไปเขียนทับที่ตำแหน่งดิสก์เดิมตรงตัว (In-place Update) ทำให้ดึงข้อมูลสุ่มอ่าน (Random Read) รวดเร็ว แต่เขียนช้า - **LSM-Tree Engine (เช่น RocksDB, Cassandra)**: แปลงการเขียนเป็นระเบียบล็อกต่อท้าย (Append-only) โดยจะพักข้อมูลเรียงลำดับในหน่วยความจำ (Memtable) แล้วทยอยเขียนลงดิสก์ทีเดียวเป็นโครงสร้างไฟล์ SSTable ทำให้ประสิทธิภาพฝั่งเขียน (Write Throughput) ดีเลิศ

# Disk Layout Logic Comparison
B-Tree (In-Place):
Disk Block [Page 1: Row A, Row B, Row C] -> (Update B) -> Overwrite Page 1

LSM-Tree (Append-only):
Memtable (RAM) -> (Sorted Flush) -> SSTable 1 (Disk) [Row B v2]
(Old Row B v1 remains in SSTable 0 on disk until Compaction merges them)
                    

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

ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations): LSM-Tree ต้องแลกมาด้วยความล่าช้าในการอ่าน (Read Latency) เนื่องจากข้อมูลของหนึ่งออบเจกต์อาจกระจายอยู่หลายไฟล์ SSTable แก้ไขโดยใช้อัลกอริทึม **Bloom Filter** (ตัวทดสอบทางสถิติขนาดเล็กในแรม) เพื่อคัดกรองข้ามการเปิดไฟล์ SSTable ที่ไม่มีคีย์นั้นๆ แน่นอน

3. ระบบบันทึก Log ก่อนเขียนจริง (WAL) และกลไกการบดอัดข้อมูล SSTable Compaction

ทฤษฎีและกลไกการทำงาน (How it works): ใน LSM-Tree เพื่อป้องกันความปลอดภัยของข้อมูลสูญหายเมื่อไฟดับระหว่างที่ข้อมูลพักใน Memtable ระบบจะทำการเขียนบันทึกลงไฟล์ **Write-Ahead Log (WAL)** บนดิสก์แบบต่อท้ายทันทีก่อนตอบยืนยันสำเร็จ เมื่อ Memtable เต็มจะถูก Flush ลงดิสก์เป็นไฟล์ **SSTable** (Sorted String Table) ขนาดเล็กๆ ที่แก้ไขไม่ได้ เมื่อไฟล์ SSTable สะสมตัวมากขึ้น ระบบจะทำ **Compaction** (การเคลียร์พื้นที่ดิสก์ย่อย) โดยเปิดอ่าน SSTable หลายๆ ตัวมาทำการผสานและคัดเลือกเฉพาะคีย์รุ่นใหม่ล่าสุดเก็บไว้ แล้วลบไฟล์เก่าทิ้ง

# Configuration parameters for RocksDB SSTable Compaction size thresholds
# Set maximum size of level-1 SSTables to 256MB before compaction triggers
write_buffer_size = 67108864 # 64MB Memtable Size
max_write_buffer_number = 3
target_file_size_base = 268435456 # 256MB
                    

Use Case ในชีวิตจริง (Real-world Scenario): ระบบบันทึกข้อความสนทนาใน Messenger ใช้ระบบ LSM-Tree เมื่อผู้ใช้ส่งข้อความ ข้อมูลจะเข้าสู่ WAL เพื่อความทนทาน และในเบื้องหลังช่วงเวลาเที่ยงคืนที่มีคนใช้งานน้อย ระบบจะรัน Compaction เพื่อยุบรวมไฟล์ SSTable ช่วยไม่ให้ดิสก์เต็มและเร่งความเร็วการดึงประวัติย้อนหลัง

ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations): สภาวะ **Compaction Storm** เกิดขึ้นเมื่อระบบรัน Compaction หนักหน่วงแย่งชิงพลังดิสก์ I/O และ CPU จนแอปพลิเคชันหลักทำงานช้าลงกะทันหัน แก้ไขโดยจำกัดความเร็วการเขียนเขียนของ Compaction (Rate Limiting) หรือเลือกโหมดการบดอัดแบบ Leveled Compaction ที่ควบคุมสัดส่วนได้ดีขึ้น

4. สถาปัตยกรรม Wide-Column Store และกลไกการจัดการคลัสเตอร์ของ Cassandra

ทฤษฎีและกลไกการทำงาน (How it works): **Apache Cassandra** ทำงานบนโครงสร้างแบบคอลัมน์กว้าง (Wide-Column) โดยการกระจายข้อมูลออกเป็นโหนดแบบไร้ศูนย์กลาง (Masterless Architecture) ข้อมูลจะถูกจัดพิกัดลงในวงแหวนเสมือน (Hash Ring) โดยมีพาร์ทิชันคีย์ (Partition Key) แปลงเป็นค่าแฮชเพื่อเลือกว่าข้อมูลจะถูกยิงเก็บไว้ที่โหนดใดเป็นเครื่องหลัก เพื่อรองรับความคงทน ระบบจะจำลองข้อมูลคัดลอก (Replication) ส่งต่อไปยังโหนดข้างเคียงตามค่าที่กำหนด (Replication Factor)

# Cassandra Keyspace creation defining replication strategy across datacenters
CREATE KEYSPACE pipecraft_analytics
WITH replication = {
    'class': 'NetworkTopologyStrategy',
    'datacenter1': 3 -- Keep 3 copies of data in datacenter1
};
                    

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

ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations): ปัญหาข้อมูลสองโหนดขัดแย้งกันเนื่องจากการซิงก์ล่าช้า แก้ไขโดยใช้ระบบการอ่านแบบแก้ข้อมูลด้วยเสียงข้างมาก (Quorum Reads/Writes) เช่น การตั้งเกณฑ์ให้อ่านข้อมูลจาก 2 ใน 3 โหนดพร้อมกันและสแกนคัดเลือกค่าที่มี Time stamp ล่าสุดส่งกลับแอปพลิเคชัน

5. ฐานข้อมูลกราฟและการวิเคราะห์เครือข่ายสัมพันธ์ผ่าน Neo4j

ทฤษฎีและกลไกการทำงาน (How it works): **Graph Database (เช่น Neo4j)** จัดเก็บข้อมูลในรูปของโหนด (Nodes/Entities) และเส้นเชื่อมความสัมพันธ์ (Edges/Relationships) ชนิดพิเศษของมันคือมีกลไก **Index-Free Adjacency** ทุกโหนดจะเก็บลิงก์ชี้พิกัดแรมของโหนดที่เชื่อมโยงอยู่ด้วยตรงตัว ทำให้เมื่อรันคิวรีเชื่อมสัมพันธ์ยาวหลายทอด (Multi-hop Query) ระบบจะกวาดหาโดยชี้แรมต่อกันทันทีโดยไม่ต้องรันคำสั่ง `JOIN` ที่สแกนดัชนี B-Tree ซ้ำๆ เสมือนฐานข้อมูลทั่วไป

// Cypher query template in Neo4j to find potential fraud rings
MATCH (u1:User)-[:SHARED_IP]->(ip:IPAddress)<-[:SHARED_IP]-(u2:User)
MATCH (u1)-[:TRANSFERRED_MONEY]->(u2)
RETURN u1.id, u2.id, ip.address;
                    

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

ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations): การรันคิวรีกราฟแบบไม่จำกัดความลึกสัมพันธ์ (Supernode traversal) เช่น ปล่อยให้ระบบค้นหาความสัมพันธ์กวาดโหนดที่มีการเชื่อมต่อนับสิบล้านเส้น (เช่น ดาราดัง) อาจทำให้หน่วยความจำ RAM พุ่งเต็ม 100% จนเครื่องล่ม แก้ไขโดยจำกัดความลึกสแกน (`*1..3`) หรือจำกัดจำนวนรายการสืบค้นผ่านฟังก์ชัน `LIMIT` เสมอ

🛠️ Weekend Sandbox Challenge: Caching layer with Redis

โจทย์ปฏิบัติการ: จงเขียนโปรแกรม Python เชื่อมต่อดึงข้อมูลจากหน่วยความจำชั่วคราวความเร็วสูง (Redis Cache) โดยกำหนดเงื่อนไขการคืนข้อมูลทันทีหากเจอคีย์ล็อก และเซตเวลากำหนดหมดอายุ (TTL) เพื่อประคองระบบงาน

# local_cache_test.py
import redis
import json

r = redis.Redis(host='localhost', port=6379, db=0)

def get_user_profile(user_id):
    cache_key = f"user:{user_id}"
    cached_data = r.get(cache_key)
    if cached_data:
        return json.loads(cached_data), "CACHE_HIT"
    
    # Simulate DB fetch
    db_profile = {"user_id": user_id, "name": "Somsak"}
    r.setex(cache_key, 60, json.dumps(db_profile)) # TTL set to 60 seconds
    return db_profile, "CACHE_MISS"

print(get_user_profile("1001"))
                    

💼 Senior Technical Interview Q&A

Q1: ตามทฤษฎี CAP Theorem ระบบ NoSQL ชนิดประมวลผลกระจายศูนย์ มักจะเลือกแลกเปลี่ยน Availability (A) และ Partition Tolerance (P) โดยยอมลด Consistency (C) อย่างไร?

A1: เพื่อรองรับความทนทานต่อเน็ตเวิร์กขาดช่วง (P) และยังตอบสนองคำขอผู้ใช้งานได้ตลอดเวลา (A) ระบบจะเลือกใช้การยืนยันสถานะความคงตัวภายหลัง (Eventual Consistency) ข้อมูลที่อัปเดตใหม่จะยังไม่กระจายถึงโหนดอื่นทันที แต่ระบบยังเปิดให้เขียนอ่านได้โดยไม่ต้องรอผลประสานล็อกข้ามโลก

Q2: เปรียบเทียบความคุ้มค่าและความเหมาะสมระหว่างสถาปัตยกรรมเก็บข้อมูลคีย์-ค่าแบบ Redis กับระบบเอกสารแบบ MongoDB?

A2: Redis ทำงานในแรมประมวลผล (In-memory) ความหน่วงต่ำมากระดับไมโครวินาที เหมาะสำหรับใช้ทำแคช เซสชัน หรือค่านับสถิติชั่วคราว ในขณะที่ MongoDB จัดเก็บไฟล์โครงสร้างเอกสารลงฮาร์ดดิสก์หลัก รองรับคำสั่งคิวรีซับซ้อนและการทำดัชนี (Indexing) เหมาะสำหรับเป็นฐานข้อมูลเก็บประวัติหรือข้อมูลเอกสารที่มีขนาดเกินแรมโฮสต์

💾 Interactive NoSQL Document Query Runner

Interactive NoSQL

เป้าหมาย: เขียนคำสั่งค้นหาข้อมูลในรูปแบบ JSON ของ MongoDB เพื่อกรองเอกสาร (Documents) ของผู้ใช้ที่อายุ (age) มากกว่า 25 ปี (ใช้สัญลักษณ์คีย์เวิร์ด $gt)

📋 คอลเลกชันเอกสารดิบ (Collection: `db.users`):
{ "_id": 1, "name": "Alice", "age": 22, "city": "Bangkok" }
{ "_id": 2, "name": "Bob", "age": 30, "city": "Phuket" }
{ "_id": 3, "name": "Charlie", "age": 28, "city": "Chiang Mai" }
📝 ป้อนเงื่อนไขคิวรี JSON (MongoDB Query Syntax):
db.users.find( ... ) BSON Parser Active
db.users.find( )

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

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

  • เก็บข้อมูลได้ยืดหยุ่นสูงมากโดยไม่ต้องดีไซน์หรือปรับโครงสร้าง Schema ล่วงหน้า
  • รองรับปริมาณการเขียนข้อมูลพร้อมๆ กันระดับสูงและขยายตัวแบบแนวนอนได้ดี

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

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

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

Bilingual Guide

แล็บ: คิวรีวิเคราะห์เอกสารข้อมูล JSON ด้วยคีย์เวิร์ดของ NoSQL

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

สำหรับฐานข้อมูล NoSQL แบบ Document ห้ามละเลยการสร้าง Index บนฟิลด์ที่ใช้คิวรีบ่อยเด็ดขาด มิฉะนั้นระบบจะทำการสแกนเอกสารทั้งหมดทุกตัว (Collection Scan) ซึ่งทำงานช้าไม่ต่างจาก SQL full scan