Datacenter และการขยายขนาด
เมื่อเครื่องเดียวไม่พอ เราไม่ได้เพียงนำเครื่องหลายตัวมาตั้งข้างกัน แต่กำลังสร้างคอมพิวเตอร์ชนิดใหม่ที่มีเครือข่ายเป็นทางเดินข้อมูล มี scheduler เป็นผู้จัดสรรงาน และมีความล้มเหลวบางส่วนเป็นเหตุการณ์ปกติ
1The Datacenter is the Computer
ในคอมพิวเตอร์เครื่องเดียว โปรแกรมไม่จำเป็นต้องสั่งมอเตอร์ของดิสก์หรือเลือก transistor ที่ใช้คำนวณ Operating System, compiler และ hardware ช่วยสร้าง abstraction ให้เราใช้งานทรัพยากรซับซ้อนได้โดยไม่ควบคุมทุกชิ้นเอง
เมื่อขยายเป็นศูนย์ข้อมูล เราต้องการ abstraction แบบเดียวกันในระดับที่ใหญ่ขึ้น ผู้ใช้ส่ง job หรือ service เข้าไป แล้วระบบเลือกเครื่อง จัด CPU และ memory วางข้อมูล ตรวจสุขภาพ ย้ายงานเมื่อเครื่องเสีย และรวบรวมผลกลับมา
| หลักการ | รายละเอียด |
|---|---|
| Resource Pooling | รวม CPU, memory, storage และ accelerator จากหลายเครื่องให้ scheduler จัดสรรตามงาน |
| Scale Up และ Scale Out | เลือกเพิ่มความสามารถเครื่องเดิมหรือเพิ่มจำนวนเครื่องตาม workload, cost และข้อจำกัด ไม่มีกฎว่าต้องใช้ทางเดียว |
| Failure-aware Design | ยอมรับว่า process, disk, switch หรือเครื่องบางส่วนล้มได้ แล้วออกแบบ retry, replication และ recovery ไว้ล่วงหน้า |
| Data Locality | พยายามเริ่ม computation ใกล้ข้อมูล หรือทำให้ข้อมูลเล็กลงก่อนส่งผ่านเครือข่าย |
| Batch and Sequential Access | รวมงานและอ่านข้อมูลเป็นก้อน เพื่อใช้ bandwidth คุ้มและลด latency ซ้ำ ๆ |
| Observability | วัด queue, utilization, tail latency, failure และ cost เพราะระบบใหญ่ไม่สามารถวิเคราะห์จากเครื่องเดียวได้ |
Instruction Set ของศูนย์ข้อมูลเป็นภาพเปรียบเทียบ
MapReduce ให้ผู้ใช้เขียน Map กับ Reduce แล้ว framework จัดการ partition, scheduling, Shuffle และ retry จึงเปรียบได้กับ instruction set ระดับศูนย์ข้อมูล แต่ MapReduce ไม่ใช่ตัวอย่างแรกของ distributed abstraction และไม่ใช่คำตอบสุดท้าย สิ่งสำคัญคือมันทำให้แนวคิดนี้แพร่หลายและแสดงให้เห็นว่าการจำกัดรูปแบบโปรแกรมช่วยให้ framework จัดการระบบแทนผู้ใช้ได้มากขึ้น
Spark เพิ่ม DAG และการเก็บผลใน memory Kubernetes จัด placement และ lifecycle ของ container ส่วน serverless ซ่อนการจัดสรร server มากขึ้น แต่ abstraction แต่ละแบบเลือกสิ่งที่จะรับประกันต่างกัน ผู้ใช้ยังต้องรู้ข้อจำกัด เช่น state อยู่ที่ไหน งานทำซ้ำได้หรือไม่ และค่าใช้จ่ายเกิดจากอะไร
ศูนย์ข้อมูลหนึ่งแห่งมีลำดับชั้นภายใน
เครื่องไม่ได้เชื่อมกันด้วยระยะทางเท่ากันทั้งหมด โดยทั่วไปมีระดับตั้งแต่ core และ socket ภายในเครื่อง ไปยังเครื่องใน rack เดียวกัน ข้าม rack และข้ามศูนย์ข้อมูล ต้นทุน latency, bandwidth และ failure domain เพิ่มตามขอบเขต
| ขอบเขต | ทรัพยากรที่แชร์ | ตัวอย่างปัญหา |
|---|---|---|
| Core / Socket | Cache, memory channel และ interconnect ภายในเครื่อง | NUMA, cache contention, memory bandwidth |
| Machine | RAM, local storage, NIC และ OS | Process crash, out-of-memory, disk failure |
| Rack | Top-of-rack switch และพลังงานบางส่วน | Oversubscription, switch failure, rack power loss |
| Datacenter | เครือข่ายและบริการส่วนกลาง | Network partition, cooling หรือ facility incident |
| Region | ระยะทางไกลและข้อกำกับข้อมูล | High latency, egress cost, disaster recovery |
การทำสำเนาสามชุดบนเครื่องสามตัวแต่ทั้งหมดอยู่ rack เดียว ช่วยทนเครื่องเสียแต่ไม่ทน rack เสีย Placement policy จึงต้องรู้ topology และ failure domain ไม่ใช่นับจำนวนสำเนาอย่างเดียว
Abstraction ที่ดีซ่อนรายละเอียด แต่ไม่ซ่อนต้นทุน
ผู้ใช้ Spark สามารถเรียก groupByKey ได้ในบรรทัดเดียว แต่คำสั่งนั้นอาจทำให้ข้อมูลจำนวนมหาศาล Shuffle ข้ามเครื่อง ความง่ายของ API ไม่ได้แปลว่าการทำงานข้างใต้ราคาถูก ผู้เรียนจึงต้องอ่านทั้ง abstraction และ physical behavior
2Seek vs. Scan: ทำไม Random Access ถึงเป็นศัตรูของ Big Data
คำว่า “ศัตรู” ในหัวข้อนี้ตั้งใจให้จำง่าย แต่ไม่ควรตีความว่า random access เป็นสิ่งผิด ฐานข้อมูล OLTP ต้องใช้ point lookup และ random update อยู่เสมอ ประเด็นคือเมื่อเราต้องแตะข้อมูลจำนวนมาก การจ่าย latency สำหรับแต่ละ record แยกกันแพงกว่าการอ่านเป็นก้อนอย่างต่อเนื่องมาก
| วิธีการ | เวลาที่ใช้ |
|---|---|
| Mutate ทีละ record (seek+read+write ~30ms/ครั้ง) | ~35 วัน |
| อ่าน 1 TB และเขียนผลใหม่ 1 TB แบบต่อเนื่องที่ 100 MB/s | ~5.6 ชั่วโมง |
ทำไมการรวมงานชิ้นเล็กจึงช่วย
ทุก request มีต้นทุนตั้งต้น เช่น system call, network round trip, seek, metadata lookup และการตั้งค่าการส่งข้อมูล ถ้าทำงานทีละ record เราจ่ายต้นทุนเหล่านี้ซ้ำ การ batch ช่วยหารต้นทุนตั้งต้นด้วยข้อมูลหลายรายการ
Block Size เป็นการตัดสินใจหลายด้าน
Distributed file system ใช้ block ขนาดใหญ่กว่าระบบไฟล์ทั่วไป เพื่อลด metadata และให้ task หนึ่งทำงานต่อเนื่องนานพอคุ้มค่า scheduling แต่ block ใหญ่เกินไปลดจำนวน task ที่แบ่งได้และทำให้ worker บางตัวรับงานหนักกว่า ส่วน block เล็กเกินไปสร้าง metadata กับ scheduling overhead และไฟล์เล็กจำนวนมาก
ขนาด partition ใน Spark มี trade-off คล้ายกัน Partition เล็กมากทำให้ task overhead สูง Partition ใหญ่มากเสี่ยง memory pressure, spill และ straggler เป้าหมายคือให้แต่ละ task มีงานพอคุ้ม overhead แต่ยังเล็กพอกระจายสมดุลและ retry ได้ไม่แพง
Sequential Access กับ Columnar Access ทำงานร่วมกันได้
การอ่านต่อเนื่องทั้งแถวทุกคอลัมน์ยังสิ้นเปลือง หาก Query ใช้เพียงสองคอลัมน์จากหนึ่งร้อย Columnar format วางค่าชนิดเดียวกันไว้ด้วยกัน จึงอ่านเฉพาะคอลัมน์ที่ใช้ บีบอัดได้ดี และประมวลผลแบบ vectorized ได้
Predicate pushdown ช่วยข้าม row group ที่สถิติบอกว่าไม่มีค่าตรงเงื่อนไข Projection pruning ช่วยตัดคอลัมน์ที่ไม่ใช้ ทั้งสองแนวคิดทำให้ “scan” ไม่จำเป็นต้องแปลว่าอ่านทุก byte
Compression อาจทำให้เร็วขึ้น แม้ต้องใช้ CPU เพิ่ม
ถ้างานติด storage หรือ network bandwidth การบีบอัดลด byte ที่ต้องอ่านและส่ง แม้ต้องใช้ CPU ถอดรหัสเพิ่ม เวลารวมอาจลดลง Columnar data มักบีบอัดได้ดีเพราะค่าชนิดเดียวกันและค่าซ้ำอยู่ใกล้กัน
แต่ compression ที่หนักเกินไปอาจกลายเป็นคอขวด CPU จึงต้องวัดตาม workload และ codec ไม่ใช่ตั้งสมมุติฐานว่าบีบอัดเร็วหรือช้าเสมอ
Small Files Problem
ไฟล์ขนาดเล็กจำนวนมากทำให้ metadata โต เปิดไฟล์ซ้ำ และสร้าง task สั้นจำนวนมาก ต่อให้ขนาดข้อมูลรวมไม่ใหญ่ ระบบอาจช้าจาก overhead การ compact ไฟล์เป็นก้อนและจัด partition ตามรูปแบบ Query จึงช่วยได้มากกว่าการเพิ่ม worker
เมื่อใด Random Access ยังเหมาะสม
ถ้าต้องอ่านหนึ่ง record จากข้อมูลหลายพันล้าน record การสแกนทั้งหมดไม่สมเหตุสมผล Index, key-value store และ cache ช่วยให้ point lookup เร็ว งานบริการมักยอมจ่ายต้นทุนดูแล index เพื่อแลก latency ต่ำ ขณะที่ analytical workload ซึ่งแตะข้อมูลสัดส่วนมากมักเลือก scan
| คำถาม | แนวทางที่มักเหมาะ |
|---|---|
| อ่านหนึ่ง key | Hash index, B-tree, key-value lookup หรือ cache |
| อ่านช่วง key | Ordered index, range partition และ sequential scan ภายในช่วง |
| รวมทั้งคอลัมน์ | Columnar scan, vectorization และ partial aggregation |
| แก้ข้อมูลจำนวนมาก | Batch update, append version ใหม่ หรือ rewrite partition ตามระบบ |
Storage Hierarchy: ใช้ตัวเลขเก่าเพื่อจำลำดับ ไม่ใช่จำสเปก
ตารางต่อไปเป็นตัวเลขเชิงประวัติศาสตร์ที่นิยมใช้อธิบาย “Latency Numbers Every Programmer Should Know” ฮาร์ดแวร์ปัจจุบันเปลี่ยนไปมาก แต่ลำดับความต่างยังให้บทเรียนสำคัญ: cache เร็วกว่าหน่วยความจำ หน่วยความจำเร็วกว่างาน I/O หลายชนิด และการสื่อสารไกลมี latency สูงกว่าการทำงานภายในเครื่อง
| การดำเนินการ | เวลาโดยประมาณในตารางอ้างอิงดั้งเดิม |
|---|---|
| L1 cache reference | 0.5 ns |
| L2 cache reference | 7 ns |
| Main memory reference | 100 ns |
| Compress 1KB ด้วย Zippy | 10,000 ns |
| ส่งข้อมูล 2KB ผ่านเครือข่าย 1 Gbps | 20,000 ns |
| Round trip ภายใน datacenter เดียวกัน | 500,000 ns |
| Disk seek | 10,000,000 ns |
| อ่าน 1MB จากดิสก์แบบ sequential | 30,000,000 ns |
| ส่ง packet ข้ามทวีป (CA→เนเธอร์แลนด์→CA) | 150,000,000 ns |
3Compute-Intensive กับ Data-Intensive: คอขวดอยู่คนละตำแหน่ง
การแบ่งงานเป็น compute-intensive กับ data-intensive ไม่ได้แบ่งว่าระบบใด “ใช้ supercomputer ได้” หรือไม่ได้ แต่ช่วยถามว่าทรัพยากรใดกำหนดเวลารวม งานวิทยาศาสตร์บางชนิดใช้ arithmetic จำนวนมากต่อข้อมูลหนึ่ง byte จึงติด compute ส่วนงานสแกน log อาจคำนวณเพียงไม่กี่ operation ต่อ record แต่ต้องอ่านและส่งข้อมูลมหาศาล จึงติด I/O หรือ memory bandwidth
| ลักษณะงาน | ตัวอย่าง | คอขวดที่เป็นไปได้ |
|---|---|---|
| Compute-intensive | Simulation, matrix computation, model training บางชนิด | CPU/GPU throughput, vectorization, accelerator utilization |
| Memory-intensive | Hash aggregation, graph traversal, in-memory analytics | Memory bandwidth, cache miss, NUMA |
| Storage-intensive | Full-table scan, ETL, sort ข้อมูลใหญ่ | Read/write throughput, small files, spill |
| Network-intensive | Shuffle, distributed Join, replication | NIC, switch oversubscription, serialization |
| Coordination-intensive | งานหลายรอบที่มี barrier หรือ metadata ส่วนกลาง | Tail latency, straggler, coordinator |
HPC กับ Big Data มีประวัติการออกแบบต่างกัน แต่กำลังเข้าใกล้กัน
ระบบ HPC เน้น interconnect ประสิทธิภาพสูง งานคำนวณขนาน และ parallel file system ส่วน Hadoop ยุคแรกเน้น commodity server, local disk, fault tolerance และ data locality การอธิบายว่า supercomputer ใช้กับ data-intensive workload ไม่ได้จึงไม่ถูกต้อง ระบบ HPC รองรับ I/O ขนาดใหญ่ได้ แต่รูปแบบ software และสมมุติฐานเรื่องงานต่างจาก Hadoop
ปัจจุบัน workload ผสมกันมากขึ้น AI training ต้องใช้ทั้ง compute และ network bandwidth งานวิทยาศาสตร์สร้างข้อมูลมหาศาล ส่วน data platform ใช้ accelerator มากขึ้น เส้นแบ่งจึงไม่ชัดเหมือนเดิม สิ่งที่ยังใช้ได้คือการระบุ bottleneck จากอัตราส่วน computation ต่อ data movement
นำ Computation ไปหา Data
ใน HDFS scheduler พยายามวาง Map task แบบ node-local หากทำไม่ได้จึงเลือก rack-local หลักนี้ลด network traffic และกระจายการอ่านไปยัง local storage หลายเครื่องพร้อมกัน บทที่ 4 จะอธิบายว่า NameNode ช่วยบอกตำแหน่ง block และ execution framework เลือก task placement อย่างไร
แต่ Data Locality ไม่ได้มีรูปเดียวตลอดไป
เมื่อ storage แยกจาก compute เช่น object storage บน cloud เราไม่สามารถเริ่ม task บน “เครื่องที่มีดิสก์ก้อนนั้น” แบบ HDFS ได้เสมอไป ระบบจึงใช้วิธีอื่น เช่น cache ข้อมูลใกล้ compute, อ่านเฉพาะ column/row group, push filter ไปยัง storage, เพิ่ม bandwidth ระหว่างชั้น และจัดรูปไฟล์เพื่อลด byte ที่ต้องอ่าน
ดังนั้นหลักที่ลึกกว่า co-location คือ ลด data movement ที่ไม่สร้างคุณค่า บางยุควาง disk กับ compute ไว้เครื่องเดียว บางยุคแยกเพื่อให้ขยายอิสระ แต่พยายามลดการเดินทางด้วย caching และ pushdown
Arithmetic เร็วขึ้นไม่ได้ช่วยเมื่อรอข้อมูล
ถ้า worker ใช้ CPU เพียง 20% และเวลาส่วนใหญ่รอ Shuffle การเพิ่ม CPU เป็นสองเท่าแทบไม่ช่วย หาก worker ใช้ GPU ไม่เต็มเพราะ batch เล็ก การเพิ่ม GPU อาจลด utilization มากกว่าเดิม การวัดต้องดู resource utilization, queue และ throughput ของแต่ละชั้นร่วมกัน
4Horizontal vs. Vertical Scalability
การขยายระบบมีมากกว่าสองปุ่ม แต่ Scale Up กับ Scale Out เป็นจุดเริ่มต้นที่ดี Scale Up เพิ่มทรัพยากรให้หน่วยเดียว Scale Out เพิ่มหน่วยและแบ่งงานระหว่างกัน ระบบจริงมักใช้ทั้งคู่ เช่น เลือกเครื่องที่มี RAM พอเหมาะก่อน แล้วเพิ่มจำนวน worker เมื่อ workload โตต่อ
| รูปแบบ | วิธีการ | ข้อจำกัด |
|---|---|---|
| Vertical Scaling (Scale Up) | เพิ่ม core, RAM, storage หรือ accelerator ในเครื่องเดิม | มีเพดานฮาร์ดแวร์ ราคาอาจเพิ่มเร็วเมื่อเข้าเครื่องระดับสูง และยังมี failure domain ใหญ่จุดเดียว |
| Horizontal Scaling (Scale Out) | เพิ่มเครื่องแล้ว partition หรือ replicate งานออกไป | ต้องจ่าย communication, coordination, skew, partial failure และ operational complexity |
ข้อดีของ Scale Up ที่มักถูกมองข้าม
เครื่องเดียวไม่มี network partition ภายใน process ใช้ shared memory ได้ และ transaction ข้ามข้อมูลหลายส่วนทำได้ง่ายกว่า การ debug, profiling และ deployment มักตรงไปตรงมากว่า หาก workload พอดีเครื่องเดียว การ Scale Up อาจเป็นการออกแบบที่ง่ายและคุ้มที่สุด
ข้อดีของ Scale Out ที่ไม่ได้มีเพียงกำลังรวม
Scale Out ช่วยแบ่ง failure domain เพิ่ม capacity ทีละส่วน และกระจายงานไปใกล้ผู้ใช้หรือข้อมูลได้ แต่ประโยชน์เหล่านี้เกิดเมื่อ software แบ่ง state และงานได้จริง การเพิ่มเครื่องให้โปรแกรมที่มี lock กลางหรือฐานข้อมูลไฟล์เดียวไม่ทำให้ระบบกระจายโดยอัตโนมัติ
Strong Scaling กับ Weak Scaling
Strong scaling คงขนาดงานเดิมแล้วเพิ่มทรัพยากร เพื่อดูว่าเวลาลดลงเท่าใด ส่วน Weak scaling เพิ่มขนาดงานตามจำนวนทรัพยากร เพื่อดูว่าระบบรักษาเวลาไว้ได้หรือไม่ ทั้งสองตอบคนละคำถาม
Scalability ไม่เท่ากับ Speed
ระบบ A อาจเร็วกว่า B ที่ workload ปัจจุบัน แต่พอข้อมูลโต B อาจเพิ่ม throughput ได้ดีกว่า Scalability จึงมองการเปลี่ยนแปลงเมื่อ workload กับทรัพยากรโต ไม่ใช่เวลา ณ จุดเดียว
ควรวัดหลายมิติ:
- Throughput เพิ่มตามทรัพยากรเพียงใด
- Latency เฉลี่ยและ tail latency เปลี่ยนอย่างไร
- Cost ต่อ Query หรือ record ลดลงหรือเพิ่มขึ้น
- Utilization ของ CPU, memory, storage และ network เป็นเท่าใด
- Recovery time โตตามขนาดระบบหรือไม่
Amdahl ยังตามมาถึงศูนย์ข้อมูล
หากงานส่วนหนึ่งต้องผ่าน coordinator หรือทำเรียงลำดับ ต่อให้ส่วนอื่นกระจายได้ การเพิ่ม worker จะให้ผลลดลงเรื่อย ๆ ในระบบข้อมูล serial fraction อาจอยู่ใน metadata, commit, global sort, driver หรือ stage boundary
นอกจากนี้ overhead ของการกระจายไม่ได้คงที่เสมอ จำนวน worker มากขึ้นอาจเพิ่ม communication และ scheduling cost จึงเป็นไปได้ที่เพิ่มเครื่องแล้วงานช้าลง ไม่ใช่เพียงเร็วขึ้นน้อยลง
Stateless Scale ง่ายกว่า Stateful แต่ระบบจริงหลีก state ไม่ได้ทั้งหมด
Service แบบ stateless ส่ง request ไป instance ใดก็ได้ จึงเพิ่มหรือลด instance ง่าย ส่วน stateful service ต้องคิดว่า state อยู่ที่ไหน ทำสำเนาอย่างไร และย้าย partition เมื่อเพิ่มเครื่องอย่างไร
แนวทางทั่วไปคือแยก compute ที่ปรับจำนวนได้ง่ายออกจาก storage ที่รักษา state แต่การแยกนี้เพิ่ม network I/O และอาจลด locality อีกครั้ง ทุก abstraction จึงแลกปัญหาชุดหนึ่งกับอีกชุดหนึ่ง
5ความล้มเหลวในระดับศูนย์ข้อมูล: ยิ่งมีชิ้นส่วนมาก ยิ่งพบเหตุการณ์บ่อย
ถ้าเครื่องหนึ่งมีโอกาสล้มเหลวน้อย การมีเครื่องหลายพันตัวไม่ได้ทำให้แต่ละเครื่องแย่ลง แต่ทำให้โอกาสที่ “มีบางเครื่องกำลังมีปัญหา” สูงขึ้น ระบบจึงต้องทำงานต่อได้เมื่อบางส่วนหาย ช้า หรือสื่อสารกันไม่ได้
Failure Domain
ความล้มเหลวเกิดได้หลายขอบเขต ตั้งแต่ process, disk, machine, rack, datacenter จนถึง region การทำสำเนาควรกระจายข้ามขอบเขตที่ต้องการทน หากสำเนาทั้งหมดใช้ power supply หรือ switch เดียวกัน จำนวนสำเนาอาจดูมากแต่ป้องกันเหตุร่วมไม่ได้
Replication กับ Erasure Coding
Replication เก็บสำเนาเต็มหลายชุด อ่านและกู้คืนง่ายแต่ใช้พื้นที่มาก Erasure coding แยกข้อมูลพร้อม parity ให้กู้คืนจากบางส่วน ใช้พื้นที่คุ้มกว่าแต่การสร้างและซ่อมข้อมูลใช้ computation กับ network มากกว่า ระบบอาจใช้ replication กับข้อมูลร้อน และ erasure coding กับข้อมูลเย็น
Retry, Idempotency และ Duplicate Work
เมื่อ task timeout ระบบไม่รู้เสมอว่ามันยังทำอยู่ เสร็จแล้วแต่คำตอบหาย หรือหยุดจริง การ retry อาจสร้างงานซ้ำ Output commit และ idempotent operation จึงสำคัญ ไม่เช่นนั้น task สองสำเนาอาจเขียนผลซ้ำหรือขัดกัน
Straggler และ Speculative Execution
Stage เสร็จเมื่อ task สุดท้ายเสร็จ Worker ที่ช้าเพียงตัวเดียวจึงลาก tail latency ทั้งงาน Framework อาจเปิด task สำรองบนเครื่องอื่น แต่ถ้าความช้าเกิดจาก data skew ไม่ใช่เครื่องผิดปกติ สำเนาใหม่ก็ยังรับข้อมูลก้อนใหญ่เท่าเดิม การแก้ต้องเริ่มจาก partitioning
Recovery มีต้นทุนและใช้ bandwidth เดียวกับงานปกติ
เมื่อ disk เสีย ระบบต้องอ่านสำเนาและสร้างข้อมูลใหม่ การซ่อมแซมใช้ network กับ storage throughput ซึ่งอาจกระทบ Query ของผู้ใช้ Capacity planning จึงต้องเหลือทรัพยากรสำหรับ recovery ไม่ใช่ออกแบบให้ใช้งานปกติเต็ม 100%
6Scheduling และ Placement: งานควรไปรันที่ไหน
Scheduler ต้องจับคู่ความต้องการของงานกับทรัพยากรที่กระจายอยู่ โดยพิจารณา CPU, memory, GPU, local data, topology, priority และงานอื่นที่กำลังแชร์เครื่อง ปัญหานี้คล้าย bin packing แต่มี dependency กับเวลาและ failure เพิ่มเข้ามา
Data-local, Rack-local และ Off-rack
ถ้ารัน task บนเครื่องที่มี block เรียกว่า data-local หากอยู่คนละเครื่องแต่ rack เดียวกันเป็น rack-local และถ้าข้าม rack ต้องใช้ bandwidth ส่วนกลางมากขึ้น Scheduler อาจยอมรอเครื่อง local ชั่วครู่ แต่ถ้ารอนานเกินไปก็เสีย CPU idle จึงต้องแลก locality กับเวลารอคิว
Resource Fragmentation
คลัสเตอร์อาจมี CPU และ memory รวมเหลือมาก แต่ไม่มีเครื่องใดเหลือทั้งสองอย่างพอสำหรับ task ใหญ่ เช่น บางเครื่องเหลือ CPU แต่ RAM เต็ม อีกเครื่อง RAM เหลือแต่ CPU เต็ม ทรัพยากรจึงแตกเป็นชิ้นที่ใช้ร่วมกันไม่ได้ การกำหนด task size มีผลต่อ utilization
Fairness, Priority และ SLA
ระบบหลายผู้ใช้ต้องตัดสินว่างาน batch ใหญ่ควรใช้คลัสเตอร์ได้แค่ไหนเมื่อมี Query เร่งด่วนเข้ามา Fair scheduling, queue และ preemption ช่วยแบ่งทรัพยากร แต่การหยุดงานอาจทิ้ง intermediate state และเสียงานที่ทำไปแล้ว
Autoscaling มองย้อนหลังเสมอ
Autoscaler เพิ่มเครื่องหลัง metric แสดงว่าโหลดสูง แต่การเปิดเครื่องและ warm cache ใช้เวลา หาก workload พุ่งเร็ว ระบบอาจช้าก่อน capacity ใหม่พร้อม การ scale down เร็วเกินไปก็ทำให้ cache หายและเกิดการย้าย state การปรับอัตโนมัติจึงต้องเข้าใจ delay กับ hysteresis
7ต้นทุน พลังงาน และการใช้ทรัพยากรให้คุ้ม
ระบบที่เร็วที่สุดอาจไม่ใช่ระบบที่คุ้มที่สุด การเพิ่มเครื่องลดเวลาได้แต่เพิ่มค่า compute, storage, network และการดูแล การวัดควรรวม cost ต่อผลลัพธ์ ไม่ใช่ดูเวลาจบอย่างเดียว
ต้นทุนที่มองเห็นกับต้นทุนที่ซ่อนอยู่
| ต้นทุน | ตัวอย่าง |
|---|---|
| Compute | CPU/GPU hour, memory reservation และเวลาที่เครื่องว่างแต่ยังจ่าย |
| Storage | ข้อมูลดิบ สำเนา checkpoint intermediate result และ version เก่า |
| Network | Shuffle, replication, cross-zone และการนำข้อมูลออกจากผู้ให้บริการ |
| Operations | Monitoring, upgrade, incident response, security และเวลาของทีม |
| Opportunity | ผลวิเคราะห์ช้าเกินใช้ หรือระบบซับซ้อนจนเปลี่ยนแปลงได้ช้า |
Performance per Watt และ Carbon Awareness
ศูนย์ข้อมูลใช้พลังงานทั้งกับ computation และ cooling งานที่อ่านข้อมูลซ้ำหรือใช้ GPU ไม่เต็มยังใช้พลังงานโดยไม่สร้างผลลัพธ์ การปรับ file layout, cache และ batch size จึงลดทั้งเวลา ค่าใช้จ่าย และพลังงานได้พร้อมกัน
งาน batch ที่ไม่เร่งด่วนอาจเลื่อนไปช่วงที่พลังงานสะอาดหรือ capacity ว่างมากกว่าได้ แต่ต้องรักษา deadline และข้อกำกับตำแหน่งข้อมูล การวางงานจึงเริ่มรวมมิติด้านพลังงานเข้ากับ performance
Utilization สูงไม่ใช่เป้าหมายเดียว
การใช้เครื่องใกล้ 100% ทำให้ cost ต่อทรัพยากรดูดี แต่ queue และ tail latency อาจเพิ่มมากเมื่อไม่มี headroom ระบบออนไลน์จึงต้องเหลือพื้นที่รับ burst และ failure ส่วน batch cluster อาจเน้น utilization สูงกว่าได้
8เมื่อยุคเปลี่ยน: จุดตัดระหว่างเครื่องเดียวกับคลัสเตอร์ขยับอยู่เสมอ
คำถามตัดสินใจ: เครื่องเดียว คลัสเตอร์ หรือบริการที่แยก Storage/Compute
| คำถาม | ถ้าคำตอบเป็นเช่นนี้ | แนวทางที่ควรพิจารณา |
|---|---|---|
| Working set พอดีเครื่องเดียวหรือไม่ | พอดีและ Query ไม่ชนกันมาก | เริ่มจากเครื่องเดียวเพื่อความง่าย แล้ววัดก่อนกระจาย |
| ต้องเพิ่ม capacity ทีละน้อยหรือไม่ | ข้อมูลและผู้ใช้โตต่อเนื่องเกินเพดานเครื่อง | Scale Out พร้อมออกแบบ partition และ failure handling |
| Compute กับ storage โตพร้อมกันหรือไม่ | โตคนละจังหวะและ workload เปลี่ยนตามเวลา | แยก storage/compute เพื่อปรับจำนวนอิสระ แต่ประเมิน network cost |
| ต้องตอบหลายผู้ใช้พร้อมกันหรือไม่ | Concurrency สูงและมี SLA | แยก workload, queue, admission control และ capacity สำหรับ tail |
| ข้อมูลย้ายข้ามพื้นที่ได้หรือไม่ | ติดข้อกำกับหรือ egress cost | วาง computation ในพื้นที่เดียวกับข้อมูลและลดการเคลื่อนย้าย |
9จะรู้ได้อย่างไรว่าระบบติดตรงไหน: วัดทั้งเส้นทาง ไม่ใช่ดูเครื่องเดียว
ในเครื่องเดียว เราอาจเปิด Task Manager หรือ profiler แล้วเห็นภาพส่วนใหญ่ แต่ในศูนย์ข้อมูลหนึ่ง Query ผ่านหลาย service, worker, switch และ storage การดู CPU เฉลี่ยของคลัสเตอร์จึงอาจซ่อนเครื่องที่ร้อนจัดหรือ task ที่ช้าผิดปกติไว้
Metrics, Logs และ Traces ตอบคนละคำถาม
| ข้อมูลสังเกตการณ์ | ตอบคำถาม | ตัวอย่าง |
|---|---|---|
| Metrics | ระบบมีแนวโน้มอย่างไร และค่าใดเกินขอบเขต | CPU, memory, queue length, throughput, p99 latency |
| Logs | เหตุการณ์เฉพาะเกิดอะไรขึ้น พร้อมรายละเอียดบริบท | Task failed, out-of-memory, retry, permission denied |
| Traces | Request หนึ่งเดินผ่านส่วนใดและใช้เวลาตรงไหน | อ่าน metadata → scan → Shuffle → aggregate → response |
| Profiles | ภายใน process ใช้ CPU หรือ memory กับ function ใด | Serialization, hashing, compression, garbage collection |
Metric ชี้ว่าปัญหาเกิดเมื่อใด Trace ชี้เส้นทางที่ช้า Log ให้รายละเอียดเหตุการณ์ และ profile ชี้ function ภายใน ไม่มีชนิดใดแทนอีกชนิดได้ทั้งหมด
ค่าเฉลี่ยซ่อน Tail
ถ้า task 99 ตัวเสร็จในหนึ่งวินาที แต่อีกตัวใช้หนึ่งนาที ค่าเฉลี่ยอาจยังดูไม่ร้าย แต่ stage ต้องรอหนึ่งนาที Percentile เช่น p95, p99 และค่าสูงสุดช่วยเห็นหางของ distribution ซึ่งมีผลโดยตรงต่อ distributed job
Utilization ต่ำไม่ได้แปลว่าไม่มีคอขวด
CPU เฉลี่ย 30% อาจเกิดจากทุกเครื่องว่าง หรือเกิดจากครึ่งหนึ่งเต็ม 100% แต่อีกครึ่งไม่มีข้อมูลทำ ข้อมูลเฉลี่ยระดับคลัสเตอร์จึงต้องดูคู่กับ distribution ต่อ worker และ partition
อีกกรณีคือ CPU ต่ำเพราะกำลังรอ storage หรือ network หากเพิ่ม CPU ระบบไม่เร็วขึ้น ควรดู I/O wait, throughput, queue และเวลาที่ task อยู่แต่ละสถานะ
Skew มองเห็นได้จากขนาด Partition และเวลาของ Task
หาก task ส่วนใหญ่ประมวลผล 100 MB แต่บางตัวรับ 20 GB ปัญหาอยู่ที่การแบ่งข้อมูล ไม่ใช่ประสิทธิภาพเครื่อง การเพิ่ม worker ไม่สามารถแบ่ง partition ที่สร้างไปแล้วโดยอัตโนมัติเสมอ ต้องแก้ key, salting, repartition หรือใช้ adaptive execution ตามความสามารถของ engine
Queue บอกความสัมพันธ์ระหว่าง Arrival Rate กับ Service Rate
ถ้างานเข้ามาเร็วกว่าระบบทำเสร็จ Queue จะโตต่อเนื่อง แม้แต่ละ request ยังตอบได้ ระบบกำลังสะสมหนี้เวลา การเพิ่ม capacity, ลดงานต่อ request หรือทำ backpressure ต้องเกิดก่อน queue ใช้ memory หมดหรือ latency เกิน SLA
วัดก่อนและหลังด้วย Workload เดียวกัน
การเปรียบเทียบต้องควบคุมขนาดข้อมูล รูปแบบ Query, cache state, concurrency และ failure condition หากรอบใหม่เร็วขึ้นเพราะข้อมูลอยู่ใน cache แต่รอบเก่าเป็น cold start เราไม่ควรสรุปว่า architecture ใหม่เร็วกว่าโดยไม่แยกสาเหตุ
10สรุปบทและขั้นตอนถัดไป
การมองศูนย์ข้อมูลเป็นคอมพิวเตอร์หนึ่งเครื่องช่วยให้เราออกแบบ abstraction ที่จัดการทรัพยากรจำนวนมากได้ แต่ “หนึ่งเครื่อง” ในที่นี้มีลักษณะพิเศษ:
- หน่วยความจำไม่ได้เป็น address space เดียว
- การสื่อสารมี latency และ bandwidth จำกัด
- เครื่องและเครือข่ายบางส่วนล้มแยกจากส่วนอื่นได้
- ข้อมูลมีตำแหน่ง และตำแหน่งนั้นเปลี่ยนต้นทุนการคำนวณ
- ผู้ใช้หลายงานแข่งขันกันใช้ทรัพยากร
- การเพิ่มเครื่องเพิ่มทั้งกำลังและ overhead
แนวคิดสำคัญของบทนี้จึงไม่ใช่ “Scale Out ดีกว่า Scale Up” แต่คือเลือกขอบเขตที่เหมาะกับ workload เครื่องเดียวให้ความง่ายและ shared memory คลัสเตอร์ให้ capacity กับ failure isolation ส่วนการแยก storage ออกจาก compute ให้ความยืดหยุ่นแต่เพิ่ม data movement
ก่อนออกแบบระบบ ควรตอบให้ได้ว่า:
- งานติด compute, memory, storage, network หรือ coordination
- ข้อมูลอยู่ตรงไหน และลด byte ก่อนส่งได้หรือไม่
- partition กระจายงานสมดุลหรือมี hotspot
- ต้องทน failure ขอบเขตใด และ recovery ใช้ทรัพยากรเท่าใด
- เพิ่มเครื่องแล้ว throughput, latency และ cost เปลี่ยนอย่างไร
เลือกงานวิเคราะห์หนึ่งงานแล้ววาดสามตำแหน่ง: ข้อมูลอยู่ที่ไหน computation เริ่มที่ไหน และผลย่อยถูกรวมตรงไหน จากนั้นวงเส้นทางที่ข้อมูลต้องข้ามเครื่อง แผนภาพนี้จะช่วยให้บท HDFS และ MapReduce ไม่กลายเป็นการจำชื่อ component แต่เป็นคำตอบต่อปัญหา placement กับ data movement ที่เห็นอยู่แล้ว
- อธิบายแนวคิด “The Datacenter is the Computer” พร้อมระบุสิ่งที่ abstraction ซ่อนได้และสิ่งที่ผู้พัฒนายังต้องรับผิดชอบ
- จากตัวอย่างฐานข้อมูล 1 TB อธิบายสมมุติฐานของเวลาประมาณ 35 วันกับ 5.6 ชั่วโมง และเหตุใดจึงไม่ควรนำตัวเลขไปใช้เป็น benchmark ปัจจุบันตรง ๆ
- เปรียบเทียบ latency กับ bandwidth และอธิบายว่า batch size แลก throughput กับเวลารออย่างไร
- อธิบายความต่างระหว่าง compute-, memory-, storage-, network- และ coordination-intensive workload
- เปรียบเทียบ Scale Up กับ Scale Out โดยยกข้อดีที่อีกฝ่ายไม่มีอย่างน้อยด้านละสองข้อ
- อธิบาย Strong Scaling กับ Weak Scaling พร้อมออกแบบการทดลองอย่างละหนึ่งแบบ
- อธิบายเหตุผลที่ replica สามชุดใน rack เดียวไม่ได้ป้องกัน rack failure
- วิเคราะห์ว่าเหตุใดการแยก storage ออกจาก compute ลด locality แต่ยังได้รับความนิยมในบางสถาปัตยกรรม
- เลือก workload หนึ่งงานแล้วเสนอ metric ด้าน performance, reliability และ cost ที่ควรวัดร่วมกัน