System design 1/3

Phai Panda
6 min readMar 8, 2024

--

การออกแบบระบบหรือ System design มีโอกาสได้ศึกษาเรื่องนี้บ้างจากที่ทำงาน จึงคิดว่าได้รับแล้วก็ควรจะแบ่งปันเพื่อนๆด้วย

หากจะพูดถึงการออกแบบระบบ ในหัวผมจะคิดถึง flow (ลูกศรบอกทิศทางการใช้ข้อมูล) กับพวกรูปภาพที่บอกถึงเทคโนโลยีที่ใช้ แน่นอนว่าต้องมีกรอบสี่เหลี่ยมน้อยใหญ่ครอบกันไปมา เหล่านี้ขอเรียกรวมๆว่า Architecture ซึ่งในทางปฏิบัติเราไม่อาจเข้าใจ architecture ด้วยตนเองได้ทั้งหมด ต้องอาศัยผู้ออกแบบหรือผู้อยู่ก่อนกาล (อยู่มาก่อน) คอยช่วยอธิบายเรื่องนี้ให้ฟังอีกที

ทว่าบทความนี้จะพูดถึงเทคโนโลยีที่เกี่ยวข้องกับการออกแบบระบบเป็นหลักครับ

System design คือกระบวนการการออกแบบระบบ (architecture)

  • ระบบที่ว่านี้อย่างน้อยต้องสามารถบอกได้ว่ามี ข้อดี/ข้อเสีย อะไรบ้าง
  • ระบบคุยกัน ภายใน/ภายนอก อย่างไร
  • เก็บข้อมูลรูปแบบไหน
  • เหมาะสมแล้วกับ business ที่จะทำ (ตาม requirement) โดยอาศัยประสบการณ์ร่วมกับพฤติกรรมของข้อมูลที่เคยพบเจอ (มิเช่นนั้นมีโอกาสที่จะต้อง Rearchitecture)

กระบวนการการออกแบบระบบ ต้องดูว่าตอบความต้องการของ business ด้านอะไรบ้าง เช่น

  • Performance
  • Scalability
  • Security
  • User experience
  • Reliability

Performance

ในที่นี้หมายถึงตัวเลขที่เกิดจาการวัดค่าด้วยวิธีการที่ทีมยอมรับ เช่น จำนวนโหลดต่อวินาที ใช้พื้นที่เก็บข้อมูลลดลงในขณะที่ปริมาณข้อมูลเท่าเดิม โดยดูจากลักษณะของ business กับขนาดของ project เป็นหลัก, performance ที่ดีอาจมีต้นทุนในการพัฒนาและค่าการจัดเก็บข้อมูล (รายเดือน) ที่สูงตามไปด้วย

Scalability

คือการรองรับระบบที่อาจขยายตัวในอนาคต กล่าวคือระบบยังคงสามารถทำงานได้ปกติเมื่อปริมาณการใช้งาานสูงขึ้น

Security

ออกแบบระบบให้มีความปลอดภัยจากภัยคุกคาม (Threat) เพราะแต่ละระบบก็มีความต้องการด้านนี้ต่างกัน เช่น ธนาคารต้องการความปลอดภัยสูงเพราะมีผลต่อความน่าเชื่อถือ ในขณะที่ application อื่นที่ใช้ภายในองค์กรอาจต้องการความปลอดภัยที่น้อยกว่า ทั้งนี้ก็ขึ้นอยู่กับ requirement

User experience

สำคัญต่อระบบทำให้ business ทำงานได้อย่างมีประสิทธิภาพ สมมติถ้าใช้ message queue จำพวก Kafka ก็จะได้ asynchronous message ซึ่งต้องดูว่า requirement หรือ business ณ เวลานั้นยอมรับ user experience นี้หรือไม่ ถ้าบอกว่าโอนเงินแล้วต้องเห็นยอดเงินทันที อย่างนี้ก็ต้องหันไปหา synchronous แทน

Reliability

จึงเป็นการพูดว่าสิ่งที่จะทำนั้นไม่ว่าจะเป็น scalabitily, security และ user experience สามารถทำได้อย่างสม่ำเสมอหรือไม่ ตลอดทั้งวันและคืนที่ผ่านไปนั้นระบบจะล่มหรือไม่ (crash) มีความน่าเชื่อถือเพียงใด

ทีนี้จึงให้รายละเอียดกับ requirement คิดเพิ่มระหว่าง functional requirements กับ non functional requirements

Functional requirements vs Non functional requirements

สิ่งที่ business user ต้องการจะมาในรูป functional requirements มักเป็นสิ่งที่มองเห็นได้ เช่น เว็บไซต์ต้องมีหน้า Home, หน้า Profile สามารถแก้ไขชื่อเองได้ สามารถใช้งานเว็บไซต์ได้ตลอดเวลา

พอเป็น non functional requirements ก็คือสิ่งที่ business user ไม่ได้บอก เช่น หน้า Home ควรจะแสดงในระยะเวลาไม่เกิน 1.5 วินาที มากกว่านี้ถือว่าช้าเกินไป, หน้า Profile จะต้องมีการ encrypted ข้อมูลสำคัญโดยถือเอา user ref ID เป็นตัวอ้างอิงข้อมูลในฐานข้อมูล, เว็บไซต์รองรับการเข้าใช้งานพร้อมกันได้ไม่เกิน 1 พันคน เป็นต้น

System Architecture Layers

พื้นฐานมี 3 layers ได้แก่

  • Presentation layer ส่วนที่เป็น client เช่น web UI, mobile UI
  • Application layer ส่วนที่เป็น business logic เขียนโปรแกรมขึ้นมา
  • Data Storage layer ส่วนเก็บข้อมูล เช่น ฐานข้อมูล

Client — Server — Database

ขออธิบายในแง่ของการให้บริการเว็บไซต์

  • เดิม software ที่ใช้งานกับ client เท่านั้นเรียกว่า standalon ใช้วิธีการติดตั้งด้วยการ install
  • ต่อมาเมื่อ internet มีการใช้งานแพร่หลาย มี web server เกิดขึ้น ก็เกิดการคุยกันระหว่าง client กับ server ผ่าน web browser เราจะเรียก server ว่าผู้ให้บริการเว็บไซต์
  • และเมื่อต้องการจัดเก็บข้อมูล server ก็จะเป็นฝั่งในการติดต่อกับ database ให้ มองได้ว่า browser ก็คือ client มี web UI หรือสิ่งที่มองเห็นได้เป็น interface และโทรศัพท์มือถือก็คือ client ที่มี mobile UI เป็น interface ขอใช้บริการข้อมูลกับ server ที่มีโปรแกรมหรือ application server คอยให้บริการจัดการข้อมูล (ด้วย business logic) จัดเก็บข้อมูลไว้ใน database ให้อัตโนมัติ
client — server — database
  • วันหนึ่งพบว่า server เพียงหนึ่งเดียวทำงานหนัก (ตอบสนองการใช้งานช้าลง — ไม่เป็นไปตาม non functional requirement) จึงได้เพิ่ม server ขึ้นอีกและเพื่อให้มันทำงานได้เหมือนเดิมก็ต้องอาศัยสิ่งที่เรียกว่า Load Balance ตามตัวอย่างของเราก็คือ load balance web server
add load balance

load balance จะทำหน้าที่แบ่ง request ส่งให้กับ server1, server2 อัตโนมัติ

  • การเพิ่มจำนวน server เพื่อตอบสนองการใช้งานอาจดูเป็น physical หรือเครื่อง server จริงๆ ทว่าปัจจุบันก็มีให้ผู้บริการ Cloud ให้บริการเช่าทรัพยากรของเครื่อง server โดยที่ผู้ออกแบบระบบสามารถกำหนดความต้องการการใช้งาน CPU, memory, storage ตลอดจนฐานข้อมูลต่างๆ ตัวเลือกนี้จึงทำให้องค์กรไม่จำเป็นต้องมีเครื่อง server จริงๆอีกต่อไป ทั้งยังตอบความสามารถ scalability อีกด้วย

Top 6 Load Balancing Algorithms

เพราะผู้ออกแบบระบบได้เป้าหมายที่จะสร้าง application ที่ปรับขนาดได้และมีประสิทธิภาพ ดังนั้นเพื่อ response ที่ดีมาดูว่า algorithm ยอดนิยมของ load balance มีอะไรบ้าง (อ้างอิง Top Load Balancing Algorithms) แน่นอนว่าเราต้องรู้ข้อดีข้อเสียของมันทั้งหมด! — ไม่งั้นจะหาข้อเปรียบเทียบเพื่อออกแบบระบบได้ไงล่ะ

  1. Round Robin จะแจก request เหมือนแจกไพ่, ข้อดี เหมาะกับ stateless applications, ข้อเสีย หากไม่ตรวจสอบให้ดีจะทำให้บาง server เกิดการ overload ได้
  2. Sticky Round Robin เหมือนกับ round robin แต่สามารถกำหนดให้ client รายเดียวกันไปยัง server เดียวกัน, ข้อดี ข้อมูลของ client รายนั้นเมื่อถูกจัดเก็บไว้ใน cache การคุยกับ server เครื่องเดิมจึงได้ประสิทธิภาพดีกว่า เช่น stateful applications, ข้อเสีย มีความเสี่ยงการกระจายโหลดที่ไม่สม่ำเสมอ
  3. Weighted Round Robin เหมือนกับ round robin แต่มีการให้น้ำหนัก (weight) กับ server ตามความสามารถ, server ที่มีค่าน้ำหนักมากจะได้รับ request ที่มากกว่า, ข้อเสีย ปรับเปลี่ยนค่าน้ำหนักแบบ real time ไม่ได้
  4. Hash-Based ใช้ฟังก์ชันแฮชกับ IP หรือ URL เพื่อกำหนดให้ request ไปยัง server นั้นๆ, ข้อดี ได้ศักยภาพการกระจาย request สม่ำเสมอ, ข้อเสีย มีความยากที่ต้องเลือกฟังก์ชันแฮชที่เหมาะสม
  5. Least Connections ส่ง request ไปยัง server ที่มี connection น้อยที่สุด, ข้อดี เกิดการกระจายการโหลด
  6. Least Response Time ส่ง request ไปยัง server ที่มีค่า response time น้อยที่สุด

High Availability & Disaster Recovery

high availability คือระบบมีความพร้อมใช้งานสูง ในขณะที่ disaster recovery คือกระบวนการทำให้ระบบกลับสู่สภาพปกติหากว่าระบบมีปัญหาไม่สามารถทำงานได้

สมมติให้ server1 และ server2 ตั้งอยู่ที่อาคารเดอะปาร์คพระรามสี่ วันหนึ่งเกิดไฟดับหรือมีปัญหาเป็นเหตุให้ใช้งานไม่ได้ก็เท่ากับว่า application เราใช้งานไม่ได้ด้วย แต่ถ้าย้าย server2 ไปอยู่ชลบุรี อย่างนี้ load balance ยังสามารถแจก request ไปยัง server2 ได้

ก็มีศัพท์ที่เรียกการตั้งอยู่ของ server1 ว่า Data Center (DC) Site เพื่อเก็บข้อมูลทุกสิ่งอย่าง เรียกการตั้งอยู่ของ server2 ว่า Disaster Recovery (DR) Site เพื่อสำรองข้อมูลที่สำคัญจาก DC และทั้งสองไซต์นี้ควรห่างกันอย่างน้อย 160 กิโลเมตร

สมมติอีก สมมติว่าทั้งไซต์ DC และไซต์ DR ใช้ฐานข้อมูลที่เดียวกัน กลับกลายเป็นว่าสิ่งที่ล่ม (ล้มเหลว) คือฐานข้อมูล หากเป็นอย่างนี้จะออกแบบอย่างไร? ให้แต่ละไซต์เชื่อมฐานข้อมูลจากคนละแหล่งได้หรือไม่ ถ้าได้สิ่งที่จะต้องทำต่อไปคืออะไร? คำตอบคือ Database Replication

Database Replication

ทำให้เรามีฐานข้อมูลหลายตัวได้ การทำ replication เป็นการสำเนาข้อมูลไปยังฐานข้อมูลสำรอง (เกิดสิ่งที่เรียกว่า redundant หรือข้อมูลซ้ำ) เพื่อรับประกันว่า หากฐานข้อมูลหลักล่มไปหรือเกิดข้อมูลพลาด ระบบยังมีฐานข้อมูลสำรองไว้ทำหน้าที่แทน (อ้างอิง MongoDB: Replication)

เรียกฐานข้อมูลสำรองว่า Replica Database เรียกฐานข้อมูลหลักว่า Master Database และสำเนาข้อมูลระหว่างกันด้วยสิ่งที่เรียกว่า Streaming Replication

อ้างอิง Standard Streaming Replication

เมื่อใดก็ตามที่ฐานข้อมูลหลักล่มไปหรือเกิดปัญหา application server ก็สามารถชี้ไปยัง replica database แทนได้

หรือถ้าเกิดว่าเราใช้บริการของ Google Cloud Platform (GCP) ซึ่งต้องเลือกภูมิภาค (region) ที่จะใช้งานฐานข้อมูล สมมติเลือกเป็นภูมิภาค A และ B ก็สามารถทำ replication ระหว่างภูมิภาคได้

GCP Region A and B Replication

จากในภาพเมื่อฝั่งภูมิภาค A มีปัญหาก็สามารถ switch ไปใช้ภูมิภาค B แทนได้ แต่ละภูมิภาคยังมี read replica database ได้มากกว่า 1 ตัวเพื่อช่วยเรื่อง performance

Monolithic VS Microservices Architecture

ง่ายๆว่า Monolitic คือก้อนใหญ่ (รวมทุกฟังก์ชัน) ของหนึ่ง application (Single Instance) ส่วน Microservices แยกออกเป็นหลายก้อน (ฟังก์ชัน) เล็กๆทำงานร่วมกันเป็นหนึ่ง application (Multiple Instances)

1 instance นี้หมายถึง 1 operation system (OS) ประกอบด้วยจำนวน CPU core, RAM และ storage

Monolitic Architecture
Microservices Architecture

ภาพโครงสร้างระบบข้างต้นนี้เป็นเพียงตัวอย่างง่ายๆที่แสดงให้เห็นความแตกต่างระหว่างการออกแบบ 1 deploy ของ monolitic กับแบบเลือก deploy ตาม feature/fix ได้ของ microserivces

ข้อดี/ข้อเสีย

  • monolitic นั้น deploy ง่าย ส่วน microserivces ต้องแยก deploy ตาม feature/fix
  • monolitic ใช้แค่ repository เดียว (Git) หาโค้ดง่าย ทุกอย่างรวมอยู่ที่เดียว ต่างจาก microserivces ที่ใช้หลาย repository ต้องมองภาพรวม
  • monolitic เพียงตัวเดียวมี performance ดีกว่า จบคุยกันภายใน ต่างจาก microserivces ที่ต้องคุยกันผ่าน interface ต่างๆ เช่น RESTful, SOAP, RPC เป็นต้น
  • monolitic เทส, debug ง่ายเพราะรันอยู่บน instance เดียว
  • monolitic สำหรับโปรแกรมที่มีความซับซ้อนมากบริหารจัดการโค้ดยาก เกิด code conflict ได้ง่าย เสียเวลาไล่โค้ด
  • monolitic ด้าน scalability แย่กว่า microserivces เพราะต้องทำทั้ง instance ทำให้ใช้ทรัพยากรเกือบสองเท่าทุกครั้งไป
  • monolitic โค้ดดูแลรักษายาก เช่น อยากเปลี่ยนจาก Java เป็น Go ก็ต้องทำทั้งโปรเจกต์ หรือถ้าใช้ Java ก็ต้องหานักพัฒนา Java มาดูแลเท่านั้น ต่างจาก microserivces ที่เขียนแต่ละ service แยกภาษาได้เลย
  • microserivces เริ่มต้นได้เร็วกว่า เพราะเริ่มจากชิ้นเล็กๆ deploy ได้เร็ว
  • microserivces เปลี่ยนแปลง tech stack ได้ง่ายกว่า
  • microserivces จะต้องออกแบบระบบให้ดี โดยเฉพาะการคุยกันของ service ต่างๆไม่ว่าจะทีมเดียวกันหรือต่างทีม (การเพิ่ม organize layers ก็จะเสียเวลาคุยเพิ่มขึ้น)
  • ระบบ Log นั้น monolitic จัดการง่ายกว่า
  • กรณีที่ต้องการคุณภาพของโค้ด (code quality) microserivces ดูแลได้ยากกว่า monolitic เพราะอาจหาเจ้าภาพของทุก service ไม่ได้ (ไม่มีคนเฆี่ยนตี)

Centralized VS Decentralized Databases

ไม่ว่าจะเป็น monolitic หรือ microserivces ก็ขึ้นอยู่กับ requirement และพฤติกรรมการใช้ข้อมูลของ business เป็นหลักจึงค่อยพิจารณาว่าแต่ละ service ควรใช้ฐานข้อมูลเดียว (centralized) หรือแยกกันไปเลย (decentralized)

ข้อดี/ข้อเสีย

  • centralized ดูแลรักษาง่ายกว่า เชื่อถือได้ในเรื่องความถูกต้องของข้อมูล
  • centralized กับข้อมูลจำนวนมหาศาลจะกิน cost มากตามไปด้วย
  • centralized กับข้อมูลจำนวนมหาศาลจะเกิดปัญหาการใช้ข้อมูลร่วมกัน การลบหรือเพิ่มจะกระทบกับทุก service ที่เรียกใช้
  • decentralized กับ microserivces ที่มี data model ต่างกันทำให้ดูแลโครงสร้างข้อมูลยากทั้งๆที่เป็นข้อมูลเดียวกัน
  • decentralized เลือกใช้ฐานข้อมูลต่างประเภทกันได้ เหมาะสมกับพฤติกรรมการใช้ข้อมูล
  • decentralized ทำให้เกิด consistency ได้ง่าย ไม่สอดคล้องกัน

CAP Theorem

คือสิ่งที่ต้องคํานึงเพื่อออกแบบ microserivces ประกอบด้วย

อ้างอิง CAP Theorem
  • Consistency: client ทั้งหมดต้องเห็นข้อมูลเดียวกันในเวลาเดียวกัน ข้อมูลที่ถูกเขียนไปยัง node ใดๆจะต้องส่งต่อหรือ sync ไปยัง node อื่นๆทั้งหมดในระบบจึงจะถือว่าการเขียนนั้น “สำเร็จ”
  • Availability: client จะยังคงสามารถเข้าถึงข้อมูลได้แม้ว่าบาง node ของระบบล้มเหลว
  • Partitioning: ระบบจะยังทำงานได้ตามที่คาดหวังแม้ว่าเครือข่ายจะล้มเหลวบางส่วนก็ตาม

ตัวอย่าง

ระบบคลังสินค้าอีคอมเมิร์ซ (E-commerce stock) ที่ควรให้สมดุลระหว่าง consistency กับ availability

  • ในภาวะปกติเพราะเป็นการซื้อขายสินค้าหรือบริการด้วยอินเทอร์เน็ต ลูกค้าจึงสามารถทำรายการได้พร้อมกัน เห็นข้อมูลเดียวกันในเวลาเดียวกันแบบทันทีทันใด
  • ร้านค้าก็จะเห็นการทำรายการเหล่านั้นในเวลาเดียวกันแบบทันทีทันใด
  • แต่ถ้าเกิดระบบมีปัญหา ระบบที่มีแค่ consistency ก็จะให้บริการไม่ได้ ต้องปิดระบบไปก่อน (out of service)
  • เราจึงควรออกแบบให้ระบบมี availability ด้วย เพื่อให้ระบบยังคงให้บริการต่อไปได้ เช่น ลูกค้ายังสามารถดูสินค้าหน้าร้านแต่ทำรายการสั่งซื้อไม่ได้ บางรายการสั่งซื้ออาจต้องดำเนินการภายหลัง อาจเกิดการสั่งซื้อซ้ำหรือสั่งซื่อสินค้าที่ไม่มีเหลืออยู่ในคลังสินค้าของร้านแล้ว (เนื่องจากตัด stock ไม่ได้)
  • ดังนั้นระบบที่มี availability จำต้องมีวิธีดำเนินการในกรณีที่ระบบมีปัญหานั่นเอง

Database Types and Netflix use cases

ลองไปส่องดูฐานข้อมูลประเภทต่างๆของ Netflix กัน

อ้างอิง Netflix Tech Stack Database

จะเห็นได้ว่าระบบนี้ไม่ได้ใช้ฐานข้อมูลเพียงประเภทเดียว มีทั้ง Relational, Columnar, Key-Value, Wide-Column, Time Series และ Text Search ซึ่งแต่ละประเภทก็มีหลายยี่ห้อโดดเด่นแตกต่างกันไป

แน่นอนว่าผู้ออกแบบระบบก็ต้องทราบรายละเอียดเหล่านี้พอสมควรจึงจะสามารถเลือกที่เหมาะสมกับ requirement ได้

  • Relational Database: จากภาพ Netflix เลือก MySQL สำหรับธุรกรรมการเรียกเก็บเงิน (billing transactions), การสมัครสมาชิก (subscriptions), ภาษี (taxes) และรายได้ (revenue) พวกเขายังเลือกใช้ CockroachDB เพื่อรองรับสถาปัตยกรรมที่ใช้งานอยู่หลายภูมิภาค (multi-region)
  • Columnar Database: Netflix ใช้สำหรับวัตถุประสงค์ในการวิเคราะห์เป็นหลัก (หัวใจคือความเร็ว) ข้อมูลที่ถูกจัดเก็บไว้ใน structured data storage นั้นพวกเขาเลือก Redshift และ Druid
  • Key-Value Database: เลือกยี่ห้อ EVCache (ฐานคือ Memcached) แทนที่จะเป็น Redis (อ้างอิง Memcached vs Redis) ใช้กับแคชข้อมูลต่างๆ เช่น หน้าแรกของ Netflix และคำแนะนำส่วนบุคคล (Personal Recommendations)
  • Wide-Column Database: ประเภทนี้ใช้กับ content เกือบทั้งหมดของ Netflix รวมไปถึง video/actor information, user data, device information และ viewing history จ้าวที่ถูกเลือกคือ Cassandra
  • Time Series Database: Netflix สร้าง in-memory database ชื่อ Atlas ขึ้นมาเพื่อการจัดเก็บและการรวมกลุ่มเมตริก (metrics storage and aggregation) ซึ่งข้อมูลเน้นไปที่เวลาเป็นหลัก
  • Text Search Database: เกี่ยวกับการค้นหาทั้งหมด Netflix ใช้ Elasticsearch
  • สุดท้ายคือ ข้อมูลที่ไม่มีโครงสร้าง (Unstructured data) พวกเขาเลือก S3 เก็บแทบทุกอย่าง ไม่ว่าจะเป็น image, video, metrics และ log files

When a Database Reaches Its Limit

เมื่อถึงขีดจำกัดของฐานข้อมูล เป็นอีกเรื่องที่ต้องพิจารณา

  • Storage Capacity: เมื่อพื้นที่เก็บเต็ม
  • Memory: เมื่อหน่วยความจำไม่พอ
  • CPU Usage: เมื่อ CPU ทำงาน 100%
  • I/O Throughput: ความเร็วในการอ่านเขียนถึงขีดจำกัดของ storage

Verfical Scaling

  • Storage Capacity: แก้ไขด้วยการเพิ่ม disk ลูกใหม่, ทำ RAID (การนำ disk หลายๆตัวมาเชื่อมต่อเพื่อทำงานเหมือนเป็นตัวเดียว)
  • Memory: แก้ไขด้วยการเพิ่ม RAM
  • CPU Usage: แก้ไขด้วยการเพิ่มจำนวน CPU core
  • I/O Throughput: อาจเปลี่ยนไปใช้ SSD เพื่อลดค่า I/O latency

Horizontal Scaling

  • ถ้าพฤติกรรมเป็นการอ่านหนักๆ (heavy workloads): แก้ไขด้วยการ replication, ทำ caching, load balance
  • ถ้าพฤติกรรมเป็นการเขียนหนักๆ: แบ่งฐานข้อมูลเป็นหลาย node เช่น ระดับข้อมูล 100 ล้าน records ก็แบ่งเป็น sharding ของแต่ละประเทศแทน (อ่านเพิ่มเติมเกี่ยวกับ sharding implementation by citusdata), ทำ partitioning คือใน node เดียวแต่ไปแยก table ของข้อมูลแทน, ทำ database federation คือรวมเอาฐานข้อมูลหลายๆลูกไว้ด้วยกันเป็น single virtual database เพื่อกระจายการเขียนข้อมูล ดังเช่น Foreign Data Wrappers (FDW) ของ PostgreSQL

ไว้พบกัน System design 2/3 ครับ

--

--